parent
a85582b94e
commit
856a694f0b
@ -1 +1 @@ |
|||||||
_test_env.php |
pages/_test_env.php |
||||||
|
@ -0,0 +1,29 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
return [ |
||||||
|
'%term_title%' => 'ESP8266 Wireless Terminal', |
||||||
|
|
||||||
|
'%b1%' => '1', |
||||||
|
'%b2%' => '2', |
||||||
|
'%b3%' => '3', |
||||||
|
'%b4%' => '4', |
||||||
|
'%b5%' => '5', |
||||||
|
'%screenData%' => '{ |
||||||
|
"w": 26, "h": 10, |
||||||
|
"x": 0, "y": 0, |
||||||
|
"cv": 1, |
||||||
|
"screen": "70 t259" |
||||||
|
}', |
||||||
|
|
||||||
|
'%ap_enable%' => '1', |
||||||
|
'%tpw%' => '60', |
||||||
|
'%ap_channel%' => '7', |
||||||
|
'%ap_ssid%' => 'ESP-123456', |
||||||
|
'%ap_password%' => 'Passw0rd!', |
||||||
|
'%ap_hidden%' => '0', |
||||||
|
'%sta_ssid%' => 'LibraryFreeWifi', |
||||||
|
'%sta_password%' => 'windows XP is The Best', |
||||||
|
'%sta_active_ip%' => '', |
||||||
|
|
||||||
|
'%sta_enable%' => '0', |
||||||
|
]; |
@ -0,0 +1,3 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
define("ESP_IP", "192.168.0.19"); |
@ -0,0 +1,25 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
$pages = []; |
||||||
|
|
||||||
|
/** Add a page */ |
||||||
|
function pg($key, $bc, $path) { |
||||||
|
global $pages; |
||||||
|
$pages[$key] = (object) [ |
||||||
|
'bodyclass' => $bc, |
||||||
|
'path' => $path, |
||||||
|
'label' => tr("menu.$key"), |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
pg('cfg_wifi', 'cfg', '/cfg/wifi'); |
||||||
|
pg('cfg_network', 'cfg', '/cfg/network'); |
||||||
|
pg('cfg_term', 'cfg', '/cfg/term'); |
||||||
|
pg('about', 'cfg', '/about'); |
||||||
|
pg('help', 'cfg', '/help'); |
||||||
|
pg('term', 'term', '/'); |
||||||
|
|
||||||
|
// technical |
||||||
|
pg('wifi_set', '', '/cfg/wifi/set'); |
||||||
|
|
||||||
|
return $pages; |
@ -1,144 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
require '_test_env.php'; |
|
||||||
|
|
||||||
$prod = defined('STDIN'); |
|
||||||
$root = $prod ? '' : ('http://' . ESP_IP); |
|
||||||
|
|
||||||
$menu = [ |
|
||||||
'home' => [ $prod ? '/status' : '/page_status.php', 'Home' ], |
|
||||||
'wifi' => [ $prod ? '/wifi' : '/page_wifi.php', 'WiFi config' ], |
|
||||||
'about' => [ $prod ? '/about' : '/page_about.php', 'About' ], |
|
||||||
]; |
|
||||||
|
|
||||||
$appname = 'Current Analyser'; |
|
||||||
|
|
||||||
function e($s) { |
|
||||||
return htmlspecialchars($s, ENT_HTML5|ENT_QUOTES); |
|
||||||
} |
|
||||||
|
|
||||||
?><!doctype html> |
|
||||||
<html> |
|
||||||
<head> |
|
||||||
<meta charset="utf-8"> |
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
|
||||||
|
|
||||||
<title><?= e($menu[$page][1]) ?> - <?= e($appname) ?></title>
|
|
||||||
|
|
||||||
<link href="/css/app.css" rel="stylesheet"> |
|
||||||
<script src="/js/all.js"></script> |
|
||||||
<script> |
|
||||||
// server root (or URL) - used for local development with remote AJAX calls |
|
||||||
// (this needs CORS working on the target - which I added to esp-httpd) |
|
||||||
var _root = <?= json_encode($root) ?>;
|
|
||||||
</script> |
|
||||||
</head> |
|
||||||
<body class="page-<?=$page?>">
|
|
||||||
<div id="outer"> |
|
||||||
<nav id="menu"> |
|
||||||
<div id="brand" onclick="$('#menu').toggleClass('expanded')"><?= e($appname) ?></div>
|
|
||||||
<?php |
|
||||||
// generate the menu |
|
||||||
foreach($menu as $k => $m) { |
|
||||||
$sel = ($page == $k) ? ' class="selected"' : ''; |
|
||||||
$text = e($m[1]); |
|
||||||
$url = e($m[0]); |
|
||||||
echo "<a href=\"$url\"$sel>$text</a>"; |
|
||||||
} |
|
||||||
?> |
|
||||||
</nav> |
|
||||||
<div id="content"> |
|
||||||
<img src="/img/loader.gif" alt="Loading…" id="loader"> |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!doctype html> |
|
||||||
<html> |
|
||||||
<head> |
|
||||||
<meta charset="utf-8"> |
|
||||||
<meta name="viewport" content="width=device-width,shrink-to-fit=no,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0"> |
|
||||||
|
|
||||||
<title>WiFi Settings - ESP8266 Remote Terminal</title> |
|
||||||
|
|
||||||
<link rel="stylesheet" href="/css/app.css"> |
|
||||||
<script src="/js/app.js"></script> |
|
||||||
</head> |
|
||||||
<body class="page-wifi"> |
|
||||||
|
|
||||||
<img src="/img/loader.gif" alt="Loading…" id="loader"> |
|
||||||
|
|
||||||
<h1 onclick="location.href='/'">WiFi settings</h1> |
|
||||||
|
|
||||||
<div class="Box" id="wificonfbox"> |
|
||||||
<table> |
|
||||||
<tr> |
|
||||||
<th>WiFi mode</th> |
|
||||||
<td id="opmodebox">%WiFiMode%</td> |
|
||||||
</tr> |
|
||||||
<tr class="x-hide-noip x-hide-2"> |
|
||||||
<th>IP</th> |
|
||||||
<td>%StaIP%</td> |
|
||||||
</tr> |
|
||||||
<tr> |
|
||||||
<th>Switch to</th> |
|
||||||
<td id="modeswitch"></td> |
|
||||||
</tr> |
|
||||||
<tr class="x-hide-1"> |
|
||||||
<th><label for="channel">AP channel</label></th> |
|
||||||
<td> |
|
||||||
<form action="/wifi/setchannel" method="GET"> |
|
||||||
<input name="ch" id="channel" type="number" step=1 min=1 max=14 value="%WiFiChannel%"><!-- |
|
||||||
--><input type="submit" value="Set" class="narrow btn-green x-hide-3"> |
|
||||||
</form> |
|
||||||
</td> |
|
||||||
</tr> |
|
||||||
<tr class="x-hide-1"> |
|
||||||
<th><label for="channel">AP name</label></th> |
|
||||||
<td> |
|
||||||
<form action="/wifi/setname" method="GET"> |
|
||||||
<input name="name" type="text" value="%APName%"><!-- |
|
||||||
--><input type="submit" value="Set" class="narrow btn-green"> |
|
||||||
</form> |
|
||||||
</td> |
|
||||||
</tr> |
|
||||||
<tr><td colspan=2 style="white-space: normal;"> |
|
||||||
<p>Some changes require a reboot, dropping connection. It can take a while to re-connect.</p> |
|
||||||
<p> |
|
||||||
<b>If you lose access</b>, hold the BOOT button for 2 seconds (the Tx LED starts blinking) to re-enable AP mode. |
|
||||||
If that fails, hold the BOOT button for over 5 seconds (rapid Tx LED flashing) to perform a factory reset. |
|
||||||
<p> |
|
||||||
</td></tr> |
|
||||||
</table> |
|
||||||
</div> |
|
||||||
|
|
||||||
<div class="Box" id="ap-box"> |
|
||||||
<h2>Select AP to join</h2> |
|
||||||
<div id="ap-loader" class="x-hide-2">Scanning<span class="anim-dots">.</span></div> |
|
||||||
<div id="ap-noscan" class="x-hide-1 x-hide-3">Can't scan in AP-only mode.</div> |
|
||||||
<div id="ap-list" style="display:none"></div> |
|
||||||
</div> |
|
||||||
|
|
||||||
<nav id="botnav"> |
|
||||||
<a href="/">Terminal</a><!-- |
|
||||||
--><a href="/help">Help</a><!-- |
|
||||||
--><a href="/about">About</a> |
|
||||||
</nav> |
|
||||||
|
|
||||||
<div class="Modal hidden" id="psk-modal"> |
|
||||||
<div class="Dialog"> |
|
||||||
<form action="/wifi/connect" method="post" id="conn-form"> |
|
||||||
<input type="hidden" id="conn-essid" name="essid"><!-- |
|
||||||
--><label for="conn-passwd">Password:</label><!-- |
|
||||||
--><input type="password" id="conn-passwd" name="passwd"><!-- |
|
||||||
--><input type="submit" value="Connect!"> |
|
||||||
</form> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
|
|
||||||
<script> |
|
||||||
_root = window.location.host; |
|
||||||
wifiInit({staSSID: '%StaSSID%', staIP: '%StaIP%', mode: '%WiFiModeNum%'}); |
|
||||||
</script> |
|
||||||
</body> |
|
||||||
</html> |
|
@ -0,0 +1,64 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
require '_env.php'; |
||||||
|
$prod = defined('STDIN'); |
||||||
|
define ('DEBUG', !$prod); |
||||||
|
$root = DEBUG ? ESP_IP : ''; |
||||||
|
define ('LIVE_ROOT', $root); |
||||||
|
|
||||||
|
define('CUR_PAGE', $_GET['page'] ?: 'term'); |
||||||
|
define('LOCALE', $_GET['locale'] ?: 'en'); |
||||||
|
|
||||||
|
$_messages = require(__DIR__ . '/messages/' . LOCALE . '.php'); |
||||||
|
$_pages = require('_pages.php'); |
||||||
|
|
||||||
|
define('APP_NAME', 'ESPTerm'); |
||||||
|
define('PAGE_TITLE', $_pages[CUR_PAGE]->label . ' :: ' . APP_NAME); |
||||||
|
define('BODYCLASS', $_pages[CUR_PAGE]->bodyclass); |
||||||
|
|
||||||
|
/** URL (dev or production) */ |
||||||
|
function url($name, $root=false) { |
||||||
|
global $_pages; |
||||||
|
if ($root) return LIVE_ROOT . $_pages[$name]->path; |
||||||
|
|
||||||
|
if (DEBUG) return "/index.php?page=$name"; |
||||||
|
else return $_pages[$name]->path; |
||||||
|
} |
||||||
|
|
||||||
|
/** URL label for a button */ |
||||||
|
function label($name) { |
||||||
|
global $_pages; |
||||||
|
return $_pages[$name]->label; |
||||||
|
} |
||||||
|
|
||||||
|
function e($s) { |
||||||
|
return htmlspecialchars($s, ENT_HTML5|ENT_QUOTES); |
||||||
|
} |
||||||
|
|
||||||
|
function tr($key) { |
||||||
|
global $_messages; |
||||||
|
return $_messages[$key] ?: ('??'.$key.'??'); |
||||||
|
} |
||||||
|
|
||||||
|
/** Like eval, but allows <?php and ?> */
|
||||||
|
function include_str($code) { |
||||||
|
$tmp = tmpfile(); |
||||||
|
$tmpf = stream_get_meta_data($tmp); |
||||||
|
$tmpf = $tmpf ['uri']; |
||||||
|
fwrite($tmp, $code); |
||||||
|
$ret = include($tmpf); |
||||||
|
fclose($tmp); |
||||||
|
return $ret; |
||||||
|
} |
||||||
|
|
||||||
|
require 'pages/_head.php'; |
||||||
|
$_pf = 'pages/'.CUR_PAGE.'.php'; |
||||||
|
if (file_exists($_pf)) { |
||||||
|
$f = file_get_contents($_pf); |
||||||
|
$reps = require('_debug_replacements.php'); |
||||||
|
$str = str_replace(array_keys($reps), array_values($reps), $f); |
||||||
|
include_str($str); |
||||||
|
} else { |
||||||
|
echo "404"; |
||||||
|
} |
||||||
|
require 'pages/_tail.php'; |
@ -0,0 +1,35 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
return [ |
||||||
|
'appname' => 'ESPTerm', |
||||||
|
|
||||||
|
'menu.cfg_wifi' => 'WiFi Settings', |
||||||
|
'menu.cfg_network' => 'Network Configuration', |
||||||
|
'menu.cfg_term' => 'Terminal Settings', |
||||||
|
'menu.about' => 'About ESPTerm', |
||||||
|
'menu.help' => 'Help', |
||||||
|
'menu.term' => 'Back to Terminal', |
||||||
|
|
||||||
|
'box.ap' => 'Built-in Access Point', |
||||||
|
'box.sta' => 'Client Mode', |
||||||
|
|
||||||
|
'wifi.enable' => 'Enabled:', |
||||||
|
'wifi.tpw' => 'Transmit Power:', |
||||||
|
'wifi.ap_channel' => 'Channel:', |
||||||
|
'wifi.ap_ssid' => 'AP SSID:', |
||||||
|
'wifi.ap_password' => 'Password:', |
||||||
|
'wifi.ap_hidden' => 'Hide SSID:', |
||||||
|
'wifi.sta_info' => 'Selected Network:', |
||||||
|
|
||||||
|
'wifi.sta_ssid' => 'Network SSID:', |
||||||
|
'wifi.sta_password' => 'Password:', |
||||||
|
'wifi.not_conn' => 'Not connected.', |
||||||
|
'wifi.forget' => '', |
||||||
|
|
||||||
|
'wifi.submit' => 'Apply!', |
||||||
|
|
||||||
|
'enabled' => 'Enabled', |
||||||
|
'disabled' => 'Disabled', |
||||||
|
'yes' => 'Yes', |
||||||
|
'no' => 'No', |
||||||
|
]; |
@ -0,0 +1,15 @@ |
|||||||
|
|
||||||
|
<nav id="menu"> |
||||||
|
<div id="brand" onclick="$('#menu').toggleClass('expanded')"><?= tr('appname') ?></div>
|
||||||
|
<?php |
||||||
|
// generate the menu |
||||||
|
foreach($_pages as $k => $page) { |
||||||
|
if ($page->bodyclass !== 'cfg') continue; |
||||||
|
$sel = (CUR_PAGE == $k) ? ' class="selected"' : ''; |
||||||
|
$text = $page->label; |
||||||
|
$url = e(url($k)); |
||||||
|
echo "<a href=\"$url\"$sel>$text</a>"; |
||||||
|
} |
||||||
|
?><a href="<?= e(url('term')) ?>"><?= tr('menu.term') ?></a>
|
||||||
|
|
||||||
|
</nav> |
@ -0,0 +1,26 @@ |
|||||||
|
<!doctype html> |
||||||
|
<html> |
||||||
|
<head> |
||||||
|
<meta charset="utf-8"> |
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
||||||
|
<title><?= PAGE_TITLE ?></title>
|
||||||
|
<link href="/css/app.css" rel="stylesheet"> |
||||||
|
<script src="/js/app.js"></script> |
||||||
|
<script>var _root = <?= json_encode(LIVE_ROOT) ?>;</script>
|
||||||
|
</head> |
||||||
|
<body class="<?= BODYCLASS ?>">
|
||||||
|
<div id="outer"> |
||||||
|
<?php |
||||||
|
$cfg = false; |
||||||
|
if ($_pages[CUR_PAGE]->bodyclass == 'cfg') { |
||||||
|
$cfg = true; |
||||||
|
require __DIR__ . '/_cfg_menu.php'; |
||||||
|
} |
||||||
|
?> |
||||||
|
|
||||||
|
<div id="content"> |
||||||
|
<img src="/img/loader.gif" alt="Loading…" id="loader"> |
||||||
|
<?php if ($cfg): ?> |
||||||
|
<h1><?= tr('menu.' . CUR_PAGE) ?></h1>
|
||||||
|
<?php endif; ?> |
@ -0,0 +1,5 @@ |
|||||||
|
</div> |
||||||
|
|
||||||
|
</div> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,123 @@ |
|||||||
|
<form class="Box str mobcol" action="<?= e(url('wifi_set')) ?>" method="POST">
|
||||||
|
<h2><?= tr('box.ap') ?></h2>
|
||||||
|
|
||||||
|
<div class="Row checkbox"> |
||||||
|
<label><?= tr('wifi.enable') ?></label><!--
|
||||||
|
--><span class="box"></span> |
||||||
|
<input type="hidden" name="ap_enable" value="%ap_enable%"> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="Row"> |
||||||
|
<label for="ap_ssid"><?= tr('wifi.ap_ssid') ?></label>
|
||||||
|
<input type="text" name="ap_ssid" id="ap_ssid" value="%ap_ssid%" required> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="Row"> |
||||||
|
<label for="ap_password"><?= tr('wifi.ap_password') ?></label>
|
||||||
|
<input type="text" name="ap_password" id="ap_password" value="%ap_password%"> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="Row"> |
||||||
|
<label for="ap_channel"><?= tr('wifi.ap_channel') ?></label>
|
||||||
|
<input type="number" name="ap_channel" id="ap_channel" min=1 max=14 value="%ap_channel%" required> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="Row range"> |
||||||
|
<label for="tpw"> |
||||||
|
<?= tr('wifi.tpw') ?> |
||||||
|
<span class="display x-disp1 mq-phone"></span> |
||||||
|
</label> |
||||||
|
<input type="range" name="tpw" id="tpw" step=1 min=0 max=82 value="%tpw%"> |
||||||
|
<span class="display x-disp2 mq-tablet-min"></span> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="Row checkbox"> |
||||||
|
<label><?= tr('wifi.ap_hidden') ?></label><!--
|
||||||
|
--><span class="box"></span> |
||||||
|
<input type="hidden" name="ap_hidden" value="%ap_hidden%"> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="Row buttons"> |
||||||
|
<input type="submit" value="<?= tr('wifi.submit') ?>">
|
||||||
|
</div> |
||||||
|
</form> |
||||||
|
|
||||||
|
<form class="Box str mobcol" action="<?= e(url('wifi_set')) ?>" method="POST">
|
||||||
|
<h2><?= tr('box.sta') ?></h2>
|
||||||
|
|
||||||
|
<div class="Row checkbox"> |
||||||
|
<label><?= tr('wifi.enable') ?></label><!--
|
||||||
|
--><span class="box"></span> |
||||||
|
<input type="hidden" name="sta_enable" value="%sta_enable%"> |
||||||
|
</div> |
||||||
|
|
||||||
|
<input type="hidden" name="sta_ssid" id="sta_ssid" value="%sta_ssid%"> |
||||||
|
<input type="hidden" name="sta_password" id="sta_password" value="%sta_password%"> |
||||||
|
|
||||||
|
<div class="Row sta-info"> |
||||||
|
<label><?= tr('wifi.sta_info') ?></label>
|
||||||
|
<div class="AP-preview" id="sta-nw"> |
||||||
|
<div class="wrap"> |
||||||
|
<div class="inner"> |
||||||
|
<div class="essid"></div> |
||||||
|
<div class="passwd"></div> |
||||||
|
<div class="ip"></div> |
||||||
|
</div> |
||||||
|
<a class="forget" id="forget-sta">×</a> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="Row buttons"> |
||||||
|
<input type="submit" value="<?= tr('wifi.submit') ?>">
|
||||||
|
</div> |
||||||
|
</form> |
||||||
|
|
||||||
|
<script> |
||||||
|
$('.Row.checkbox').forEach(function(x) { |
||||||
|
var inp = x.querySelector('input'); |
||||||
|
var box = x.querySelector('.box'); |
||||||
|
|
||||||
|
$(box).toggleClass('checked', inp.value); |
||||||
|
|
||||||
|
$(x).on('click', function() { |
||||||
|
inp.value = 1 - inp.value; |
||||||
|
$(box).toggleClass('checked', inp.value) |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
$('.Box.mobcol').forEach(function(x) { |
||||||
|
var h = x.querySelector('h2'); |
||||||
|
$(h).on('click', function() { |
||||||
|
$(x).toggleClass('expanded'); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
function rangePt(inp) { |
||||||
|
return Math.round(((inp.value / inp.max)*100)) + '%'; |
||||||
|
} |
||||||
|
|
||||||
|
$('.Row.range').forEach(function(x) { |
||||||
|
var inp = x.querySelector('input'); |
||||||
|
var disp1 = x.querySelector('.x-disp1'); |
||||||
|
var disp2 = x.querySelector('.x-disp2'); |
||||||
|
var t = rangePt(inp); |
||||||
|
$(disp1).html(t); |
||||||
|
$(disp2).html(t); |
||||||
|
$(inp).on('input', function() { |
||||||
|
t = rangePt(inp); |
||||||
|
$(disp1).html(t); |
||||||
|
$(disp2).html(t); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
function wifiShowSelected(name, password, ip) { |
||||||
|
$('#sta-nw .essid').html(e(name)); |
||||||
|
var nopw = undef(password) || password.length == 0; |
||||||
|
$('#sta-nw .passwd').html(e(password)).toggleClass('hidden', nopw); |
||||||
|
$('#sta-nw .ip').html(ip.length>0 ? ip : '<?=tr('wifi.not_conn')?>');
|
||||||
|
} |
||||||
|
|
||||||
|
wifiShowSelected('%sta_ssid%', '%sta_password%', '%sta_active_ip%'); |
||||||
|
|
||||||
|
</script> |
@ -0,0 +1,37 @@ |
|||||||
|
<script> |
||||||
|
// Workaround for badly loaded page |
||||||
|
setTimeout(function() { |
||||||
|
if (typeof termInit == 'undefined' || typeof $ == 'undefined') { |
||||||
|
location.reload(true); |
||||||
|
} |
||||||
|
}, 2000); |
||||||
|
</script> |
||||||
|
|
||||||
|
<h1 onclick="location.href='<?= e(url('cfg_wifi_simple')) ?>'">%term_title%</h1>
|
||||||
|
|
||||||
|
<div id="termwrap"> |
||||||
|
<div id="screen"></div> |
||||||
|
|
||||||
|
<div id="buttons"> |
||||||
|
<button data-n="1" class="btn-blue">%b1%</button><!-- |
||||||
|
--><button data-n="2" class="btn-blue">%b2%</button><!-- |
||||||
|
--><button data-n="3" class="btn-blue">%b3%</button><!-- |
||||||
|
--><button data-n="4" class="btn-blue">%b4%</button><!-- |
||||||
|
--><button data-n="5" class="btn-blue">%b5%</button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<nav id="botnav"> |
||||||
|
<a href="<?= url('cfg_wifi_simple') ?>"><?= tr('menu.cfg_wifi') ?></a><!--
|
||||||
|
--><a href="<?= url('help') ?>">Help</a><!--
|
||||||
|
--><a href="<?= url('about') ?>">About</a>
|
||||||
|
</nav> |
||||||
|
|
||||||
|
<script> |
||||||
|
try { |
||||||
|
termInit(%screenData%); |
||||||
|
} catch(e) { |
||||||
|
console.error("Fail, reloading..."); |
||||||
|
location.reload(true); |
||||||
|
} |
||||||
|
</script> |
@ -1,178 +0,0 @@ |
|||||||
html { |
|
||||||
font-family: Arial, sans-serif; |
|
||||||
color: #D0D0D0; |
|
||||||
background: #131315; |
|
||||||
} |
|
||||||
|
|
||||||
html, body { |
|
||||||
@include naked(); |
|
||||||
width: 100%; |
|
||||||
height: 100%; |
|
||||||
overflow: hidden; |
|
||||||
} |
|
||||||
|
|
||||||
a, a:visited, a:link { |
|
||||||
cursor: pointer; |
|
||||||
color: #5abfff; |
|
||||||
text-decoration: none; |
|
||||||
} |
|
||||||
|
|
||||||
a:hover { |
|
||||||
color: #5abfff; |
|
||||||
text-decoration: underline; |
|
||||||
} |
|
||||||
|
|
||||||
.Box { |
|
||||||
display: block; |
|
||||||
max-width: 900px; |
|
||||||
|
|
||||||
margin-top: dist(0); |
|
||||||
padding: dist(-1) dist(0); |
|
||||||
|
|
||||||
@include media($phone) { |
|
||||||
margin-top: dist(-1); |
|
||||||
padding: dist(-3) dist(-2); |
|
||||||
} |
|
||||||
// |
|
||||||
//h1 + & { |
|
||||||
// margin-top: 0; |
|
||||||
//} |
|
||||||
// |
|
||||||
//h2 { |
|
||||||
// margin-top: 0; |
|
||||||
//} |
|
||||||
|
|
||||||
p:first-child { |
|
||||||
margin-top:0; |
|
||||||
} |
|
||||||
|
|
||||||
border-radius: 3px; |
|
||||||
background-color: rgba(white, .07); |
|
||||||
|
|
||||||
//&.wide { |
|
||||||
// width: initial; |
|
||||||
// max-width: initial; |
|
||||||
//} |
|
||||||
// |
|
||||||
//&.medium { |
|
||||||
// max-width: 1200px; |
|
||||||
//} |
|
||||||
// |
|
||||||
//.Valfield { |
|
||||||
// display: inline-block; |
|
||||||
// min-width: 10em; |
|
||||||
//} |
|
||||||
} |
|
||||||
|
|
||||||
body { |
|
||||||
position: relative; |
|
||||||
|
|
||||||
padding: dist(0); |
|
||||||
@include media($phone) { |
|
||||||
padding: dist(-1); |
|
||||||
} |
|
||||||
|
|
||||||
overflow-y: auto; |
|
||||||
|
|
||||||
& > * { |
|
||||||
margin-left: auto; |
|
||||||
margin-right: auto; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
h1,h2 { |
|
||||||
@include noselect(); |
|
||||||
} |
|
||||||
|
|
||||||
h1 { |
|
||||||
text-align: center; |
|
||||||
font-size: fsize(6); |
|
||||||
margin-top: 0; |
|
||||||
margin-bottom: dist(0); |
|
||||||
|
|
||||||
@include media($phone) { |
|
||||||
font-size: fsize(3); |
|
||||||
margin-bottom: dist(-1); |
|
||||||
} |
|
||||||
|
|
||||||
@include media($tablet) { |
|
||||||
font-size: fsize(5); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
h2 { |
|
||||||
font-size: fsize(2); |
|
||||||
margin-bottom: dist(-1); |
|
||||||
//&:first-child{margin-top:0} |
|
||||||
} |
|
||||||
|
|
||||||
td, th { |
|
||||||
padding: dist(-2); |
|
||||||
white-space: nowrap; |
|
||||||
|
|
||||||
@include media($phone) { |
|
||||||
padding: dist(-3); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
tbody th { |
|
||||||
text-align: right; |
|
||||||
width: $form-label-w; |
|
||||||
color: $c-form-label-fg; |
|
||||||
|
|
||||||
@include media($phone) { |
|
||||||
width: auto; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
tbody td { |
|
||||||
input[type="text"], input[type="number"] { |
|
||||||
width: 10em; |
|
||||||
|
|
||||||
@include media($phone) { |
|
||||||
width: 8em; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Loader wheel in top right corner |
|
||||||
#loader { |
|
||||||
position: absolute; |
|
||||||
right: dist(1); |
|
||||||
top: dist(1); |
|
||||||
|
|
||||||
transition: opacity .2s; |
|
||||||
opacity: 0; |
|
||||||
|
|
||||||
@include media($phone) { |
|
||||||
top: dist(0); |
|
||||||
right: dist(0); |
|
||||||
} |
|
||||||
|
|
||||||
&.show { |
|
||||||
opacity:1; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
ul > * { |
|
||||||
padding-top: .1em; |
|
||||||
padding-bottom: .1em; |
|
||||||
} |
|
||||||
|
|
||||||
#botnav { |
|
||||||
padding-top: 1.5em; |
|
||||||
text-align: center; |
|
||||||
|
|
||||||
a { |
|
||||||
padding: 0 dist(-2); |
|
||||||
text-decoration: underline; |
|
||||||
|
|
||||||
&, &:visited, &:link { |
|
||||||
color: #2e4d6e; |
|
||||||
} |
|
||||||
|
|
||||||
&:hover { |
|
||||||
color: #5abfff; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,31 @@ |
|||||||
|
html { |
||||||
|
font-family: Arial, sans-serif; |
||||||
|
color: #D0D0D0; |
||||||
|
background: #131315; |
||||||
|
} |
||||||
|
|
||||||
|
html, body { |
||||||
|
@include naked(); |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
|
||||||
|
a, a:visited, a:link { |
||||||
|
cursor: pointer; |
||||||
|
color: #5abfff; |
||||||
|
text-decoration: none; |
||||||
|
} |
||||||
|
|
||||||
|
a:hover { |
||||||
|
color: #5abfff; |
||||||
|
text-decoration: underline; |
||||||
|
} |
||||||
|
|
||||||
|
.hidden { |
||||||
|
display: none !important; |
||||||
|
} |
||||||
|
|
||||||
|
[onclick] { |
||||||
|
cursor: pointer; |
||||||
|
} |
@ -0,0 +1,91 @@ |
|||||||
|
.Box { |
||||||
|
display: block; |
||||||
|
max-width: 900px; |
||||||
|
|
||||||
|
margin-top: dist(0); |
||||||
|
padding: dist(-1) dist(0); |
||||||
|
|
||||||
|
@include media($phone) { |
||||||
|
margin-top: dist(-1); |
||||||
|
} |
||||||
|
|
||||||
|
h1 + & { |
||||||
|
margin-top: 0; |
||||||
|
} |
||||||
|
|
||||||
|
h2 { |
||||||
|
margin-top: 0; |
||||||
|
} |
||||||
|
|
||||||
|
border-radius: 3px; |
||||||
|
background-color: rgba(white, .07); |
||||||
|
|
||||||
|
&.wide { |
||||||
|
width: initial; |
||||||
|
max-width: initial; |
||||||
|
} |
||||||
|
|
||||||
|
&.medium { |
||||||
|
max-width: 1200px; |
||||||
|
} |
||||||
|
|
||||||
|
//.Valfield { |
||||||
|
// display: inline-block; |
||||||
|
// min-width: 10em; |
||||||
|
//} |
||||||
|
|
||||||
|
&.str { |
||||||
|
position: relative; |
||||||
|
|
||||||
|
.Row.buttons { |
||||||
|
position: absolute; |
||||||
|
right: dist(0); |
||||||
|
top: 2.7em; |
||||||
|
margin: 12px auto; |
||||||
|
} |
||||||
|
|
||||||
|
@include media($tablet-min) { |
||||||
|
.Row.buttons { |
||||||
|
//position: absolute; |
||||||
|
right: 0; |
||||||
|
top: 0; |
||||||
|
//margin: 12px auto; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@include media($phone) { |
||||||
|
.Box.mobcol { |
||||||
|
h2 { |
||||||
|
position: relative; |
||||||
|
cursor: pointer; |
||||||
|
|
||||||
|
&::after { |
||||||
|
position: absolute; |
||||||
|
right: 0; |
||||||
|
content: '▸'; |
||||||
|
|
||||||
|
top:50%; |
||||||
|
font-size: 120%; |
||||||
|
font-weight: bold; |
||||||
|
transform: translate(0,-50%) rotate(90deg); |
||||||
|
} |
||||||
|
|
||||||
|
margin-bottom: 0 !important; |
||||||
|
} |
||||||
|
|
||||||
|
&.expanded h2::after { |
||||||
|
transform: translate(-25%,-50%) rotate(-90deg); |
||||||
|
margin-bottom: dist(0); |
||||||
|
} |
||||||
|
|
||||||
|
.Row { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
|
||||||
|
&.expanded .Row { |
||||||
|
display: flex; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
#content { |
||||||
|
flex-grow: 1; |
||||||
|
position: relative; |
||||||
|
|
||||||
|
padding: dist(0); |
||||||
|
@include media($phone) { |
||||||
|
padding: dist(-1); |
||||||
|
} |
||||||
|
|
||||||
|
overflow-y: auto; |
||||||
|
|
||||||
|
& > * { |
||||||
|
margin-left: auto; |
||||||
|
margin-right: auto; |
||||||
|
} |
||||||
|
|
||||||
|
h1 { |
||||||
|
text-align: center; |
||||||
|
font-size: fsize(7); |
||||||
|
margin-top: 0; |
||||||
|
margin-bottom: dist(0); |
||||||
|
} |
||||||
|
|
||||||
|
@include media($phone) { |
||||||
|
h1 { |
||||||
|
font-size: fsize(5); |
||||||
|
margin-bottom: dist(-1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
h2 { |
||||||
|
font-size: fsize(3); |
||||||
|
margin-bottom: dist(-1); |
||||||
|
} |
||||||
|
|
||||||
|
td, th { |
||||||
|
padding: dist(-2); |
||||||
|
} |
||||||
|
|
||||||
|
tbody th { |
||||||
|
text-align: right; |
||||||
|
width: $form-label-w; |
||||||
|
color: $c-form-label-fg; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
|
||||||
|
ul > * { |
||||||
|
padding-top: .1em; |
||||||
|
padding-bottom: .1em; |
||||||
|
} |
||||||
|
|
||||||
|
h1,h2 { |
||||||
|
@include noselect(); |
||||||
|
} |
||||||
|
|
||||||
|
h1 { |
||||||
|
text-align: center; |
||||||
|
font-size: fsize(6); |
||||||
|
margin-top: 0; |
||||||
|
margin-bottom: dist(0); |
||||||
|
|
||||||
|
@include media($phone) { |
||||||
|
font-size: fsize(3); |
||||||
|
margin-bottom: dist(-1); |
||||||
|
} |
||||||
|
|
||||||
|
@include media($tablet) { |
||||||
|
font-size: fsize(5); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
h2 { |
||||||
|
font-size: fsize(2); |
||||||
|
margin-bottom: dist(-1); |
||||||
|
//&:first-child{margin-top:0} |
||||||
|
} |
||||||
|
|
||||||
|
td, th { |
||||||
|
padding: dist(-2); |
||||||
|
white-space: nowrap; |
||||||
|
|
||||||
|
@include media($phone) { |
||||||
|
padding: dist(-3); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
tbody th { |
||||||
|
text-align: right; |
||||||
|
width: $form-label-w; |
||||||
|
color: $c-form-label-fg; |
||||||
|
|
||||||
|
@include media($phone) { |
||||||
|
width: auto; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
tbody td { |
||||||
|
input[type="text"], input[type="number"] { |
||||||
|
width: 10em; |
||||||
|
|
||||||
|
@include media($phone) { |
||||||
|
width: 8em; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
body { |
||||||
|
position: relative; |
||||||
|
|
||||||
|
padding: dist(0); |
||||||
|
@include media($phone) { |
||||||
|
padding: dist(-1); |
||||||
|
} |
||||||
|
|
||||||
|
overflow-y: auto; |
||||||
|
|
||||||
|
& > * { |
||||||
|
margin-left: auto; |
||||||
|
margin-right: auto; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,9 @@ |
|||||||
|
@import "base"; |
||||||
|
|
||||||
|
@import "outer-wrap"; |
||||||
|
@import "menu"; |
||||||
|
@import "content"; |
||||||
|
@import "loader"; |
||||||
|
|
||||||
|
@import "box"; |
||||||
|
@import "modal"; |
@ -0,0 +1,18 @@ |
|||||||
|
// Loader wheel in top right corner |
||||||
|
#loader { |
||||||
|
position: absolute; |
||||||
|
right: dist(1); |
||||||
|
top: dist(1); |
||||||
|
|
||||||
|
transition: opacity .2s; |
||||||
|
opacity: 0; |
||||||
|
|
||||||
|
@include media($phone) { |
||||||
|
top: dist(0); |
||||||
|
right: dist(0); |
||||||
|
} |
||||||
|
|
||||||
|
&.show { |
||||||
|
opacity:1; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,98 @@ |
|||||||
|
#menu { |
||||||
|
$menu-bg: #3983CD; |
||||||
|
$menu-hl: #5badff; //#1bd886; |
||||||
|
$menu-fg: white; |
||||||
|
|
||||||
|
flex: 0 0 15rem; |
||||||
|
background: $menu-bg; |
||||||
|
|
||||||
|
& > * { |
||||||
|
display: block; |
||||||
|
text-decoration: none; |
||||||
|
padding: dist(-1) dist(0); |
||||||
|
|
||||||
|
@include nowrap; |
||||||
|
@include noselect; |
||||||
|
} |
||||||
|
|
||||||
|
#brand { |
||||||
|
color: $menu-fg; |
||||||
|
background: darken($menu-bg, 10%); |
||||||
|
font-size: 120%; |
||||||
|
text-align: center; |
||||||
|
position:relative; |
||||||
|
transition: none; |
||||||
|
font-weight: bold; |
||||||
|
|
||||||
|
margin-bottom: dist(0); |
||||||
|
|
||||||
|
@include media($phone) { |
||||||
|
background: $menu-bg; |
||||||
|
cursor: pointer; |
||||||
|
margin-bottom: dist(-2); |
||||||
|
|
||||||
|
&::after { |
||||||
|
position: absolute; |
||||||
|
color: rgba(black, .4); |
||||||
|
right: dist(0); |
||||||
|
content: '▸'; |
||||||
|
|
||||||
|
top:50%; |
||||||
|
font-size: 120%; |
||||||
|
font-weight: bold; |
||||||
|
transform: translate(0,-50%) rotate(90deg); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
&.expanded #brand { |
||||||
|
background: darken($menu-bg, 10%); |
||||||
|
|
||||||
|
@include media($phone) { |
||||||
|
&:after { transform: translate(-25%,-50%) rotate(-90deg) } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
a { |
||||||
|
font-size: 130%; |
||||||
|
color: $menu-fg; |
||||||
|
|
||||||
|
transition: background-color 0.2s; |
||||||
|
text-shadow: 0 0 5px rgba(black, .4); |
||||||
|
|
||||||
|
&:hover, &.selected { |
||||||
|
background: $menu-hl; |
||||||
|
text-shadow: 0 0 5px rgba(black, .6); |
||||||
|
} |
||||||
|
|
||||||
|
&.selected { |
||||||
|
position: relative; |
||||||
|
box-shadow: 0 0 5px rgba(black, .5); |
||||||
|
} |
||||||
|
|
||||||
|
&::before { |
||||||
|
content: "▸"; |
||||||
|
padding-right: .5rem; |
||||||
|
position: relative; |
||||||
|
top: -0.1rem; |
||||||
|
} |
||||||
|
|
||||||
|
@include media($phone) { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.expanded a { display:block } |
||||||
|
|
||||||
|
@include media($tablet) { |
||||||
|
#brand { |
||||||
|
font-size: 95%; |
||||||
|
margin-bottom: dist(-1); |
||||||
|
} |
||||||
|
|
||||||
|
a { font-size: 105%; } |
||||||
|
|
||||||
|
flex-basis: 10rem; |
||||||
|
|
||||||
|
& > * { padding: dist(-2) dist(-1); } |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
/* Main outer container */ |
||||||
|
#outer { |
||||||
|
display: flex; |
||||||
|
|
||||||
|
position: absolute; |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
top: 0; |
||||||
|
bottom: 0; |
||||||
|
overflow: hidden; |
||||||
|
|
||||||
|
flex-direction: row; |
||||||
|
} |
||||||
|
|
||||||
|
@include media($phone) { |
||||||
|
#outer { |
||||||
|
display: block; |
||||||
|
overflow-y: scroll; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,68 @@ |
|||||||
|
|
||||||
|
// Utilities for background tiling |
||||||
|
|
||||||
|
// Use a tile as background (w, h - size of time) |
||||||
|
@mixin tile_xy($w, $h, $x, $y) { |
||||||
|
background-position: (-$x*$w) (-$y*$h); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// Use a square tile as background (size - w & h of time) |
||||||
|
@mixin tile($size, $x, $y) { |
||||||
|
@include tile_xy($size, $size, $x, $y); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// Button with sprite-sheet |
||||||
|
// A B |
||||||
|
// B:hover B:hover |
||||||
|
@mixin tile_btn_h($w, $h, $x) { |
||||||
|
@include tile_xy($w, $h, $x, 0); |
||||||
|
&:hover { |
||||||
|
@include tile_xy($w, $h, $x, 1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// active the same as hover |
||||||
|
@mixin tile_btn_h_act($w, $h, $x) { |
||||||
|
@include tile_xy($w, $h, $x, 0); |
||||||
|
&:hover, &.active { |
||||||
|
@include tile_xy($w, $h, $x, 1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Button with sprite-sheet |
||||||
|
// A A:hover |
||||||
|
// B B:hover |
||||||
|
@mixin tile_btn_v($w, $h, $y) { |
||||||
|
@include tile_xy($w, $h, 0, $y); |
||||||
|
&:hover { |
||||||
|
@include tile_xy($w, $h, 1, $y); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// active the same as hover |
||||||
|
@mixin tile_btn_v_act($w, $h, $y) { |
||||||
|
@include tile_xy($w, $h, 0, $y); |
||||||
|
&:hover, &.active { |
||||||
|
@include tile_xy($w, $h, 1, $y); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@mixin inset-shadow-top($w, $c) { |
||||||
|
box-shadow: inset 0 $w ($w*2) (-$w) $c; |
||||||
|
} |
||||||
|
|
||||||
|
@mixin inset-shadow-bottom($w, $c) { |
||||||
|
box-shadow: inset 0 (-$w) ($w*2) (-$w) $c; |
||||||
|
} |
||||||
|
|
||||||
|
@mixin inset-shadow-left($w, $c) { |
||||||
|
box-shadow: inset $w 0 ($w*2) (-$w) $c; |
||||||
|
} |
||||||
|
|
||||||
|
@mixin inset-shadow-right($w, $c) { |
||||||
|
box-shadow: inset (-$w) 0 ($w*2) (-$w) $c; |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
@import "background-tiling"; |
||||||
|
@import "pointer"; |
||||||
|
@import "misc"; |
@ -0,0 +1,34 @@ |
|||||||
|
// Add a highlight for debugging |
||||||
|
@mixin highlight($color) { |
||||||
|
outline: 1px solid $color; |
||||||
|
background: rgba($color, .05); |
||||||
|
box-shadow: 0 0 2px 2px rgba($color, .2), inset 0 0 2px 2px rgba($color, .2); |
||||||
|
} |
||||||
|
|
||||||
|
// Ellipsis, but for block elements |
||||||
|
@mixin block-ellipsis($width: 100%) { |
||||||
|
display: block; |
||||||
|
max-width: $width; |
||||||
|
overflow: hidden; |
||||||
|
text-overflow: ellipsis; |
||||||
|
white-space: nowrap; |
||||||
|
word-wrap: normal; |
||||||
|
} |
||||||
|
|
||||||
|
// No margins, padding, borders |
||||||
|
@mixin naked() { |
||||||
|
border: 0 none; |
||||||
|
margin: 0; |
||||||
|
padding: 0; |
||||||
|
text-decoration: none; |
||||||
|
} |
||||||
|
|
||||||
|
@mixin translate($x, $y) { |
||||||
|
@include transform(translate($x, $y)); |
||||||
|
} |
||||||
|
|
||||||
|
// Disallow wrapping |
||||||
|
@mixin nowrap() { |
||||||
|
white-space: nowrap; |
||||||
|
word-wrap: normal; |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
|
||||||
|
@mixin click-through() { |
||||||
|
pointer-events: none; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// Disallow text selection |
||||||
|
@mixin noselect() { |
||||||
|
-webkit-user-select: none; |
||||||
|
-khtml-user-select: none; |
||||||
|
-moz-user-select: none; |
||||||
|
-ms-user-select: none; |
||||||
|
user-select: none; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// Allow text selection |
||||||
|
@mixin can-select() { |
||||||
|
-webkit-user-select: text; |
||||||
|
-khtml-user-select: text; |
||||||
|
-moz-user-select: text; |
||||||
|
-ms-user-select: text; |
||||||
|
user-select: text; |
||||||
|
|
||||||
|
cursor: text; |
||||||
|
} |
@ -1,3 +1,3 @@ |
|||||||
#!/bin/bash |
#!/bin/bash |
||||||
|
|
||||||
xterm -e "php -S localhost:2000" |
xterm -e "php -S 0.0.0.0:2000" |
||||||
|
Loading…
Reference in new issue