Compare commits

...
35 Commits
Author SHA1 Message Date
MightyPork c04433b7f5 v5.6 - ESP-01S compatibility (blue LED at GPIO2, not GPIO1) 2017-03-27 20:49:40 +02:00
MightyPork ab00467914 blinking indication of BOOT held down; added info to the help page 2017-03-21 20:00:48 +01:00
MightyPork 97044c2a17 Auto wipe & reset SSID name if AI-THINKER ssid found 2017-03-19 00:47:51 +01:00
MightyPork 8eb01a725b 0.5.3 - added auto reconnect fn to javascript to fix broken page loads in some cases 2017-03-19 00:35:12 +01:00
MightyPork b074eb4f2c version bump 2017-03-02 00:52:31 +01:00
MightyPork 9dd5a1f082 Implemented cursor wrap control codes e[?7h and l 2017-03-02 00:06:45 +01:00
MightyPork e7c26b3e94 send code 0x18 on restart 2017-03-01 23:57:07 +01:00
MightyPork b6a0e796d8 Fixed broken Report Device OK response 2017-01-30 01:22:16 +01:00
MightyPork 29f726c073 Fixed some broken impl 2017-01-30 01:10:10 +01:00
MightyPork 0acf0bdd72 Small front-end improvements + made screen clearing apply cursor color to cleared area 2017-01-29 20:08:58 +01:00
MightyPork 03179a0ff0 readme 2017-01-29 15:18:00 +01:00
MightyPork 2560eae519 removed html folder, added to gitignore 2017-01-29 15:15:38 +01:00
MightyPork 9113756091 Fixed a mistake on the help page with color numbers 2017-01-29 15:13:17 +01:00
MightyPork f87f638f03 Added Help and About pages 2017-01-29 14:47:39 +01:00
MightyPork 16f81cd411 Fix issue with buffer overflow for too large screen updated too fast 2017-01-29 11:10:19 +01:00
MightyPork e62c4ece90 improvements + page testing php scripts (use with php -S localhost:1337 in the folder) 2017-01-29 01:58:36 +01:00
MightyPork b1baffa3d5 Implemented device status query cmd & cursor save/restore with attrs 2017-01-28 02:04:18 +01:00
MightyPork 1d891dd313 added a 20 ms delay before sending WS update, improves performance when user repains entire screen quickly - just 1 update 2017-01-28 01:42:34 +01:00
MightyPork f7edbf19b0 I'm an idiot 2017-01-28 01:20:21 +01:00
MightyPork bbb56541f8 packed screen struct to 2 bytes, saved 2 kB of RAM 2017-01-28 01:17:13 +01:00
MightyPork 1d52cd551a implemented mouse input, CSI6n cmd, added sass cmd to build_web.sh 2017-01-28 00:47:10 +01:00
MightyPork def04042a7 Implemented factory reset & split ansi_parser to parser and callbacks 2017-01-27 23:35:43 +01:00
MightyPork 46320ef4b9 updated Readme 2017-01-27 22:32:02 +01:00
MightyPork 5aaef1a972 readme updated 2017-01-27 02:03:20 +01:00
MightyPork f8a1d9dbf8 smaller h1 size on terminal screen 2017-01-27 01:34:54 +01:00
MightyPork f8d848f383 FIXED STUPID JSON BUG YOOOO 2017-01-27 01:29:30 +01:00
MightyPork 0f7fb9430c Much better wifi config, added display for IP etc, improved "connecting" page 2017-01-27 00:11:57 +01:00
MightyPork 78c2f9ee52 fix sending 'cv' cursor visible flag 2017-01-26 04:46:34 +01:00
MightyPork 1a33084041 most of the wifi functionality working, + new style 2017-01-26 04:38:19 +01:00
MightyPork c9b03ebca1 readme improvement 2017-01-24 12:58:19 +01:00
MightyPork b31f3b9335 working debug on uart1 & fixed other issues 2017-01-24 12:54:26 +01:00
MightyPork b0d3c55bbb attempt to fix uart1 but nnot working 2017-01-24 12:05:41 +01:00
MightyPork c2593c2207 implemented browser-esp comm; uart1 not working for some reason 2017-01-24 11:38:17 +01:00
MightyPork 521a00ce47 Fixed multi-part socket for long screen data 2017-01-24 02:15:18 +01:00
MightyPork ca93a3b90d Added messaging from browser to server, tap handling, improved resize on clientside 2017-01-24 01:37:26 +01:00
170 changed files with 11017 additions and 1067 deletions
+4
View File
@@ -1,3 +1,4 @@
html/
build/
firmware/
espfs/mkespfsimage/*.o
@@ -14,3 +15,6 @@ eagle.app.sym
.idea/
CMakeLists.txt
cmake-build-debug/
.sass-cache
*.map
+1 -1
View File
@@ -65,7 +65,7 @@ LIBS += esphttpd
# compiler flags using during compilation of source files
CFLAGS = -Os -ggdb -std=gnu99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inline-functions \
-nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DICACHE_FLASH \
-Wno-address -Wno-unused
-Wno-address -Wno-unused -DHTTPD_MAX_BACKLOG_SIZE=8192
# linker flags used to generate the main object file
LDFLAGS = -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static
+71 -37
View File
@@ -13,67 +13,101 @@ Those forks include improvements not yet available upstream.
This project aims to be a wireless terminal emulator that'll work with the likes of
Arduino, AVR, PIC, STM8, STM32, mbed etc, anything with UART, even your USB-serial dongle will work.
Connect it to the master device via UART and use the terminal (on your PC or phone) for debug logging,
Connect it to the master device via UART and use the terminal on the built-in web page for debug logging,
remote control etc. It works like a simple LCD screen, in a way.
It lets you make simple UI (manipulating the screen with ANSI sequences) and receive input from buttons on
the webpage (and keyboard on PC). Touch input is a possibility but not currently implemented.
the webpage (and keyboard on PC). Touch input is planned as well.
The screen size should be adjustable up to 25x80 (via a special control sequence) and uses 16 standard colors.
The screen size is adjustable up to 25x80 (via a special control sequence) and uses 16 standard colors
(8 dark and 8 bright).
## Project status
*Still far from finished and also there's like zero documentation, but you can give it a spin if you wish.*
*Almost finished, still possibly buggy, but it looks promising. Most of the features are there now.*
- Presently we have a working **1-way terminal** (UART->ESP->Browser) with real-time update via websocket.
The terminal should support multiple sockets at once (not tested).
- We have a working **2-way terminal** (UART->ESP->Browser and vice versa) with real-time update via websocket.
- All ANSi sequences that make sense, as well as control codes like Backspace and CR / LF are implemented.
Set colors with your usual `\e[31;1m` etc (see Wikipedia). `\e` is the hex code 0x18 or dec 27, or ESC.
This may be hard to type on a desktop terminal emulator, if you're trying it with a USB-serial dongle.
It'll be easy with the microcontroller, of course.
This means that what you type in the browser is sent to UART0 and what's received on UART0 is processed by the
ANSI parser and applied to the internal screen buffer. You'll also immediately see the changes in your browser.
There's a filter in the way that discards garbage characters (like unicode and most ASCII outside 32-126).
For a quick test, try connecting the UART0 Rx and Tx with a piece of wire to make a loopback interface.
*NOTE: Use the bare module, not something like LoLin or NodeMCU with a FTDI, it'll interfere*.
You should then directly see what you type & can even try some ANSI sequences, right from the browser.
- All ANSI sequences that make sense, as well as control codes like Backspace and CR / LF are implemented.
Set colors with your usual `\e[31;1m` etc (see Wikipedia). `\e` is the ASCII code 27 (ESC).
Arrow keys generate ANSI sequences, ESC sends literal ASCII code 27 etc. Almost everything can be input
straight from the browser.
- To resize the screen, send `\e]W<rows>;<cols>\a` (it's an OSC code, terminated by ST).
- The buttons or other input from the browser don't work yet.
- Buttons pressed in the browser UI send ASCII codes 1..5. Mouse clicks are sent as `\e[<row>;<col>M`.
- There is also currently no way to set up the WiFi, so it'll use whatever you configured the ESP to
in your previous project. This'll be addressed later.
- There's a built-in WiFi config page and a Help page with a list of all supported ANSI sequences etc.
## Setting it all up
## Development
### Installation for development
- Clone this project with `--recursive`, or afterwards run `git submodule init` and `git submodule update`.
- Install [esp-open-sdk](https://github.com/pfalcon/esp-open-sdk/) and build it with
`make toolchain esptool libhal STANDALONE=n`. Make sure the `xtensa-lx106-elf/bin` folder is on $PATH.
- Install [esptool](https://github.com/espressif/esptool) (it's in Arch community repo and on AUR, too)
`make toolchain esptool libhal STANDALONE=n`.
Make sure the `xtensa-lx106-elf/bin` folder is on $PATH.
- Install [esptool](https://github.com/espressif/esptool) (it's in the Arch community repo and on AUR, too)
- Set up udev rules so you have access to ttyUSB0 without root, eg:
```
KERNEL=="tty[A-Z]*[0-9]*", GROUP="uucp", MODE="0666"
```
- Clone this project with `--recursive`, or afterwards run `git submodule init` and `git submodule update`.
## Development
- Install Ragel if you wish to make modifications to the parser.
If not, comment out it's call in `build_parser.sh`. The `.rl` file is the actual source, the `.c` is generated.
The web resources are in `html_orig`. To prepare for a build, run `compress_html.sh`.
This should pack them and put in `html`.
- Install Ruby and then the `sass` package with `gem install sass` (or try some other implementation, such as
`sassc`)
If you're missing the compression tools, you can simply copy them there manually uncompressed and hope for the best.
- Get the IoT SDK from one of:
serial comm is handled in `serial.c`, sockets etc in `user_main.c`.
```
ESP8266_NONOS_SDK_V2.0.0_16_08_10.zip:
wget --content-disposition "http://bbs.espressif.com/download/file.php?id=1690"
ESP8266_NONOS_SDK_V2.0.0_16_07_19.zip:
wget --content-disposition "http://bbs.espressif.com/download/file.php?id=1613"
ESP8266_NONOS_SDK_V1.5.4_16_05_20.zip:
wget --content-disposition "http://bbs.espressif.com/download/file.php?id=1469"
ESP8266_NONOS_SDK_V1.5.3_16_04_18.zip:
wget --content-disposition "http://bbs.espressif.com/download/file.php?id=1361"
ESP8266_NONOS_SDK_V1.5.2_16_01_29.zip:
wget --content-disposition "http://bbs.espressif.com/download/file.php?id=1079"
```
Get the IoT SDK from one of:
It's tested with 1.5.2, 2.0.0 won't work without adjusting the build scripts. Any 1.5.x could be fine.
```
ESP8266_NONOS_SDK_V2.0.0_16_08_10.zip:
wget --content-disposition "http://bbs.espressif.com/download/file.php?id=1690"
ESP8266_NONOS_SDK_V2.0.0_16_07_19.zip:
wget --content-disposition "http://bbs.espressif.com/download/file.php?id=1613"
ESP8266_NONOS_SDK_V1.5.4_16_05_20.zip:
wget --content-disposition "http://bbs.espressif.com/download/file.php?id=1469"
ESP8266_NONOS_SDK_V1.5.3_16_04_18.zip:
wget --content-disposition "http://bbs.espressif.com/download/file.php?id=1361"
ESP8266_NONOS_SDK_V1.5.2_16_01_29.zip:
wget --content-disposition "http://bbs.espressif.com/download/file.php?id=1079"
```
The `esp-open-sdk` Makefile could also download this for you with the right flags.
It's tested with 1.5.2, 2.0.0 won't work without adjusting the build scripts. Any 1.5.x could be fine.
- Make sure your `esphttpdconfig.mk` is set up properly - link to the SDK etc.
To flash, just run `make flash`. First make sure your `esphttpdconfig.mk` is set up properly - link to sdk etc.
### Web resources
The web resources are in `html_orig`. To prepare for a build, run `build_web.sh`, which packs them and
copies over to `html`. The compression and minification is handled by scripts in libesphttpd, specifically
it runs yuicompressor on js and css and gzip or heatshrink on the other files. The `html` folder is
then embedded in the firmware image.
It's kind of tricky to develop the web resources locally; you might want to try the "split image"
Makefile option, then you can flash just the html portion with `make htmlflash`. I haven't tried this.
### Flashing
The Makefile should automatically build the parser and web resources for you when you run `make`.
Sometimes it does not, particularly with `make -B`. Try just plain `make`. You can always run those
build scripts manually, too.
To flash, just run `make flash`.
+26 -4
View File
@@ -2,7 +2,29 @@
echo "-- Preparing WWW files --"
mkdir -p html
yuicompressor html_orig/style.css > html/style.css
yuicompressor html_orig/script.js > html/script.js
minify --type=html html_orig/term.html -o html/term.tpl
[[ -e html ]] && rm -r html
mkdir -p html/img
mkdir -p html/js
mkdir -p html/css
# Join scripts
DD=html_orig/jssrc
cat $DD/chibi.js \
$DD/utils.js \
$DD/modal.js \
$DD/appcommon.js \
$DD/term.js \
$DD/wifi.js > html/js/app.js
sass --sourcemap=none html_orig/sass/app.scss html_orig/css/app.css
# No need to compress CSS and JS now, we run YUI on it later
cp html_orig/css/app.css html/css/app.css
cp html_orig/term.html html/term.tpl
cp html_orig/wifi.html html/wifi.tpl
cp html_orig/about.html html/about.tpl
cp html_orig/help.html html/help.tpl
cp html_orig/wifi_conn.html html/wifi_conn.tpl
cp html_orig/img/loader.gif html/img/loader.gif
cp html_orig/img/cvut.svg html/img/cvut.svg
cp html_orig/favicon.ico html/favicon.ico
-1
View File
@@ -1 +0,0 @@
var $=function(d,c){d=d.match(/^(\W)?(.*)/);return(c||document)["getElement"+(d[1]?d[1]=="#"?"ById":"sByClassName":"sByTagName")](d[2])};var m=function(e,d,f){d=document;f=d.createElement("p");f.innerHTML=e;e=d.createDocumentFragment();while(d=f.firstChild){e.appendChild(d)}return e};(function(){function a(r){return document.createElement(r)}var b=26,k=10;var l={a:false,x:0,y:0,suppress:false,hidden:false};var o=[];var g=["#111213","#CC0000","#4E9A06","#C4A000","#3465A4","#75507B","#06989A","#D3D7CF","#555753","#EF2929","#8AE234","#FCE94F","#729FCF","#AD7FA8","#34E2E2","#EEEEEC"];function p(){o.forEach(function(r,s){r.t=" ";r.fg=7;r.bg=0;d(r)})}function c(s,r){return o[s*b+r]}function i(){return c(l.y,l.x)}function q(r){l.hidden=!r;l.a&=r;d(i(),l.a)}function f(s,r){l.suppress=true;d(i(),false);l.x=r;l.y=s;l.suppress=false;d(i(),l.a)}function d(s,r){var v=s.e,t,u;t=r?s.bg:s.fg;u=r?s.fg:s.bg;v.innerText=(s.t+" ")[0];v.style.color=e(t);v.style.backgroundColor=e(u);v.style.fontWeight=t>7?"bold":"normal"}function h(){o.forEach(function(s,t){var r=l.a&&(t==l.y*b+l.x);d(s,r)})}function j(v){l.x=v.x;l.y=v.y;var w=0,C=0,y=v.screen;var r=7,x=0;while(w<y.length&&C<b*k){var A=o[C++];var u=y[w];if(u!=","){r=A.fg=parseInt(y[w++],16);x=A.bg=parseInt(y[w++],16)}else{w++;A.fg=r;A.bg=x}var B=A.t=y[w++];var s=0;switch(y[w]){case"r":s=1;break;case"s":s=2;break;case"t":s=3;break;case"u":s=4;break;default:s=0}if(s>0){var z=parseInt(y.substr(w+1,s));w=w+s+1;for(;z>0&&C<b*k;z--){A=o[C++];A.fg=r;A.bg=x;A.t=B}}}h()}function e(r){r=parseInt(r);if(r<0||r>15){r=0}return g[r]}function n(v){var u,r,t=$("#screen");for(var s=0;s<b*k;s++){u=a("span");if((s>0)&&(s%b==0)){t.appendChild(a("br"))}t.appendChild(u);r={t:" ",fg:7,bg:0,e:u};o.push(r);d(r)}setInterval(function(){l.a=!l.a;if(l.hidden){l.a=false}if(!l.suppress){d(i(),l.a)}},500);j(v)}window.Term={init:n,load:j,setCursor:f,enableCursor:q,clear:p}})();(function(){var g="ws://"+window.location.host+"/ws/update.cgi";var d;function c(i){console.log("CONNECTED")}function b(i){console.error("SOCKET CLOSED")}function f(i){try{console.log("RX: ",i.data);Term.load(JSON.parse(i.data))}catch(j){console.error(j)}}function e(i){console.error(i.data)}function a(i){if(typeof i!="string"){i=JSON.stringify(i)}d.send(i)}function h(){d=new WebSocket(g);d.onopen=c;d.onclose=b;d.onmessage=f;d.onerror=e;console.log("Opening socket.")}window.Conn={ws:null,init:h,send:a}})();function init(a){Term.init(a);Conn.init()};
-1
View File
@@ -1 +0,0 @@
html,body{background:#48505f;color:#eee;font-family:monospace;font-size:16pt;text-align:center}header{font-weight:bold;font-size:14pt;padding:6px;display:block}#screen{display:block;white-space:nowrap;background:#111213;border-radius:3px;padding:6px;box-shadow:inset 0 0 5px black;display:inline-block}#screen span{white-space:pre}#buttons{margin-top:10px}button{margin:0 2px;padding:10px 0;width:22%;max-width:80px;cursor:pointer}
-1
View File
@@ -1 +0,0 @@
<!doctype html><meta charset=utf-8><title>ESP8266 Remote Terminal</title><meta name=viewport content="width=device-width,shrink-to-fit=no,user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1"><link rel=stylesheet href=style.css><script src=script.js></script><header>ESP8266 Remote Terminal</header><div id=screen></div><div id=buttons><button>1</button><button>2</button><button>3</button><button>4</button></div><script>init(%screenData%)</script>
+80
View File
@@ -0,0 +1,80 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>About - ESP8266 Remote Terminal</title>
<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">
<link rel="stylesheet" href="/css/app.css">
<script src="/js/app.js"></script>
</head>
<body class="page-about">
<h1 onclick="location.href='/'">About</h1>
<div class="Box">
<img src="/img/cvut.svg" id="logo" class="mq-tablet-min">
<h2>ESP8266 Remote Terminal</h2>
<img src="/img/cvut.svg" id="logo2" class="mq-phone">
<p>&copy; Ondřej Hruška, 2017 &lt;<a href="mailto:ondra@ondrovo.com">ondra@ondrovo.com</a>&gt;</p>
<p><a href="http://measure.feld.cvut.cz/" target="blank">Katedra měření, FEL ČVUT</a><br>Department of Measurement, FEE CTU</p>
</div>
<div class="Box">
<h2>Firmware</h2>
<table>
<tr>
<th>Firmware</th>
<td>v%vers_fw%, build <i>%date%</i> at <i>%time%</i></td>
</tr>
<tr>
<th>libesphttpd</th>
<td>v%vers_httpd%</td>
</tr>
<tr>
<th>ESP&nbsp;IoT&nbsp;SDK</th>
<td>v%vers_sdk%</td>
</tr>
</table>
</div>
<div class="Box">
<h2>Issues</h2>
<p>
Please report any issues to the <a href="%githubrepo%/issues">bugtracker</a> or send them by e-mail.
</p>
<p>
Firmware updates can be downloaded from the <a href="%githubrepo%/releases">releases page</a>.
Flash the images using <a href="https://github.com/espressif/esptool">esptool</a>.
</p>
</div>
<div class="Box">
<h2>Contributing</h2>
<p>
Submit your improvements and ideas to the project on <a href="%githubrepo%">GitHub</a>.<br>
</p>
</div>
<div class="Box">
<h2>Acknowledgements</h2>
<p>
The webserver is based on a <a href="https://github.com/MightyPork/libesphttpd">fork</a> of the
<a href="https://github.com/Spritetm/esphttpd">esphttpd</a> library by Jeroen Domburg (Sprite_tm).
</p>
<p>
Using (modified) JS library <a href="https://github.com/kylebarrow/chibi">chibi.js</a> by Kyle Barrow as a lightweight jQuery alternative.
</p>
</div>
<nav id="botnav">
<a href="/">Terminal</a><!--
--><a href="/help">Help</a><!--
--><a href="/wifi">WiFi config</a>
</nav>
</body>
</html>
+868
View File
@@ -0,0 +1,868 @@
/* normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
/**
* 1. Set default font family to sans-serif.
* 2. Prevent iOS and IE text size adjust after device orientation change,
* without disabling user zoom.
*/
*, *:before, *:after {
box-sizing: border-box; }
html {
font-family: sans-serif;
/* 1 */
-ms-text-size-adjust: 100%;
/* 2 */
-webkit-text-size-adjust: 100%;
/* 2 */ }
/**
* Remove default margin.
*/
body {
margin: 0; }
/* HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined for any HTML5 element in IE 8/9.
* Correct `block` display not defined for `details` or `summary` in IE 10/11
* and Firefox.
* Correct `block` display not defined for `main` in IE 11.
*/
figure,
nav
{
display: block; }
/**
* 1. Correct `inline-block` display not defined in IE 8/9.
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
*/
canvas,
progress
{
display: inline-block;
/* 1 */
vertical-align: baseline;
/* 2 */ }
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
/**
* Address `[hidden]` styling not present in IE 8/9/10.
* Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
*/
[hidden]
{
display: none; }
/* Links
========================================================================== */
/**
* Remove the gray background color from active links in IE 10.
*/
a {
background-color: transparent; }
/**
* Improve readability of focused elements when they are also in an
* active/hover state.
*/
a:active,
a:hover {
outline: 0; }
/* Text-level semantics
========================================================================== */
/**
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
*/
/**
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
*/
b
{
font-weight: bold; }
/**
* Address styling not present in Safari and Chrome.
*/
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0; }
h2 {
font-size: 2em;
margin: 0.67em 0; }
/**
* Address styling not present in IE 8/9.
*/
/**
* Address inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%; }
/**
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline; }
sup {
top: -0.5em; }
sub {
bottom: -0.25em; }
/* Embedded content
========================================================================== */
/**
* Remove border when inside `a` element in IE 8/9/10.
*/
img {
border: 0; }
/**
* Correct overflow not hidden in IE 9/10/11.
*/
svg:not(:root) {
overflow: hidden; }
/* Grouping content
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari.
*/
/**
* Address differences between Firefox and other browsers.
*/
hr {
box-sizing: content-box;
height: 0; }
/**
* Contain overflow in all browsers.
*/
pre {
overflow: auto; }
/**
* Address odd `em`-unit font size rendering in all browsers.
*/
code,
pre
{
font-family: monospace;
font-size: 1em; }
/* Forms
========================================================================== */
/**
* Known limitation: by default, Chrome and Safari on OS X allow very limited
* styling of `select`, unless a `border` property is set.
*/
/**
* 1. Correct color not being inherited.
* Known issue: affects color of disabled elements.
* 2. Correct font properties not being inherited.
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
*/
button,
input,
select,
textarea {
color: inherit;
/* 1 */
font: inherit;
/* 2 */
margin: 0;
/* 3 */ }
/**
* Address `overflow` set to `hidden` in IE 8/9/10/11.
*/
button {
overflow: visible; }
/**
* Address inconsistent `text-transform` inheritance for `button` and `select`.
* All other form control elements do not inherit `text-transform` values.
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
* Correct `select` style inheritance in Firefox.
*/
button,
select {
text-transform: none; }
/**
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Correct inability to style clickable `input` types in iOS.
* 3. Improve usability and consistency of cursor style between image-type
* `input` and others.
*/
button,
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button;
/* 2 */
cursor: pointer;
/* 3 */ }
/**
* Re-set default cursor for disabled elements.
*/
button[disabled],
html input[disabled] {
cursor: default; }
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0; }
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
input {
line-height: normal; }
/**
* It's recommended that you don't attempt to style these elements.
* Firefox's implementation doesn't respect box-sizing, padding, or width.
*
* 1. Address box sizing set to `content-box` in IE 8/9/10.
* 2. Remove excess padding in IE 8/9/10.
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box;
/* 1 */
padding: 0;
/* 2 */ }
/**
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
* `font-size` values of the `input`, it causes the cursor style of the
* decrement button to change from `default` to `text`.
*/
/**
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
*/
/**
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
* Safari (but not Chrome) clips the cancel button when the search input has
* padding (and `textfield` appearance).
*/
/**
* Define consistent border, margin, and padding.
*/
/**
* 1. Correct `color` not being inherited in IE 8/9/10/11.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
border: 0;
/* 1 */
padding: 0;
/* 2 */ }
/**
* Remove default vertical scrollbar in IE 8/9/10/11.
*/
textarea {
overflow: auto; }
/**
* Don't inherit the `font-weight` (applied by a rule above).
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
*/
/* Tables
========================================================================== */
/**
* Remove most spacing between table cells.
*/
table {
border-collapse: collapse;
border-spacing: 0; }
td,
th {
padding: 0; }
html {
box-sizing: border-box; }
*, *::after, *::before {
box-sizing: inherit; }
.hidden {
display: none !important; }
[onclick] {
cursor: pointer; }
.Modal {
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
right: 0;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
transition: opacity .5s;
background: rgba(0, 0, 0, 0.65);
opacity: 0; }
.Modal.visible {
opacity: 1; }
.Modal.hidden {
display: none; }
.Dialog {
margin: 0.61805rem;
padding: 1rem;
overflow: hidden;
max-width: 100%;
max-height: 100%;
flex: 0 1 30rem;
background: #1c1c1e;
border-left: 6px solid #2972ba;
border-right: 6px solid #2972ba;
box-shadow: 0 0 2px 0 #434349, 0 0 6px 0 black;
border-radius: 6px; }
.Dialog h1, .Dialog h2 {
margin-top: 0; }
.Dialog p:last-child {
margin-bottom: 0; }
/*
// "toast"
.NotifyMsg {
position: fixed;
bottom: dist(2);
padding: dist(-1) dist(0);
// center horizontally
left: 50%;
@include translate(-50%,0);
// hack to remove blur in chrome
-webkit-font-smoothing: subpixel-antialiased;
-webkit-transform: translateZ(0) scale(1.0, 1.0);
background: #37a349;
&.error {
background: #d03e42;
}
color: white;
text-shadow: 0 0 2px black;
box-shadow: 0 0 6px 0 rgba(black, .6);
border-radius: 5px;
max-width: 80%;
@include media($phone) {
width: calc(100% - 1rem);
}
transition: opacity .5s;
opacity: 0;
&.visible { opacity: 1 }
&.hidden { display: none }
}
*/
html {
font-family: Arial, sans-serif;
color: #D0D0D0;
background: #131315; }
html, body {
border: 0 none;
margin: 0;
padding: 0;
text-decoration: none;
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: 1rem;
padding: 0.61805rem 1rem;
border-radius: 3px;
background-color: rgba(255, 255, 255, 0.07); }
@media screen and (max-width: 544px) {
.Box {
margin-top: 0.61805rem;
padding: 0.23608rem 0.38198rem; } }
.Box p:first-child {
margin-top: 0; }
body {
position: relative;
padding: 1rem;
overflow-y: auto; }
@media screen and (max-width: 544px) {
body {
padding: 0.61805rem; } }
body > * {
margin-left: auto;
margin-right: auto; }
h1, h2 {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none; }
h1 {
text-align: center;
font-size: 2.02729em;
margin-top: 0;
margin-bottom: 1rem; }
@media screen and (max-width: 544px) {
h1 {
font-size: 1.42383em;
margin-bottom: 0.61805rem; } }
@media screen and (min-width: 545px) and (max-width: 1000px) {
h1 {
font-size: 1.80203em; } }
h2 {
font-size: 1.26563em;
margin-bottom: 0.61805rem; }
td, th {
padding: 0.38198rem;
white-space: nowrap; }
@media screen and (max-width: 544px) {
td, th {
padding: 0.23608rem; } }
tbody th {
text-align: right;
width: 130px;
color: white; }
@media screen and (max-width: 544px) {
tbody th {
width: auto; } }
tbody td input[type="text"], tbody td input[type="number"] {
width: 10em; }
@media screen and (max-width: 544px) {
tbody td input[type="text"], tbody td input[type="number"] {
width: 8em; } }
#loader {
position: absolute;
right: 1.618rem;
top: 1.618rem;
transition: opacity .2s;
opacity: 0; }
@media screen and (max-width: 544px) {
#loader {
top: 1rem;
right: 1rem; } }
#loader.show {
opacity: 1; }
ul > * {
padding-top: .1em;
padding-bottom: .1em; }
#botnav {
padding-top: 1.5em;
text-align: center; }
#botnav a {
padding: 0 0.38198rem;
text-decoration: underline; }
#botnav a, #botnav a:visited, #botnav a:link {
color: #2e4d6e; }
#botnav a:hover {
color: #5abfff; }
button, input[type=submit], .button {
text-align: center;
cursor: pointer;
display: inline-block;
border-radius: 2px;
padding: 0 0.6em;
border: 0 none;
outline: 0 none !important;
line-height: 1.8em;
font-size: 1.1em;
margin-bottom: 3px;
min-width: 5em;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
text-shadow: 1.5px 1.5px 2px rgba(0, 0, 0, 0.6);
background-color: #3983cd;
box-shadow: 0 3px 0 #265f98;
text-decoration: none !important; }
button:active, input[type=submit]:active, .button:active {
position: relative;
top: 2px; }
button.narrow, input[type=submit].narrow, .button.narrow {
min-width: initial; }
button, button:link, button:visited, input[type=submit], input[type=submit]:link, input[type=submit]:visited, .button, .button:link, .button:visited {
color: #FEFEFE; }
button:hover, button:active, button.active, button.selected, input[type=submit]:hover, input[type=submit]:active, input[type=submit].active, input[type=submit].selected, .button:hover, .button:active, .button.active, .button.selected {
background-color: #2076C6;
color: #FEFEFE; }
button:hover, button.selected, button.active, input[type=submit]:hover, input[type=submit].selected, input[type=submit].active, .button:hover, .button.selected, .button.active {
box-shadow: 0 3px 0 #154c80; }
button:active, input[type=submit]:active, .button:active {
box-shadow: 0 1px 0 #154c80; }
button, input[type=submit], .button {
text-align: center;
cursor: pointer;
display: inline-block;
border-radius: 2px;
padding: 0 0.6em;
border: 0 none;
outline: 0 none !important;
line-height: 1.8em;
font-size: 1.1em;
margin-bottom: 3px;
min-width: 5em;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
text-shadow: 1.5px 1.5px 2px rgba(0, 0, 0, 0.6);
background-color: #3983cd;
box-shadow: 0 3px 0 #265f98;
text-decoration: none !important; }
button:active, input[type=submit]:active, .button:active {
position: relative;
top: 2px; }
button.narrow, input[type=submit].narrow, .button.narrow {
min-width: initial; }
button, button:link, button:visited, input[type=submit], input[type=submit]:link, input[type=submit]:visited, .button, .button:link, .button:visited {
color: #FEFEFE; }
button:hover, button:active, button.active, button.selected, input[type=submit]:hover, input[type=submit]:active, input[type=submit].active, input[type=submit].selected, .button:hover, .button:active, .button.active, .button.selected {
background-color: #2076C6;
color: #FEFEFE; }
button:hover, button.selected, button.active, input[type=submit]:hover, input[type=submit].selected, input[type=submit].active, .button:hover, .button.selected, .button.active {
box-shadow: 0 3px 0 #154c80; }
button:active, input[type=submit]:active, .button:active {
box-shadow: 0 1px 0 #154c80; }
input[type="number"], input[type="password"], input[type="text"], textarea, select {
border: 0 none;
border-bottom: 2px solid #214e7a;
background-color: #303030;
color: white;
padding: 6px;
line-height: 1em;
outline: 0 none !important;
-moz-outline: 0 none !important;
font-weight: normal; }
input[type="number"]:focus, input[type="number"]:hover, input[type="password"]:focus, input[type="password"]:hover, input[type="text"]:focus, input[type="text"]:hover, textarea:focus, textarea:hover, select:focus, select:hover {
border-bottom-color: #2972ba; }
#psk-modal form > *, #wificonfbox form > * {
margin-right: 0.38198rem; }
#psk-modal form > *:last-child, #wificonfbox form > *:last-child {
margin-right: 0; }
#ap-list {
column-count: 3;
column-gap: 0;
margin: 0 -0.23608rem; }
@media screen and (min-width: 545px) and (max-width: 1000px) {
#ap-list {
column-count: 2; } }
@media screen and (max-width: 544px) {
#ap-list {
column-count: 1; } }
#ap-loader, #ap-noscan {
background: rgba(255, 255, 255, 0.1);
border-radius: 5px;
padding: 0.38198rem;
margin-bottom: 0.38198rem; }
#ap-noscan {
font-weight: bold; }
#ap-box {
padding-bottom: 0.38198rem; }
#psk-modal form {
display: flex;
align-items: center;
margin: 0.38198rem; }
#psk-modal form input[type=password] {
min-width: 5rem; }
.AP {
break-inside: avoid-column;
max-width: 500px;
padding: 0.23608rem; }
.AP.selected .inner {
background: #42a6f9 !important;
cursor: default;
top: 0 !important; }
.AP .inner {
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
position: relative;
border-radius: 3px;
color: #222;
background: #afafaf;
transition: background-color 0.5s;
display: flex; }
.AP .inner:active {
left: 0;
top: 1px; }
.AP .inner:hover {
background: white; }
.AP .inner > * {
padding: 0.61805rem;
white-space: nowrap;
word-wrap: normal; }
.AP .inner .rssi {
min-width: 2.5rem;
flex: 0 0 15%;
text-align: right; }
.AP .inner .rssi:after {
padding-left: 0.09018rem;
content: '%';
font-size: 0.88889em; }
.AP .inner .essid {
flex: 1 1 70%;
min-width: 0;
text-overflow: ellipsis;
overflow: hidden;
font-weight: bold; }
.AP .inner .auth {
flex: 0 0 15%; }
.page-term h1 {
font-size: 1.80203em; }
@media screen and (max-width: 544px) {
.page-term h1 {
font-size: 1.42383em; } }
.page-term #screen {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
font-family: monospace;
font-size: 16pt;
white-space: nowrap;
background: #111213;
padding: 6px;
display: inline-block;
border: 2px solid #3983CD; }
.page-term #screen span {
white-space: pre;
cursor: pointer; }
.page-term #screen span:hover {
outline: 1px solid rgba(255, 255, 255, 0.4); }
@media screen and (max-width: 544px) {
.page-term #screen span:hover {
outline: 0 none; } }
.page-term #buttons {
margin-top: 10px;
white-space: nowrap; }
.page-term #buttons button {
margin: 0 3px;
padding: 10px 0;
width: 18%;
max-width: 65px;
min-width: initial;
cursor: pointer;
font-weight: bold; }
#termwrap {
text-align: center; }
.page-about .Box {
padding-left: 1rem;
padding-right: 1rem; }
.page-about .Box a {
font-weight: bold; }
.page-about #logo {
float: right;
height: 130px; }
.page-about #logo2 {
max-width: 100%; }
.page-about td {
white-space: normal; }
.colorprev {
margin-top: 0.38198rem;
margin-bottom: 0.38198rem; }
.colorprev span {
display: inline-block;
width: 2em;
padding: 0.38198rem 0;
text-align: center; }
.ansiref, .ansiref td, .ansiref th {
border: 1px solid #666; }
.ansiref th, .ansiref td {
white-space: normal; }
.ansiref th {
background-color: rgba(255, 255, 255, 0.1); }
.ansiref td:nth-child(1) {
font-family: monospace; }
.ansiref.w100 {
width: 100%; }
.ansiref.w100 td:nth-child(1) {
width: 9em; }
.ansiref.w100 td:nth-child(2) {
width: 8em; }
.fg0 {
color: #111213; }
.bg0 {
background-color: #111213; }
.fg1 {
color: #CC0000; }
.bg1 {
background-color: #CC0000; }
.fg2 {
color: #4E9A06; }
.bg2 {
background-color: #4E9A06; }
.fg3 {
color: #C4A000; }
.bg3 {
background-color: #C4A000; }
.fg4 {
color: #3465A4; }
.bg4 {
background-color: #3465A4; }
.fg5 {
color: #75507B; }
.bg5 {
background-color: #75507B; }
.fg6 {
color: #06989A; }
.bg6 {
background-color: #06989A; }
.fg7 {
color: #D3D7CF; }
.bg7 {
background-color: #D3D7CF; }
.fg8 {
color: #555753; }
.bg8 {
background-color: #555753; }
.fg9 {
color: #EF2929; }
.bg9 {
background-color: #EF2929; }
.fg10 {
color: #8AE234; }
.bg10 {
background-color: #8AE234; }
.fg11 {
color: #FCE94F; }
.bg11 {
background-color: #FCE94F; }
.fg12 {
color: #729FCF; }
.bg12 {
background-color: #729FCF; }
.fg13 {
color: #AD7FA8; }
.bg13 {
background-color: #AD7FA8; }
.fg14 {
color: #34E2E2; }
.bg14 {
background-color: #34E2E2; }
.fg15 {
color: #EEEEEC; }
.bg15 {
background-color: #EEEEEC; }
.fg8, .fg9, .fg10, .fg11, .fg12, .fg13, .fg14, .fg15 {
font-weight: bold; }
.nb {
font-weight: normal !important; }
@media screen and (min-width: 545px) {
.mq-phone {
display: none; } }
@media screen and (max-width: 544px) {
.mq-tablet-min {
display: none; } }
@media screen and (min-width: 1001px) {
.mq-tablet-max {
display: none; } }
@media screen and (max-width: 1000px) {
.mq-normal-min {
display: none; } }
Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

+339
View File
@@ -0,0 +1,339 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Help - ESP8266 Remote Terminal</title>
<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">
<link rel="stylesheet" href="/css/app.css">
<script src="/js/app.js"></script>
</head>
<body class="page-help">
<h1 onclick="location.href='/'">Quick Reference</h1>
<div class="Box">
<h2>Wiring</h2>
<ul>
<li>Communication UART on pins <b>Rx, Tx</b> at 115200-8-1-N</li>
<li>Debug log on pin <b>GPIO2</b> at 115200-8-1-N</li>
<li>Use 3.3V logic, or 5V with protection resistors (470R or more)</li>
<li>If the "LVD" LED on the ESP Term board lights up, the module doesn't get enough power. Check your connections.</li>
<li>Connect Rx and Tx with a piece of wire to test the terminal alone, you should see what you type in the browser.
NOTE: This won't work if your ESP8266 board has a built-in USB-serial (like NodeMCU).</li>
<li>For best performance, use the module in the Client mode. In AP mode, check that the channel used is clear;
interference may cause lag in the terminal.</li>
</ul>
</div>
<div class="Box">
<h2>Screen</h2>
<ul>
<li>Most ANSI escape sequences are supported.</li>
<li>The max screen size is 2000 characters (eg. <b>25x80</b>), default is <b>10x26</b>. Set using <code>\e]W&lt;rows&gt;;&lt;cols&gt;\a</code>.</li>
<li>The screen will automatically scroll, can be used for log output.</li>
<li>Display update is sent <b>after 20 ms of inactivity</b>.</li>
<li>At most 4 clients can be connected at the same time.</li>
<li>The browser display needs WebSockets for the real-time updating. It may not work on really old phones / browsers.</li>
</ul>
</div>
<div class="Box">
<h2>Color Reference</h2>
<p>Color is set using <code>\e[&lt;c&gt;m</code> or <code>\e[&lt;c&gt;;&lt;c&gt;m</code> where "&lt;c&gt;" are numbers from the following tables:</p>
<b>Foreground</b>
<div class="colorprev">
<span class="bg7 fg0">30</span>
<span class="bg0 fg1">31</span>
<span class="bg0 fg2">32</span>
<span class="bg0 fg3">33</span>
<span class="bg0 fg4">34</span>
<span class="bg0 fg5">35</span>
<span class="bg0 fg6">36</span>
<span class="bg0 fg7">37</span>
</div>
<div class="colorprev">
<span class="bg7 fg8">90</span>
<span class="bg0 fg9">91</span>
<span class="bg0 fg10">92</span>
<span class="bg0 fg11">93</span>
<span class="bg0 fg12">94</span>
<span class="bg0 fg13">95</span>
<span class="bg0 fg14">96</span>
<span class="bg0 fg15">97</span>
</div>
<b>Background</b>
<div class="colorprev">
<span class="bg0 fg15 nb">40</span>
<span class="bg1 fg15 nb">41</span>
<span class="bg2 fg15 nb">42</span>
<span class="bg3 fg0">43</span>
<span class="bg4 fg15 nb">44</span>
<span class="bg5 fg15 nb">45</span>
<span class="bg6 fg15 nb">46</span>
<span class="bg7 fg0">47</span>
</div>
<div class="colorprev">
<span class="bg8 fg15 nb">100</span>
<span class="bg9 fg0">101</span>
<span class="bg10 fg0">102</span>
<span class="bg11 fg0">103</span>
<span class="bg12 fg0">104</span>
<span class="bg13 fg0">105</span>
<span class="bg14 fg0">106</span>
<span class="bg15 fg0">107</span>
</div>
<p>Bright foreground can also be set using the "bold" attribute 1 (eg. <code>\e[31;1m</code>). For more details, see the ANSI code reference below.</p>
</div>
<div class="Box">
<h2>User Input</h2>
<p>
All the user types on their keyboard is sent as-is to the UART, including ESC, ANSI sequences for arrow keys and CR-LF for Enter.
The input is limited to ASCII codes 32-126, backspace 8 and tab 9.
</p>
<p>The buttons under the screen send ASCII codes 1, 2, 3, 4, 5.</p>
<p>
<b>Mouse input</b> (click/tap) is sent as <code>\e[&lt;y&gt;;&lt;x&gt;M</code>. You can use this for on-screen buttons, menu navigation etc.
</p>
</div>
<div class="Box">
<h2>Supported ANSI Escape Sequences</h2>
<p>Sequences are started by ASCII code 27 (ESC, <code>\e</code>, <code>\x1b</code>, <code>\033</code>)</p>
<p>Instead of <code>\a</code> (BELL, ASCII 7) in the commands, you can use `\e\` (ESC + backslash). It's the Text Separator code.</p>
<h3>Text Attributes</h3>
<p>
All text attributes are set using <code>\e[...m</code> where the dots are numbers separated by semicolons.
You can combine up to 3 attributes in a single command.
</p>
<table class="ansiref">
<thead>
<tr>
<th>Attribute</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>Reset text attributes to default</td>
</tr>
<tr>
<td>7</td>
<td>Inverse (fg/bg swap when printing)</td>
</tr>
<tr>
<td>27</td>
<td>Inverse OFF</td>
</tr>
<tr>
<td>30-37, 90-97</td>
<td>Foreground color, normal and bright</td>
</tr>
<tr>
<td>40-47, 100-107</td>
<td>Background color, normal and bright</td>
</tr>
</tbody>
</table>
<h3>Cursor</h3>
<p>Movement commands scroll the screen if needed. The coordinates are 1-based, origin top left.</p>
<table class="ansiref w100">
<thead>
<tr>
<th>Code</th>
<th>Params</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td>\e[&lt;n&gt;A</td>
<td>[count]</td>
<td>Move cursor up</td>
</tr>
<tr>
<td>\e[&lt;n&gt;B</td>
<td>[count]</td>
<td>Move cursor down</td>
</tr>
<tr>
<td>\e[&lt;n&gt;C</td>
<td>[count]</td>
<td>Move cursor forward (right)</td>
</tr>
<tr>
<td>\e[&lt;n&gt;D</td>
<td>[count]</td>
<td>Move cursor backward (left)</td>
</tr>
<tr>
<td>\e[&lt;n&gt;E</td>
<td>[count]</td>
<td>Go N line down, start of line</td>
</tr>
<tr>
<td>\e[&lt;n&gt;F</td>
<td>[count]</td>
<td>Go N lines up, start of line</td>
</tr>
<tr>
<td>\e[&lt;n&gt;G</td>
<td>column</td>
<td>Go to column</td>
</tr>
<tr>
<td>\e[&lt;y&gt;;&lt;x&gt;G</td>
<td>[row=1];[col=1]</td>
<td>Go to row and column</td>
</tr>
<tr>
<td>\e[6n</td>
<td>--</td>
<td>Query cursor position. Position is sent back as <code>\e[?;?R</code> with row;column.</td>
</tr>
<tr>
<td>\e[s</td>
<td>--</td>
<td>Store position</td>
</tr>
<tr>
<td>\e[u</td>
<td>--</td>
<td>Restore position</td>
</tr>
<tr>
<td>\e7</td>
<td>--</td>
<td>Store position & attributes</td>
</tr>
<tr>
<td>\e8</td>
<td>--</td>
<td>Restore position & attributes</td>
</tr>
<tr>
<td>\e[?25l</td>
<td>--</td>
<td>Hide cursor</td>
</tr>
<tr>
<td>\e[?25h</td>
<td>--</td>
<td>Show cursor</td>
</tr>
<tr>
<td>\e[?7l</td>
<td>--</td>
<td>Disable cursor auto-wrap & auto-scroll at end of screen</td>
</tr>
<tr>
<td>\e[?7h</td>
<td>--</td>
<td>Enable cursor auto-wrap & auto-scroll at end of screen</td>
</tr>
</tbody>
</table>
<h3>Screen</h3>
<table class="ansiref w100">
<thead>
<tr>
<th>Code</th>
<th>Params</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td>\e[&lt;m&gt;J</td>
<td>[mode=0]</td>
<td>Clear screen. Mode: 0 - from cursor, 1 - to cursor, 2 - all</td>
</tr>
<tr>
<td>\e[&lt;m&gt;K</td>
<td>[mode=0]</td>
<td>Erase line. Mode: 0 - from cursor, 1 - to cursor, 2 - all</td>
</tr>
<tr>
<td>\e[&lt;n&gt;S</td>
<td>[lines]</td>
<td>Scroll screen content up, add empty line at the bottom</td>
</tr>
<tr>
<td>\e[&lt;n&gt;T</td>
<td>[lines]</td>
<td>Scroll screen content down, add empty line at the top</td>
</tr>
<tr>
<td>\e]W&lt;r&gt;;&lt;c&gt;\a</td>
<td>rows;cols</td>
<td>Set screen size, maximum 25x80 (resp. total 2000 characters). This also clears the screen.</td>
</tr>
</tbody>
</table>
<h3>System Commands</h3>
<table class="ansiref w100">
<thead>
<tr>
<th>Code</th>
<th>Params</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td>\ec</td>
<td>--</td>
<td>
"Device Reset" - clear screen, reset attributes, show cursor & move it to 1,1.
The screen size and WiFi settings stay unchanged.
</td>
</tr>
<tr>
<td>\e]FR\a</td>
<td>--</td>
<td>"Factory Reset", emergency code when you mess up the WiFi, restores SSID to unique default, clears stored credentials & enters Client+AP mode.</td>
</tr>
<tr>
<td>\e[5n</td>
<td>--</td>
<td>Query device status, replies with <code>\e[0n</code> "device is OK". Can be used to check if the UART works.</td>
</tr>
</tbody>
</table>
</div>
<nav id="botnav">
<a href="/">Terminal</a><!--
--><a href="/wifi">WiFi config</a><!--
--><a href="/about">About</a>
</nav>
</body>
</html>
+5
View File
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

+1369
View File
File diff suppressed because it is too large Load Diff
+50
View File
@@ -0,0 +1,50 @@
/** Global generic init */
$.ready(function () {
// loader dots...
setInterval(function () {
$('.anim-dots').each(function (x) {
var $x = $(x);
var dots = $x.html() + '.';
if (dots.length == 5) dots = '.';
$x.html(dots);
});
}, 1000);
// flipping number boxes with the mouse wheel
$('input[type=number]').on('mousewheel', function(e) {
var val = +$(this).val();
if (isNaN(val)) val = 1;
var step = +($(this).attr('step') || 1);
var min = +$(this).attr('min');
var max = +$(this).attr('max');
if(e.wheelDelta > 0) {
val += step;
} else {
val -= step;
}
if (typeof min != 'undefined') val = Math.max(val, +min);
if (typeof max != 'undefined') val = Math.min(val, +max);
$(this).val(val);
if ("createEvent" in document) {
var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", false, true);
$(this)[0].dispatchEvent(evt);
} else {
$(this)[0].fireEvent("onchange");
}
e.preventDefault();
});
Modal.init();
});
$._loader = function(vis) {
if(vis)
$('#loader').addClass('show');
else
$('#loader').removeClass('show');
};
+702
View File
@@ -0,0 +1,702 @@
/*!chibi 3.0.7, Copyright 2012-2016 Kyle Barrow, released under MIT license */
// MODIFIED VERSION.
(function () {
'use strict';
var readyfn = [],
loadedfn = [],
domready = false,
pageloaded = false,
d = document,
w = window;
// Fire any function calls on ready event
function fireReady() {
var i;
domready = true;
for (i = 0; i < readyfn.length; i += 1) {
readyfn[i]();
}
readyfn = [];
}
// Fire any function calls on loaded event
function fireLoaded() {
var i;
pageloaded = true;
// For browsers with no DOM loaded support
if (!domready) {
fireReady();
}
for (i = 0; i < loadedfn.length; i += 1) {
loadedfn[i]();
}
loadedfn = [];
}
// Check DOM ready, page loaded
if (d.addEventListener) {
// Standards
d.addEventListener('DOMContentLoaded', fireReady, false);
w.addEventListener('load', fireLoaded, false);
} else if (d.attachEvent) {
// IE
d.attachEvent('onreadystatechange', fireReady);
// IE < 9
w.attachEvent('onload', fireLoaded);
} else {
// Anything else
w.onload = fireLoaded;
}
// Utility functions
// Loop through node array
function nodeLoop(fn, nodes) {
var i;
// Good idea to walk up the DOM
for (i = nodes.length - 1; i >= 0; i -= 1) {
fn(nodes[i]);
}
}
// Convert to camel case
function cssCamel(property) {
return property.replace(/-\w/g, function (result) {
return result.charAt(1).toUpperCase();
});
}
// Get computed style
function computeStyle(elm, property) {
// IE, everything else or null
return (elm.currentStyle) ? elm.currentStyle[cssCamel(property)] : (w.getComputedStyle) ? w.getComputedStyle(elm, null).getPropertyValue(property) : null;
}
// Returns URI encoded query string pair
function queryPair(name, value) {
return encodeURIComponent(name).replace(/%20/g, '+') + '=' + encodeURIComponent(value).replace(/%20/g, '+');
}
// Set CSS, important to wrap in try to prevent error thown on unsupported property
function setCss(elm, property, value) {
try {
elm.style[cssCamel(property)] = value;
} catch (e) {
}
}
// Show CSS
function showCss(elm) {
elm.style.display = '';
// For elements still hidden by style block
if (computeStyle(elm, 'display') === 'none') {
elm.style.display = 'block';
}
}
// Serialize form & JSON values
function serializeData(nodes) {
var querystring = '', subelm, i, j;
if (nodes.constructor === Object) { // Serialize JSON data
for (subelm in nodes) {
if (nodes.hasOwnProperty(subelm)) {
if (nodes[subelm].constructor === Array) {
for (i = 0; i < nodes[subelm].length; i += 1) {
querystring += '&' + queryPair(subelm, nodes[subelm][i]);
}
} else {
querystring += '&' + queryPair(subelm, nodes[subelm]);
}
}
}
} else { // Serialize node data
nodeLoop(function (elm) {
if (elm.nodeName === 'FORM') {
for (i = 0; i < elm.elements.length; i += 1) {
subelm = elm.elements[i];
if (!subelm.disabled) {
switch (subelm.type) {
// Ignore buttons, unsupported XHR 1 form fields
case 'button':
case 'image':
case 'file':
case 'submit':
case 'reset':
break;
case 'select-one':
if (subelm.length > 0) {
querystring += '&' + queryPair(subelm.name, subelm.value);
}
break;
case 'select-multiple':
for (j = 0; j < subelm.length; j += 1) {
if (subelm[j].selected) {
querystring += '&' + queryPair(subelm.name, subelm[j].value);
}
}
break;
case 'checkbox':
case 'radio':
if (subelm.checked) {
querystring += '&' + queryPair(subelm.name, subelm.value);
}
break;
// Everything else including shinny new HTML5 input types
default:
querystring += '&' + queryPair(subelm.name, subelm.value);
}
}
}
}
}, nodes);
}
// Tidy up first &
return (querystring.length > 0) ? querystring.substring(1) : '';
}
// Class helper
function classHelper(classes, action, nodes) {
var classarray, search, i, replace, has = false;
if (classes) {
// Trim any whitespace
classarray = classes.split(/\s+/);
nodeLoop(function (elm) {
for (i = 0; i < classarray.length; i += 1) {
var clz = classarray[i];
if (action === 'remove') {
elm.classList.remove(clz);
}
else if (action === 'add') {
elm.classList.add(clz);
}
else if (action === 'toggle') {
elm.classList.toggle(clz);
}
else if (action === 'has') {
if (elm.classList.contains(clz)) {
has = true;
break;
}
}
// search = new RegExp('\\b' + classarray[i] + '\\b', 'g');
// replace = new RegExp(' *' + classarray[i] + '\\b', 'g');
// if (action === 'remove') {
// elm.className = elm.className.replace(search, '');
// } else if (action === 'toggle') {
// elm.className = (elm.className.match(search)) ? elm.className.replace(replace, '') : elm.className + ' ' + classarray[i];
// } else if (action === 'has') {
// if (elm.className.match(search)) {
// has = true;
// break;
// }
// }
}
}, nodes);
}
return has;
}
// HTML insertion helper
function insertHtml(value, position, nodes) {
var tmpnodes, tmpnode;
if (value) {
nodeLoop(function (elm) {
// No insertAdjacentHTML support for FF < 8 and IE doesn't allow insertAdjacentHTML table manipulation, so use this instead
// Convert string to node. We can't innerHTML on a document fragment
tmpnodes = d.createElement('div');
tmpnodes.innerHTML = value;
while ((tmpnode = tmpnodes.lastChild) !== null) {
// Catch error in unlikely case elm has been removed
try {
if (position === 'before') {
elm.parentNode.insertBefore(tmpnode, elm);
} else if (position === 'after') {
elm.parentNode.insertBefore(tmpnode, elm.nextSibling);
} else if (position === 'append') {
elm.appendChild(tmpnode);
} else if (position === 'prepend') {
elm.insertBefore(tmpnode, elm.firstChild);
}
} catch (e) {
break;
}
}
}, nodes);
}
}
// Get nodes and return chibi
function chibi(selector) {
var cb, nodes = [], json = false, nodelist, i;
if (selector) {
// Element node, would prefer to use (selector instanceof HTMLElement) but no IE support
if (selector.nodeType && selector.nodeType === 1) {
nodes = [selector]; // return element as node list
} else if (typeof selector === 'object') {
// JSON, document object or node list, would prefer to use (selector instanceof NodeList) but no IE support
json = (typeof selector.length !== 'number');
nodes = selector;
} else if (typeof selector === 'string') {
nodelist = d.querySelectorAll(selector);
// Convert node list to array so results have full access to array methods
// Array.prototype.slice.call not supported in IE < 9 and often slower than loop anyway
for (i = 0; i < nodelist.length; i += 1) {
nodes[i] = nodelist[i];
}
}
}
// Only attach nodes if not JSON
cb = json ? {} : nodes;
// Public functions
// Executes a function on nodes
cb.each = function (fn) {
if (typeof fn === 'function') {
nodeLoop(function (elm) {
// <= IE 8 loses scope so need to apply
return fn.apply(elm, arguments);
}, nodes);
}
return cb;
};
// Find first
cb.first = function () {
return chibi(nodes.shift());
};
// Find last
cb.last = function () {
return chibi(nodes.pop());
};
// Find odd
cb.odd = function () {
var odds = [], i;
for (i = 0; i < nodes.length; i += 2) {
odds.push(nodes[i]);
}
return chibi(odds);
};
// Find even
cb.even = function () {
var evens = [], i;
for (i = 1; i < nodes.length; i += 2) {
evens.push(nodes[i]);
}
return chibi(evens);
};
// Hide node
cb.hide = function () {
nodeLoop(function (elm) {
elm.style.display = 'none';
}, nodes);
return cb;
};
// Show node
cb.show = function () {
nodeLoop(function (elm) {
showCss(elm);
}, nodes);
return cb;
};
// Toggle node display
cb.toggle = function (state) {
if (typeof state != 'undefined') { // ADDED
if (state)
cb.show();
else
cb.hide();
} else {
nodeLoop(function (elm) {
// computeStyle instead of style.display == 'none' catches elements that are hidden via style block
if (computeStyle(elm, 'display') === 'none') {
showCss(elm);
} else {
elm.style.display = 'none';
}
}, nodes);
}
return cb;
};
// Remove node
cb.remove = function () {
nodeLoop(function (elm) {
// Catch error in unlikely case elm has been removed
try {
elm.parentNode.removeChild(elm);
} catch (e) {
}
}, nodes);
return chibi();
};
// Get/Set CSS
cb.css = function (property, value) {
if (property) {
if (value || value === '') {
nodeLoop(function (elm) {
setCss(elm, property, value);
}, nodes);
return cb;
}
if (nodes[0]) {
if (nodes[0].style[cssCamel(property)]) {
return nodes[0].style[cssCamel(property)];
}
if (computeStyle(nodes[0], property)) {
return computeStyle(nodes[0], property);
}
}
}
};
// Get class(es)
cb.getClass = function () {
if (nodes[0] && nodes[0].className.length > 0) {
// Weak IE trim support
return nodes[0].className.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '').replace(/\s+/, ' ');
}
};
// Set (replaces) classes
cb.setClass = function (classes) {
if (classes || classes === '') {
nodeLoop(function (elm) {
elm.className = classes;
}, nodes);
}
return cb;
};
// Add class
cb.addClass = function (classes) {
classHelper(classes, 'add', nodes);
// if (classes) {
// nodeLoop(function (elm) {
// elm.className += ' ' + classes;
// }, nodes);
// }
return cb;
};
// Remove class
cb.removeClass = function (classes) {
classHelper(classes, 'remove', nodes);
return cb;
};
// Toggle class
cb.toggleClass = function (classes) {
classHelper(classes, 'toggle', nodes);
return cb;
};
// Has class
cb.hasClass = function (classes) {
return classHelper(classes, 'has', nodes);
};
// Get/set HTML
cb.html = function (value) {
if (value || value === '') {
nodeLoop(function (elm) {
elm.innerHTML = value;
}, nodes);
return cb;
}
if (nodes[0]) {
return nodes[0].innerHTML;
}
};
// Insert HTML before selector
cb.htmlBefore = function (value) {
insertHtml(value, 'before', nodes);
return cb;
};
// Insert HTML after selector
cb.htmlAfter = function (value) {
insertHtml(value, 'after', nodes);
return cb;
};
// Insert HTML after selector innerHTML
cb.htmlAppend = function (value) {
insertHtml(value, 'append', nodes);
return cb;
};
// Insert HTML before selector innerHTML
cb.htmlPrepend = function (value) {
insertHtml(value, 'prepend', nodes);
return cb;
};
// Get/Set HTML attributes
cb.attr = function (property, value) {
if (property) {
property = property.toLowerCase();
// IE < 9 doesn't allow style or class via get/setAttribute so switch. cssText returns prettier CSS anyway
if (typeof value !== 'undefined') {//FIXED BUG HERE
nodeLoop(function (elm) {
if (property === 'style') {
elm.style.cssText = value;
} else if (property === 'class') {
elm.className = value;
} else {
elm.setAttribute(property, value);
}
}, nodes);
return cb;
}
if (nodes[0]) {
if (property === 'style') {
if (nodes[0].style.cssText) {
return nodes[0].style.cssText;
}
} else if (property === 'class') {
if (nodes[0].className) {
return nodes[0].className;
}
} else {
if (nodes[0].getAttribute(property)) {
return nodes[0].getAttribute(property);
}
}
}
}
};
// Get/Set HTML data property
cb.data = function (key, value) {
if (key) {
return cb.attr('data-' + key, value);
}
};
// Get/Set form element values
cb.val = function (value) {
var values, i, j;
if (typeof value != 'undefined') { // FIXED A BUG HERE
nodeLoop(function (elm) {
switch (elm.nodeName) {
case 'SELECT':
if (typeof value === 'string' || typeof value === 'number') {
value = [value];
}
for (i = 0; i < elm.length; i += 1) {
// Multiple select
for (j = 0; j < value.length; j += 1) {
elm[i].selected = '';
if (elm[i].value === value[j]) {
elm[i].selected = 'selected';
break;
}
}
}
break;
case 'INPUT':
case 'TEXTAREA':
case 'BUTTON':
elm.value = value;
break;
}
}, nodes);
return cb;
}
if (nodes[0]) {
switch (nodes[0].nodeName) {
case 'SELECT':
values = [];
for (i = 0; i < nodes[0].length; i += 1) {
if (nodes[0][i].selected) {
values.push(nodes[0][i].value);
}
}
return (values.length > 1) ? values : values[0];
case 'INPUT':
case 'TEXTAREA':
case 'BUTTON':
return nodes[0].value;
}
}
};
// Return matching checked checkbox or radios
cb.checked = function (check) {
if (typeof check === 'boolean') {
nodeLoop(function (elm) {
if (elm.nodeName === 'INPUT' && (elm.type === 'checkbox' || elm.type === 'radio')) {
elm.checked = check;
}
}, nodes);
return cb;
}
if (nodes[0] && nodes[0].nodeName === 'INPUT' && (nodes[0].type === 'checkbox' || nodes[0].type === 'radio')) {
return (!!nodes[0].checked);
}
};
// Add event handler
cb.on = function (event, fn) {
if (selector === w || selector === d) {
nodes = [selector];
}
nodeLoop(function (elm) {
if (d.addEventListener) {
elm.addEventListener(event, fn, false);
} else if (d.attachEvent) {
// <= IE 8 loses scope so need to apply, we add this to object so we can detach later (can't detach anonymous functions)
elm[event + fn] = function () {
return fn.apply(elm, arguments);
};
elm.attachEvent('on' + event, elm[event + fn]);
}
}, nodes);
return cb;
};
// Remove event handler
cb.off = function (event, fn) {
if (selector === w || selector === d) {
nodes = [selector];
}
nodeLoop(function (elm) {
if (d.addEventListener) {
elm.removeEventListener(event, fn, false);
} else if (d.attachEvent) {
elm.detachEvent('on' + event, elm[event + fn]);
// Tidy up
elm[event + fn] = null;
}
}, nodes);
return cb;
};
return cb;
}
// Basic XHR
chibi.ajax = function (options) { // if options is a number, it's timeout in ms
var opts = extend({
method: 'GET',
nocache: true,
timeout: 5000,
loader: true,
callback: null
}, options);
opts.method = opts.method.toUpperCase();
var loaderFn = opts.loader ? chibi._loader : function(){};
var url = opts.url;
var method = opts.method;
var query = null;
if (opts.data) {
query = serializeData(opts.data);
}
if (query && (method === 'GET')) {
url += (url.indexOf('?') === -1) ? '?' + query : '&' + query;
query = null;
}
var xhr = new XMLHttpRequest();
// prevent caching
if (opts.nocache) {
var ts = (+(new Date())).toString(36);
url += ((url.indexOf('?') === -1) ? '?' : '&') + '_=' + ts;
}
loaderFn(true);
xhr.open(method, url, true);
xhr.timeout = opts.timeout;
// Abort after given timeout
var abortTmeo = setTimeout(function () {
console.error("XHR timed out.");
xhr.abort();
loaderFn(false);
}, opts.timeout + 10);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
loaderFn(false);
opts.callback && opts.callback(xhr.responseText, xhr.status);
clearTimeout(abortTmeo);
}
};
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
if (method === 'POST') {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
}
xhr.send(query);
return xhr;
};
chibi._loader = function(){};
// Alias to cb.ajax(url, 'get', callback)
chibi.get = function (url, callback, opts) {
opts = opts || {};
opts.url = url;
opts.callback = callback;
opts.method = 'GET';
return chibi.ajax(opts);
};
// Alias to cb.ajax(url, 'post', callback)
chibi.post = function (url, callback, opts) {
opts = opts || {};
opts.url = url;
opts.callback = callback;
opts.method = 'POST';
return chibi.ajax(opts);
};
// Fire on DOM ready
chibi.ready = function (fn) {
if (fn) {
if (domready) {
fn();
return chibi;
} else {
readyfn.push(fn);
}
}
};
// Fire on page loaded
chibi.loaded = function (fn) {
if (fn) {
if (pageloaded) {
fn();
return chibi;
} else {
loadedfn.push(fn);
}
}
};
var entityMap = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
'/': '&#x2F;',
'`': '&#x60;',
'=': '&#x3D;'
};
chibi.htmlEscape = function(string) {
return String(string).replace(/[&<>"'`=\/]/g, function (s) {
return entityMap[s];
});
};
// Set Chibi's global namespace here ($)
w.$ = chibi;
}());
+41
View File
@@ -0,0 +1,41 @@
/** Module for toggling a modal overlay */
(function () {
var modal = {};
modal.show = function (sel) {
var $m = $(sel);
$m.removeClass('hidden visible');
setTimeout(function () {
$m.addClass('visible');
}, 1);
};
modal.hide = function (sel) {
var $m = $(sel);
$m.removeClass('visible');
setTimeout(function () {
$m.addClass('hidden');
}, 500); // transition time
};
modal.init = function () {
// close modal by click outside the dialog
$('.Modal').on('click', function () {
if ($(this).hasClass('no-close')) return; // this is a no-close modal
modal.hide(this);
});
$('.Dialog').on('click', function (e) {
e.stopImmediatePropagation();
});
// Hide all modals on esc
$(window).on('keydown', function (e) {
if (e.which == 27) {
modal.hide('.Modal');
}
});
};
window.Modal = modal;
})();
+303
View File
@@ -0,0 +1,303 @@
(function() {
/**
* Terminal module
*/
var Term = (function () {
var W, H;
var cursor = {a: false, x: 0, y: 0, suppress: false, hidden: false};
var screen = [];
var blinkIval;
/*
/!** Clear screen *!/
function cls() {
screen.forEach(function(cell, i) {
cell.t = ' ';
cell.fg = 7;
cell.bg = 0;
blit(cell);
});
}
*/
/** Set text and color at XY */
function cellAt(y, x) {
return screen[y*W+x];
}
/** Get cell under cursor */
function cursorCell() {
return cellAt(cursor.y, cursor.x);
}
/*
/!** Enable or disable cursor visibility *!/
function cursorEnable(enable) {
cursor.hidden = !enable;
cursor.a &= enable;
blit(cursorCell(), cursor.a);
}
/!** Safely move cursor *!/
function cursorSet(y, x) {
// Hide and prevent from showing up during the move
cursor.suppress = true;
blit(cursorCell(), false);
cursor.x = x;
cursor.y = y;
// Show again
cursor.suppress = false;
blit(cursorCell(), cursor.a);
}
*/
/** Update cell on display. inv = invert (for cursor) */
function blit(cell, inv) {
var e = cell.e, fg, bg;
// Colors
fg = inv ? cell.bg : cell.fg;
bg = inv ? cell.fg : cell.bg;
// Update
e.innerText = (cell.t+' ')[0];
e.className = 'fg'+fg+' bg'+bg;
}
/** Show entire screen */
function blitAll() {
screen.forEach(function(cell, i) {
/* Invert if under cursor & cursor active */
var inv = cursor.a && (i == cursor.y*W+cursor.x);
blit(cell, inv);
});
}
/** Load screen content from a 'binary' sequence */
function load(obj) {
cursor.x = obj.x;
cursor.y = obj.y;
cursor.hidden = !obj.cv;
// full re-init if size changed
if (obj.w != W || obj.h != H) {
Term.init(obj);
return;
}
// Simple compression - hexFG hexBG 'ASCII' (r/s/t/u NUM{1,2,3,4})?
// comma instead of both colors = same as before
var i = 0, ci = 0, str = obj.screen;
var fg = 7, bg = 0;
while(i < str.length && ci<W*H) {
var cell = screen[ci++];
var j = str[i];
if (j != ',') { // comma = repeat last colors
fg = cell.fg = parseInt(str[i++], 16);
bg = cell.bg = parseInt(str[i++], 16);
} else {
i++;
cell.fg = fg;
cell.bg = bg;
}
var t = cell.t = str[i++];
var repchars = 0;
switch(str[i]) {
case 'r': repchars = 1; break;
case 's': repchars = 2; break;
case 't': repchars = 3; break;
case 'u': repchars = 4; break;
default: repchars = 0;
}
if (repchars > 0) {
var rep = parseInt(str.substr(i+1,repchars));
i = i + repchars + 1;
for (; rep>0 && ci<W*H; rep--) {
cell = screen[ci++];
cell.fg = fg;
cell.bg = bg;
cell.t = t;
}
}
}
blitAll();
}
/** Init the terminal */
function init(obj) {
W = obj.w;
H = obj.h;
/* Build screen & show */
var e, cell, scr = qq('#screen');
// Empty the screen node
while (scr.firstChild) scr.removeChild(scr.firstChild);
screen = [];
for(var i = 0; i < W*H; i++) {
e = mk('span');
(function() {
var x = i % W;
var y = Math.floor(i / W);
e.addEventListener('click', function () {
Input.onTap(y, x);
});
})();
/* End of line */
if ((i > 0) && (i % W == 0)) {
scr.appendChild(mk('br'));
}
/* The cell */
scr.appendChild(e);
cell = {t: ' ', fg: 7, bg: 0, e: e};
screen.push(cell);
blit(cell);
}
/* Cursor blinking */
clearInterval(blinkIval);
blinkIval = setInterval(function() {
cursor.a = !cursor.a;
if (cursor.hidden) {
cursor.a = false;
}
if (!cursor.suppress) {
blit(cursorCell(), cursor.a);
}
}, 500);
load(obj);
}
// publish
return {
init: init,
load: load
};
})();
/** Handle connections */
var Conn = (function() {
var ws;
function onOpen(evt) {
console.log("CONNECTED");
}
function onClose(evt) {
console.warn("SOCKET CLOSED, code "+evt.code+". Reconnecting...");
setTimeout(function() {
init();
}, 1000);
}
function onMessage(evt) {
try {
console.log("RX: ", evt.data);
// Assume all our messages are screen updates
Term.load(JSON.parse(evt.data));
} catch(e) {
console.error(e);
}
}
function doSend(message) {
console.log("TX: ", message);
if (ws.readyState != 1) {
console.error("Socket not ready");
return;
}
if (typeof message != "string") {
message = JSON.stringify(message);
}
ws.send(message);
}
function init() {
ws = new WebSocket("ws://"+_root+"/ws/update.cgi");
ws.onopen = onOpen;
ws.onclose = onClose;
ws.onmessage = onMessage;
console.log("Opening socket.");
}
return {
ws: null,
init: init,
send: doSend
};
})();
//
// Keyboard (& mouse) input
//
var Input = (function() {
function sendStrMsg(str) {
Conn.send("STR:"+str);
}
function sendPosMsg(y, x) {
Conn.send("TAP:"+y+','+x);
}
function sendBtnMsg(n) {
Conn.send("BTN:"+n);
}
function init() {
window.addEventListener('keypress', function(e) {
var code = +e.which;
if (code >= 32 && code < 127) {
var ch = String.fromCharCode(code);
//console.log("Typed ", ch, "code", code, e);
sendStrMsg(ch);
}
});
window.addEventListener('keydown', function(e) {
var code = e.keyCode;
//console.log("Down ", code, e);
switch(code) {
case 8: sendStrMsg('\x08'); break;
case 13: sendStrMsg('\x0d\x0a'); break;
case 27: sendStrMsg('\x1b'); break; // this allows to directly enter control sequences
case 37: sendStrMsg('\x1b[D'); break;
case 38: sendStrMsg('\x1b[A'); break;
case 39: sendStrMsg('\x1b[C'); break;
case 40: sendStrMsg('\x1b[B'); break;
}
});
qa('#buttons button').forEach(function(s) {
s.addEventListener('click', function() {
sendBtnMsg(+this.dataset['n']);
});
});
}
return {
init: init,
onTap: sendPosMsg
};
})();
window.termInit = function (obj) {
Term.init(obj);
Conn.init();
Input.init();
}
})();
+95
View File
@@ -0,0 +1,95 @@
/** Make a node */
function mk(e) {return document.createElement(e)}
/** Find one by query */
function qq(s) {return document.querySelector(s)}
/** Find all by query */
function qa(s) {return document.querySelectorAll(s)}
/** Convert any to bool safely */
function bool(x) {
return (x === 1 || x === '1' || x === true || x === 'true');
}
function intval(x) {
return parseInt(x);
}
/** Extend an objects with options */
function extend(defaults, options) {
var target = {};
Object.keys(defaults).forEach(function(k){
target[k] = defaults[k];
});
Object.keys(options).forEach(function(k){
target[k] = options[k];
});
return target;
}
/** Escape string for use as literal in RegExp */
function rgxe(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
function numfmt(x, places) {
var pow = Math.pow(10, places);
return Math.round(x*pow) / pow;
}
function estimateLoadTime(fs, n) {
return (1000/fs)*n+1500;
}
function msNow() {
return +(new Date);
}
function msElapsed(start) {
return msNow() - start;
}
Math.log10 = Math.log10 || function(x) {
return Math.log(x) / Math.LN10;
};
/**
* Perform a substitution in the given string.
*
* Arguments - array or list of replacements.
* Arguments numeric keys will replace {0}, {1} etc.
* Named keys also work, ie. {foo: "bar"} -> replaces {foo} with bar.
*
* Braces are added to keys if missing.
*
* @returns {String} result
*/
String.prototype.format = function () {
var out = this;
var repl = arguments;
if (arguments.length == 1 && (Array.isArray(arguments[0]) || typeof arguments[0] == 'object')) {
repl = arguments[0];
}
for (var ph in repl) {
if (repl.hasOwnProperty(ph)) {
var ph_orig = ph;
if (!ph.match(/^\{.*\}$/)) {
ph = '{' + ph + '}';
}
// replace all occurrences
var pattern = new RegExp(rgxe(ph), "g");
out = out.replace(pattern, repl[ph_orig]);
}
}
return out;
};
+178
View File
@@ -0,0 +1,178 @@
/** Wifi page */
(function () {
var authStr = ['Open', 'WEP', 'WPA', 'WPA2', 'WPA/WPA2'];
var curSSID;
/** Update display for received response */
function onScan(resp, status) {
if (status != 200) {
// bad response
rescan(5000); // wait 5sm then retry
return;
}
resp = JSON.parse(resp);
var done = !bool(resp.result.inProgress) && (resp.result.APs.length > 0);
rescan(done ? 15000 : 1000);
if (!done) return; // no redraw yet
// clear the AP list
var $list = $('#ap-list');
// remove old APs
$('.AP').remove();
$list.toggle(done);
$('#ap-loader').toggle(!done);
// scan done
resp.result.APs.sort(function (a, b) {
return b.rssi - a.rssi;
}).forEach(function (ap) {
ap.enc = intval(ap.enc);
if (ap.enc > 4) return; // hide unsupported auths
var item = document.createElement('div');
var $item = $(item)
.data('ssid', ap.essid)
.data('pwd', ap.enc != 0)
.addClass('AP');
// mark current SSID
if (ap.essid == curSSID) {
$item.addClass('selected');
}
var inner = document.createElement('div');
$(inner).addClass('inner')
.htmlAppend('<div class="rssi">{0}</div>'.format(ap.rssi_perc))
.htmlAppend('<div class="essid" title="{0}">{0}</div>'.format($.htmlEscape(ap.essid)))
.htmlAppend('<div class="auth">{0}</div>'.format(authStr[ap.enc]));
$item.on('click', function () {
var $th = $(this);
// populate the form
$('#conn-essid').val($th.data('ssid'));
$('#conn-passwd').val(''); // clear
if ($th.data('pwd')) {
// this AP needs a password
Modal.show('#psk-modal');
} else {
Modal.show('#reset-modal');
$('#conn-form').submit();
}
});
item.appendChild(inner);
$list[0].appendChild(item);
});
}
/** Ask the CGI what APs are visible (async) */
function scanAPs() {
$.get('http://'+_root+'/wifi/scan', onScan);
}
function rescan(time) {
setTimeout(scanAPs, time);
}
/** Set up the WiFi page */
window.wifiInit = function (obj) {
//var ap_json = {
// "result": {
// "inProgress": "0",
// "APs": [
// {"essid": "Chlivek", "bssid": "88:f7:c7:52:b3:99", "rssi": "204", "enc": "4", "channel": "1"},
// {"essid": "TyNikdy", "bssid": "5c:f4:ab:0d:f1:1b", "rssi": "164", "enc": "3", "channel": "1"},
// ]
// }
//};
// Hide what should be hidden in this mode
$('.x-hide-'+obj.mode).addClass('hidden');
obj.mode = +obj.mode;
// Channel writable only in AP mode
if (obj.mode != 2) $('#channel').attr('readonly', 1);
curSSID = obj.staSSID;
// add SSID to the opmode field
if (curSSID) {
var box = $('#opmodebox');
box.html(box.html() + ' (' + curSSID + ')');
}
// hide IP if IP not received
if (!obj.staIP) $('.x-hide-noip').addClass('hidden');
// scan if not AP
if (obj.mode != 2) {
scanAPs();
}
$('#modeswitch').html([
'<a class="button" href="/wifi/setmode?mode=3">Client+AP</a>&nbsp;<a class="button" href="/wifi/setmode?mode=2">AP only</a>',
'<a class="button" href="/wifi/setmode?mode=3">Client+AP</a>',
'<a class="button" href="/wifi/setmode?mode=1">Client only</a>&nbsp;<a class="button" href="/wifi/setmode?mode=2">AP only</a>'
][obj.mode-1]);
};
window.wifiConn = function () {
var xhr = new XMLHttpRequest();
var abortTmeo;
function getStatus() {
xhr.open("GET", 'http://'+_root+"/wifi/connstatus");
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status >= 200 && xhr.status < 300) {
clearTimeout(abortTmeo);
var data = JSON.parse(xhr.responseText);
var done = false;
var msg = '...';
if (data.status == "idle") {
msg = "Preparing to connect";
}
else if (data.status == "success") {
msg = "Connected! Received IP " + data.ip + ".";
done = true;
}
else if (data.status == "working") {
msg = "Connecting to selected AP";
}
else if (data.status == "fail") {
msg = "Connection failed, check your password and try again.";
done = true;
}
$("#status").html(msg);
if (done) {
$('#backbtn').removeClass('hidden');
$('.anim-dots').addClass('hidden');
} else {
window.setTimeout(getStatus, 1000);
}
}
};
abortTmeo = setTimeout(function () {
xhr.abort();
$("#status").html("Telemetry lost, try reconnecting to the AP.");
$('#backbtn').removeClass('hidden');
$('.anim-dots').addClass('hidden');
}, 4000);
xhr.send();
}
getStatus();
};
})();
+10
View File
@@ -0,0 +1,10 @@
#!/bin/bash
echo "Packing js..."
cat jssrc/chibi.js \
jssrc/utils.js \
jssrc/modal.js \
jssrc/appcommon.js \
jssrc/term.js \
jssrc/wifi.js > js/app.js
+17
View File
@@ -0,0 +1,17 @@
// Customize Neat grid
@import "lib/neat/neat-helpers";
// optionally change gri settings
// Define breakpoints
$phone: new-breakpoint(max-width 544px);
$tablet: new-breakpoint(min-width 545px max-width 1000px);
$normal: new-breakpoint(min-width 1001px max-width 1376px);
$large: new-breakpoint(min-width 1377px);
$tablet-max: new-breakpoint(max-width 1000px);
$normal-max: new-breakpoint(max-width 1376px);
$tablet-min: new-breakpoint(min-width 545px);
$normal-min: new-breakpoint(min-width 1001px);
+178
View File
@@ -0,0 +1,178 @@
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;
}
}
}
+78
View File
@@ -0,0 +1,78 @@
.Modal {
position: fixed;
width: 100%; height: 100%;
left: 0; top: 0; right: 0; bottom: 0;
display: flex;
justify-content: center;
align-items: center;
transition: opacity .5s;
background: rgba(black, .65);
opacity: 0;
&.visible { opacity: 1 }
&.hidden { display: none }
}
.Dialog {
margin: dist(-1);
padding: dist(0);
overflow: hidden;
max-width: 100%;
max-height: 100%;
flex: 0 1 30rem;
//min-height: 15rem;
background: #1c1c1e;
border-left: 6px solid $c-form-highlight-a;
border-right: 6px solid $c-form-highlight-a;
box-shadow: 0 0 2px 0 #434349, 0 0 6px 0 black;
border-radius: 6px;
h1,h2 {
margin-top:0;
}
p:last-child {
margin-bottom: 0;
}
}
/*
// "toast"
.NotifyMsg {
position: fixed;
bottom: dist(2);
padding: dist(-1) dist(0);
// center horizontally
left: 50%;
@include translate(-50%,0);
// hack to remove blur in chrome
-webkit-font-smoothing: subpixel-antialiased;
-webkit-transform: translateZ(0) scale(1.0, 1.0);
background: #37a349;
&.error {
background: #d03e42;
}
color: white;
text-shadow: 0 0 2px black;
box-shadow: 0 0 6px 0 rgba(black, .6);
border-radius: 5px;
max-width: 80%;
@include media($phone) {
width: calc(100% - #{dist(0)});
}
transition: opacity .5s;
opacity: 0;
&.visible { opacity: 1 }
&.hidden { display: none }
}
*/
+439
View File
@@ -0,0 +1,439 @@
/* normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
/**
* 1. Set default font family to sans-serif.
* 2. Prevent iOS and IE text size adjust after device orientation change,
* without disabling user zoom.
*/
*, *:before, *:after {
box-sizing: border-box;
}
html {
font-family: sans-serif; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/**
* Remove default margin.
*/
body {
margin: 0;
}
/* HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined for any HTML5 element in IE 8/9.
* Correct `block` display not defined for `details` or `summary` in IE 10/11
* and Firefox.
* Correct `block` display not defined for `main` in IE 11.
*/
//article,
//aside,
//details,
//figcaption,
figure,
//footer,
//header,
//hgroup,
//main,
//menu,
nav
//section,
//summary
{
display: block;
}
/**
* 1. Correct `inline-block` display not defined in IE 8/9.
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
*/
//audio,
canvas,
progress
//video
{
display: inline-block; /* 1 */
vertical-align: baseline; /* 2 */
}
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
//
//audio:not([controls]) {
// display: none;
// height: 0;
//}
/**
* Address `[hidden]` styling not present in IE 8/9/10.
* Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
*/
[hidden]
//template
{
display: none;
}
/* Links
========================================================================== */
/**
* Remove the gray background color from active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* Improve readability of focused elements when they are also in an
* active/hover state.
*/
a:active,
a:hover {
outline: 0;
}
/* Text-level semantics
========================================================================== */
/**
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
*/
//abbr[title] {
// border-bottom: 1px dotted;
//}
/**
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
*/
b
//strong
{
font-weight: bold;
}
/**
* Address styling not present in Safari and Chrome.
*/
//
//dfn {
// font-style: italic;
//}
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
h2 {
font-size: 2em;
margin: 0.67em 0;
}
/**
* Address styling not present in IE 8/9.
*/
//
//mark {
// background: #ff0;
// color: #000;
//}
/**
* Address inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
/* Embedded content
========================================================================== */
/**
* Remove border when inside `a` element in IE 8/9/10.
*/
img {
border: 0;
}
/**
* Correct overflow not hidden in IE 9/10/11.
*/
svg:not(:root) {
overflow: hidden;
}
/* Grouping content
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari.
*/
//figure {
// margin: 1em 40px;
//}
/**
* Address differences between Firefox and other browsers.
*/
hr {
box-sizing: content-box;
height: 0;
}
/**
* Contain overflow in all browsers.
*/
pre {
overflow: auto;
}
/**
* Address odd `em`-unit font size rendering in all browsers.
*/
code,
//kbd,
pre
//samp
{
font-family: monospace;
font-size: 1em;
}
/* Forms
========================================================================== */
/**
* Known limitation: by default, Chrome and Safari on OS X allow very limited
* styling of `select`, unless a `border` property is set.
*/
/**
* 1. Correct color not being inherited.
* Known issue: affects color of disabled elements.
* 2. Correct font properties not being inherited.
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
*/
button,
input,
//optgroup,
select,
textarea {
color: inherit; /* 1 */
font: inherit; /* 2 */
margin: 0; /* 3 */
}
/**
* Address `overflow` set to `hidden` in IE 8/9/10/11.
*/
button {
overflow: visible;
}
/**
* Address inconsistent `text-transform` inheritance for `button` and `select`.
* All other form control elements do not inherit `text-transform` values.
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
* Correct `select` style inheritance in Firefox.
*/
button,
select {
text-transform: none;
}
/**
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Correct inability to style clickable `input` types in iOS.
* 3. Improve usability and consistency of cursor style between image-type
* `input` and others.
*/
button,
//html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button; /* 2 */
cursor: pointer; /* 3 */
}
/**
* Re-set default cursor for disabled elements.
*/
button[disabled],
html input[disabled] {
cursor: default;
}
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
input {
line-height: normal;
}
/**
* It's recommended that you don't attempt to style these elements.
* Firefox's implementation doesn't respect box-sizing, padding, or width.
*
* 1. Address box sizing set to `content-box` in IE 8/9/10.
* 2. Remove excess padding in IE 8/9/10.
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
* `font-size` values of the `input`, it causes the cursor style of the
* decrement button to change from `default` to `text`.
*/
//input[type="number"]::-webkit-inner-spin-button,
//input[type="number"]::-webkit-outer-spin-button {
// height: auto;
//}
/**
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
*/
//
//input[type="search"] {
// -webkit-appearance: textfield; /* 1 */
// box-sizing: content-box; /* 2 */
//}
/**
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
* Safari (but not Chrome) clips the cancel button when the search input has
* padding (and `textfield` appearance).
*/
//
//input[type="search"]::-webkit-search-cancel-button,
//input[type="search"]::-webkit-search-decoration {
// -webkit-appearance: none;
//}
/**
* Define consistent border, margin, and padding.
*/
//
//fieldset {
// border: 1px solid #c0c0c0;
// margin: 0 2px;
// padding: 0.35em 0.625em 0.75em;
//}
/**
* 1. Correct `color` not being inherited in IE 8/9/10/11.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
border: 0; /* 1 */
padding: 0; /* 2 */
}
/**
* Remove default vertical scrollbar in IE 8/9/10/11.
*/
textarea {
overflow: auto;
}
/**
* Don't inherit the `font-weight` (applied by a rule above).
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
*/
//
//optgroup {
// font-weight: bold;
//}
/* Tables
========================================================================== */
/**
* Remove most spacing between table cells.
*/
table {
border-collapse: collapse;
border-spacing: 0;
}
td,
th {
padding: 0;
}
+24
View File
@@ -0,0 +1,24 @@
$term-colors:
// 0 black, 1 red, 2 green, 3 yellow
// 4 blue, 5 mag, 6 cyan, 7 white
#111213, #CC0000, #4E9A06, #C4A000,
#3465A4, #75507B, #06989A, #D3D7CF,
// BRIGHT
// 8 black, 9 red, 10 green, 11 yellow
// 12 blue, 13 mag, 14 cyan, 15 white
#555753, #EF2929, #8AE234, #FCE94F,
#729FCF, #AD7FA8, #34E2E2, #EEEEEC;
@for $i from 1 through length($term-colors) {
$c: nth($term-colors, $i);
.fg#{$i - 1} { color: $c; }
.bg#{$i - 1} { background-color: $c; }
}
.fg8, .fg9, .fg10, .fg11, .fg12, .fg13, .fg14, .fg15 {
font-weight: bold;
}
.nb {
font-weight: normal !important;
}
+55
View File
@@ -0,0 +1,55 @@
// 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;
}
@mixin click-through() {
pointer-events: none;
}
// Disallow text selection
@mixin noselect() {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
// Allow text selection
@mixin can-select() {
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
cursor: text;
}
+61
View File
@@ -0,0 +1,61 @@
@import "normalize";
@import "lib/bourbon/bourbon";
@import "grid-settings";
@import "lib/neat/neat";
@import "utils";
$form-label-w: 130px;
$form-label-gap: 8px;
$form-field-w: 250px;
$c-form-label-fg: white;
$c-form-field-bg: #303030;
$c-form-field-fg: white;
$c-form-highlight: #214e7a;
$c-form-highlight-a: #2972ba;
@function dist($x) {
@return modular-scale($x, 1rem, $golden);
}
@function fsize($x) {
@return modular-scale($x, 1em, $major-second);
}
.hidden {
display: none !important;
}
[onclick] {
cursor: pointer;
}
@import "modal";
@import "layout";
@import "form/index";
// import all our pages
@import "pages/wifi";
@import "pages/term";
@import "pages/about";
@import "term-colors";
// media queries
@include media($tablet-min) {
.mq-phone { display: none; }
}
@include media($phone) {
.mq-tablet-min { display: none; }
}
@include media($normal-min) {
.mq-tablet-max { display: none; }
}
@include media($tablet-max) {
.mq-normal-min { display: none; }
}
+49
View File
@@ -0,0 +1,49 @@
@import "fancy_button_mixins";
$btn-gray-f: #DDDDDD;
$btn-gray-b: #505050;
$btn-gray-l: #343434; // line
$btn-green-f: #FEFEFE;
$btn-green-b: #2ca94b;
$btn-green-fa: #FEFEFE;
$btn-green-ba: #28ba5c;
$btn-red-f: #FEFEFE;
$btn-red-b: #D04E51;
$btn-red-fa: #FEFEFE;
$btn-red-ba: #d4403f;
$btn-blue-f: #FEFEFE;
$btn-blue-b: #3983cd;
$btn-blue-fa: #FEFEFE;
$btn-blue-ba: #2076C6;
$btn-orange-f: #FEFEFE;
$btn-orange-b: #dd8751;
$btn-orange-fa: #FEFEFE;
$btn-orange-ba: #C6733F;
button, input[type=submit], .button {
@include fancy-btn-base();
&.narrow {
min-width: initial;
}
text-shadow: 1.5px 1.5px 2px rgba(black, 0.6);
@include fancy-btn-colors($btn-blue-f, $btn-blue-b, $btn-blue-fa, $btn-blue-ba);
}
//input[type="submit"], .btn-green {
// @include fancy-btn-colors($btn-green-f, $btn-green-b, $btn-green-fa, $btn-green-ba);
//}
//.btn-red {
// @include fancy-btn-colors($btn-red-f, $btn-red-b, $btn-red-fa, $btn-red-ba);
//}
//.btn-blue {
// @include fancy-btn-colors($btn-blue-f, $btn-blue-b, $btn-blue-fa, $btn-blue-ba);
//}
+58
View File
@@ -0,0 +1,58 @@
// Button styling
@mixin fancy-btn-base() {
text-align: center;
cursor: pointer;
display: inline-block;
border-radius: 2px;
padding: 0 0.6em;
border: 0 none;
outline: 0 none !important;
line-height: 1.8em;
font-size: 1.1em;
margin-bottom: 3px;
min-width: 5em;
@include noselect();
//&[class^="icon-"]::before, &[class*=" icon-"]::before {
// margin-left:0;
//}
&:active {
position: relative;
top: 2px;
}
//&, &:active, &:hover, &:visited {
// text-decoration: none;
//}
}
@mixin fancy-btn-colors-full($text_p, $back_p, $side_p, $text_a, $back_a, $side_a) {
background-color: $back_p;
box-shadow: 0 3px 0 $side_p;
text-decoration: none !important;
&, &:link, &:visited {
color: $text_p;
}
&:hover, &:active, &.active, &.selected {
background-color: $back_a;
color: $text_a;
}
&:hover, &.selected, &.active {
box-shadow: 0 3px 0 $side_a;
}
// thinner shadow
&:active {
box-shadow: 0 1px 0 $side_a;
}
}
@mixin fancy-btn-colors($text_p, $back_p, $text_a, $back_a) {
@include fancy-btn-colors-full($text_p, $back_p, darken($back_p, 14), $text_a, $back_a, darken($back_a, 16));
}
+29
View File
@@ -0,0 +1,29 @@
@import "buttons";
#{$all-text-inputs}, select {
border: 0 none;
border-bottom: 2px solid $c-form-highlight;
background-color: $c-form-field-bg;
color: $c-form-field-fg;
padding: 6px;
line-height: 1em;
outline: 0 none !important;
-moz-outline: 0 none !important;
font-weight: normal;
&:focus, &:hover {
border-bottom-color: $c-form-highlight-a;
}
}
//#{$all-text-inputs} {
// @include can-select();
//}
//textarea {
// font-family: monospace;
// line-height: 1.2em;
// display: block; // fixes weird bottom margin
//}
//@import "select";
+169
View File
@@ -0,0 +1,169 @@
// Unified Form wrapper
form { @include naked(); }
#{$all-text-inputs}, select, label.select-wrap {
width: $form-field-w;
}
form .Row {
vertical-align: middle;
margin: 14px auto;
text-align: left;
display: flex;
flex-direction: row;
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
.spacer {
width: $form-label-w;
@include media($phone) {
display: none;
}
}
&.buttons {
input, .button {
margin-right: dist(-1);
}
}
&.centered {
justify-content: center;
}
&.message {
font-size: 1em;
//margin-left: $label-gap + $w-labels;
text-shadow: 1px 1px 3px black;
text-align: center;
&.error {
color: crimson;
}
&.ok {
color: #0fe851;
}
}
&.separator {
padding-top: 14px;
border-top: 2px solid rgba(255, 255, 255, 0.1);
}
textarea {
display: inline-block;
vertical-align: top;
min-height: 10rem;
flex-grow: 1;
resize: vertical;
}
label {
font-weight: bold;
color: $c-form-label-fg;
display: inline-block;
width: $form-label-w;
text-align: right;
text-shadow: 1px 1px 3px black;
padding: $form-label-gap;
align-self: flex-start;
@include noselect;
}
.checkbox-wrap {
display: inline-block;
width: $form-label-w;
padding: $form-label-gap;
text-align: right;
align-self: flex-start;
input[type=checkbox] {
margin: auto;
width: auto;
height: auto;
}
& + label {
width: $form-field-w;
padding-left: 0;
text-align: left;
cursor: pointer;
}
}
// special phone style
@include media($phone) {
flex-direction: column;
&.buttons, &.centered {
flex-direction: row;
}
&.buttons {
justify-content: center;
// remove margin on lats button
:last-child {
margin-right:0;
}
}
label {
padding-left: 0;
text-align: left;
width: auto;
}
.checkbox-wrap {
order: 1;
text-align: left;
padding-bottom: 0;
border-radius: .4px;
width: auto;
& + label {
width: auto;
}
}
#{$all-text-inputs}, textarea {
width: 100%;
}
}
}
// red asterisk
form span.required {
color: red;
}
.RadioGroup {
display: inline-block;
line-height: 1.5em;
vertical-align: middle;
label {
width: auto;
text-align: left;
cursor: pointer;
font-weight: normal;
}
input[type="radio"] {
vertical-align: middle;
margin: 0 0 0 5px;
}
}
+13
View File
@@ -0,0 +1,13 @@
@import 'fancy_button_mixins';
@import 'buttons';
@import 'form_elements';
%form-row-spacing {
& > * {
margin-right: dist(-2);
&:last-child { margin-right: 0 }
}
}
//@import 'form_layout';
//@import 'select';
+52
View File
@@ -0,0 +1,52 @@
// target chrome only
@media screen and (-webkit-min-device-pixel-ratio: 0) {
select { padding-right: 18px }
}
select {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
cursor: pointer;
line-height: 1.2em;
//padding: 3.5px;
padding-right: 1em;
// hack for firefox to disable dotted outline
&:-moz-focusring {
color: transparent;
text-shadow: 0 0 0 $c-form-field-fg;
}
option {
background: $c-form-field-bg;
}
}
label.select-wrap {
position: relative;
display: inline !important;
margin: 0 !important;
padding: 0 !important;
width: auto !important;
&:after {
content: '<>'; /* will be rotated */
font-family: "Consolas", monospace;
font-weight: bold;
color: $c-form-highlight-a;
top: 50%;
@include transform(translate(0, -50%) rotate(90deg));
right: 2px;
position:absolute;
z-index: 100;
pointer-events: none;
}
}
+411
View File
@@ -0,0 +1,411 @@
// The following features have been deprecated and will be removed in the next MAJOR version release
@mixin inline-block {
display: inline-block;
@warn "The inline-block mixin is deprecated and will be removed in the next major version release";
}
@mixin button ($style: simple, $base-color: #4294f0, $text-size: inherit, $padding: 7px 18px) {
@if type-of($style) == string and type-of($base-color) == color {
@include buttonstyle($style, $base-color, $text-size, $padding);
}
@if type-of($style) == string and type-of($base-color) == number {
$padding: $text-size;
$text-size: $base-color;
$base-color: #4294f0;
@if $padding == inherit {
$padding: 7px 18px;
}
@include buttonstyle($style, $base-color, $text-size, $padding);
}
@if type-of($style) == color and type-of($base-color) == color {
$base-color: $style;
$style: simple;
@include buttonstyle($style, $base-color, $text-size, $padding);
}
@if type-of($style) == color and type-of($base-color) == number {
$padding: $text-size;
$text-size: $base-color;
$base-color: $style;
$style: simple;
@if $padding == inherit {
$padding: 7px 18px;
}
@include buttonstyle($style, $base-color, $text-size, $padding);
}
@if type-of($style) == number {
$padding: $base-color;
$text-size: $style;
$base-color: #4294f0;
$style: simple;
@if $padding == #4294f0 {
$padding: 7px 18px;
}
@include buttonstyle($style, $base-color, $text-size, $padding);
}
&:disabled {
cursor: not-allowed;
opacity: 0.5;
}
@warn "The button mixin is deprecated and will be removed in the next major version release";
}
// Selector Style Button
@mixin buttonstyle($type, $b-color, $t-size, $pad) {
// Grayscale button
@if $type == simple and $b-color == grayscale($b-color) {
@include simple($b-color, true, $t-size, $pad);
}
@if $type == shiny and $b-color == grayscale($b-color) {
@include shiny($b-color, true, $t-size, $pad);
}
@if $type == pill and $b-color == grayscale($b-color) {
@include pill($b-color, true, $t-size, $pad);
}
@if $type == flat and $b-color == grayscale($b-color) {
@include flat($b-color, true, $t-size, $pad);
}
// Colored button
@if $type == simple {
@include simple($b-color, false, $t-size, $pad);
}
@else if $type == shiny {
@include shiny($b-color, false, $t-size, $pad);
}
@else if $type == pill {
@include pill($b-color, false, $t-size, $pad);
}
@else if $type == flat {
@include flat($b-color, false, $t-size, $pad);
}
}
// Simple Button
@mixin simple($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) {
$color: hsl(0, 0, 100%);
$border: adjust-color($base-color, $saturation: 9%, $lightness: -14%);
$inset-shadow: adjust-color($base-color, $saturation: -8%, $lightness: 15%);
$stop-gradient: adjust-color($base-color, $saturation: 9%, $lightness: -11%);
$text-shadow: adjust-color($base-color, $saturation: 15%, $lightness: -18%);
@if is-light($base-color) {
$color: hsl(0, 0, 20%);
$text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%);
}
@if $grayscale == true {
$border: grayscale($border);
$inset-shadow: grayscale($inset-shadow);
$stop-gradient: grayscale($stop-gradient);
$text-shadow: grayscale($text-shadow);
}
border: 1px solid $border;
border-radius: 3px;
box-shadow: inset 0 1px 0 0 $inset-shadow;
color: $color;
display: inline-block;
font-size: $textsize;
font-weight: bold;
@include linear-gradient ($base-color, $stop-gradient);
padding: $padding;
text-decoration: none;
text-shadow: 0 1px 0 $text-shadow;
background-clip: padding-box;
&:hover:not(:disabled) {
$base-color-hover: adjust-color($base-color, $saturation: -4%, $lightness: -5%);
$inset-shadow-hover: adjust-color($base-color, $saturation: -7%, $lightness: 5%);
$stop-gradient-hover: adjust-color($base-color, $saturation: 8%, $lightness: -14%);
@if $grayscale == true {
$base-color-hover: grayscale($base-color-hover);
$inset-shadow-hover: grayscale($inset-shadow-hover);
$stop-gradient-hover: grayscale($stop-gradient-hover);
}
@include linear-gradient ($base-color-hover, $stop-gradient-hover);
box-shadow: inset 0 1px 0 0 $inset-shadow-hover;
cursor: pointer;
}
&:active:not(:disabled),
&:focus:not(:disabled) {
$border-active: adjust-color($base-color, $saturation: 9%, $lightness: -14%);
$inset-shadow-active: adjust-color($base-color, $saturation: 7%, $lightness: -17%);
@if $grayscale == true {
$border-active: grayscale($border-active);
$inset-shadow-active: grayscale($inset-shadow-active);
}
border: 1px solid $border-active;
box-shadow: inset 0 0 8px 4px $inset-shadow-active, inset 0 0 8px 4px $inset-shadow-active;
}
}
// Shiny Button
@mixin shiny($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) {
$color: hsl(0, 0, 100%);
$border: adjust-color($base-color, $red: -117, $green: -111, $blue: -81);
$border-bottom: adjust-color($base-color, $red: -126, $green: -127, $blue: -122);
$fourth-stop: adjust-color($base-color, $red: -79, $green: -70, $blue: -46);
$inset-shadow: adjust-color($base-color, $red: 37, $green: 29, $blue: 12);
$second-stop: adjust-color($base-color, $red: -56, $green: -50, $blue: -33);
$text-shadow: adjust-color($base-color, $red: -140, $green: -141, $blue: -114);
$third-stop: adjust-color($base-color, $red: -86, $green: -75, $blue: -48);
@if is-light($base-color) {
$color: hsl(0, 0, 20%);
$text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%);
}
@if $grayscale == true {
$border: grayscale($border);
$border-bottom: grayscale($border-bottom);
$fourth-stop: grayscale($fourth-stop);
$inset-shadow: grayscale($inset-shadow);
$second-stop: grayscale($second-stop);
$text-shadow: grayscale($text-shadow);
$third-stop: grayscale($third-stop);
}
@include linear-gradient(top, $base-color 0%, $second-stop 50%, $third-stop 50%, $fourth-stop 100%);
border: 1px solid $border;
border-bottom: 1px solid $border-bottom;
border-radius: 5px;
box-shadow: inset 0 1px 0 0 $inset-shadow;
color: $color;
display: inline-block;
font-size: $textsize;
font-weight: bold;
padding: $padding;
text-align: center;
text-decoration: none;
text-shadow: 0 -1px 1px $text-shadow;
&:hover:not(:disabled) {
$first-stop-hover: adjust-color($base-color, $red: -13, $green: -15, $blue: -18);
$second-stop-hover: adjust-color($base-color, $red: -66, $green: -62, $blue: -51);
$third-stop-hover: adjust-color($base-color, $red: -93, $green: -85, $blue: -66);
$fourth-stop-hover: adjust-color($base-color, $red: -86, $green: -80, $blue: -63);
@if $grayscale == true {
$first-stop-hover: grayscale($first-stop-hover);
$second-stop-hover: grayscale($second-stop-hover);
$third-stop-hover: grayscale($third-stop-hover);
$fourth-stop-hover: grayscale($fourth-stop-hover);
}
@include linear-gradient(top, $first-stop-hover 0%,
$second-stop-hover 50%,
$third-stop-hover 50%,
$fourth-stop-hover 100%);
cursor: pointer;
}
&:active:not(:disabled),
&:focus:not(:disabled) {
$inset-shadow-active: adjust-color($base-color, $red: -111, $green: -116, $blue: -122);
@if $grayscale == true {
$inset-shadow-active: grayscale($inset-shadow-active);
}
box-shadow: inset 0 0 20px 0 $inset-shadow-active;
}
}
// Pill Button
@mixin pill($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) {
$color: hsl(0, 0, 100%);
$border-bottom: adjust-color($base-color, $hue: 8, $saturation: -11%, $lightness: -26%);
$border-sides: adjust-color($base-color, $hue: 4, $saturation: -21%, $lightness: -21%);
$border-top: adjust-color($base-color, $hue: -1, $saturation: -30%, $lightness: -15%);
$inset-shadow: adjust-color($base-color, $hue: -1, $saturation: -1%, $lightness: 7%);
$stop-gradient: adjust-color($base-color, $hue: 8, $saturation: 14%, $lightness: -10%);
$text-shadow: adjust-color($base-color, $hue: 5, $saturation: -19%, $lightness: -15%);
@if is-light($base-color) {
$color: hsl(0, 0, 20%);
$text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%);
}
@if $grayscale == true {
$border-bottom: grayscale($border-bottom);
$border-sides: grayscale($border-sides);
$border-top: grayscale($border-top);
$inset-shadow: grayscale($inset-shadow);
$stop-gradient: grayscale($stop-gradient);
$text-shadow: grayscale($text-shadow);
}
border: 1px solid $border-top;
border-color: $border-top $border-sides $border-bottom;
border-radius: 16px;
box-shadow: inset 0 1px 0 0 $inset-shadow;
color: $color;
display: inline-block;
font-size: $textsize;
font-weight: normal;
line-height: 1;
@include linear-gradient ($base-color, $stop-gradient);
padding: $padding;
text-align: center;
text-decoration: none;
text-shadow: 0 -1px 1px $text-shadow;
background-clip: padding-box;
&:hover:not(:disabled) {
$base-color-hover: adjust-color($base-color, $lightness: -4.5%);
$border-bottom: adjust-color($base-color, $hue: 8, $saturation: 13.5%, $lightness: -32%);
$border-sides: adjust-color($base-color, $hue: 4, $saturation: -2%, $lightness: -27%);
$border-top: adjust-color($base-color, $hue: -1, $saturation: -17%, $lightness: -21%);
$inset-shadow-hover: adjust-color($base-color, $saturation: -1%, $lightness: 3%);
$stop-gradient-hover: adjust-color($base-color, $hue: 8, $saturation: -4%, $lightness: -15.5%);
$text-shadow-hover: adjust-color($base-color, $hue: 5, $saturation: -5%, $lightness: -22%);
@if $grayscale == true {
$base-color-hover: grayscale($base-color-hover);
$border-bottom: grayscale($border-bottom);
$border-sides: grayscale($border-sides);
$border-top: grayscale($border-top);
$inset-shadow-hover: grayscale($inset-shadow-hover);
$stop-gradient-hover: grayscale($stop-gradient-hover);
$text-shadow-hover: grayscale($text-shadow-hover);
}
@include linear-gradient ($base-color-hover, $stop-gradient-hover);
background-clip: padding-box;
border: 1px solid $border-top;
border-color: $border-top $border-sides $border-bottom;
box-shadow: inset 0 1px 0 0 $inset-shadow-hover;
cursor: pointer;
text-shadow: 0 -1px 1px $text-shadow-hover;
}
&:active:not(:disabled),
&:focus:not(:disabled) {
$active-color: adjust-color($base-color, $hue: 4, $saturation: -12%, $lightness: -10%);
$border-active: adjust-color($base-color, $hue: 6, $saturation: -2.5%, $lightness: -30%);
$border-bottom-active: adjust-color($base-color, $hue: 11, $saturation: 6%, $lightness: -31%);
$inset-shadow-active: adjust-color($base-color, $hue: 9, $saturation: 2%, $lightness: -21.5%);
$text-shadow-active: adjust-color($base-color, $hue: 5, $saturation: -12%, $lightness: -21.5%);
@if $grayscale == true {
$active-color: grayscale($active-color);
$border-active: grayscale($border-active);
$border-bottom-active: grayscale($border-bottom-active);
$inset-shadow-active: grayscale($inset-shadow-active);
$text-shadow-active: grayscale($text-shadow-active);
}
background: $active-color;
border: 1px solid $border-active;
border-bottom: 1px solid $border-bottom-active;
box-shadow: inset 0 0 6px 3px $inset-shadow-active;
text-shadow: 0 -1px 1px $text-shadow-active;
}
}
// Flat Button
@mixin flat($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) {
$color: hsl(0, 0, 100%);
@if is-light($base-color) {
$color: hsl(0, 0, 20%);
}
background-color: $base-color;
border-radius: 3px;
border: 0;
color: $color;
display: inline-block;
font-size: $textsize;
font-weight: bold;
padding: $padding;
text-decoration: none;
background-clip: padding-box;
&:hover:not(:disabled){
$base-color-hover: adjust-color($base-color, $saturation: 4%, $lightness: 5%);
@if $grayscale == true {
$base-color-hover: grayscale($base-color-hover);
}
background-color: $base-color-hover;
cursor: pointer;
}
&:active:not(:disabled),
&:focus:not(:disabled) {
$base-color-active: adjust-color($base-color, $saturation: -4%, $lightness: -5%);
@if $grayscale == true {
$base-color-active: grayscale($base-color-active);
}
background-color: $base-color-active;
cursor: pointer;
}
}
// Flexible grid
@function flex-grid($columns, $container-columns: $fg-max-columns) {
$width: $columns * $fg-column + ($columns - 1) * $fg-gutter;
$container-width: $container-columns * $fg-column + ($container-columns - 1) * $fg-gutter;
@return percentage($width / $container-width);
@warn "The flex-grid function is deprecated and will be removed in the next major version release";
}
// Flexible gutter
@function flex-gutter($container-columns: $fg-max-columns, $gutter: $fg-gutter) {
$container-width: $container-columns * $fg-column + ($container-columns - 1) * $fg-gutter;
@return percentage($gutter / $container-width);
@warn "The flex-gutter function is deprecated and will be removed in the next major version release";
}
@function grid-width($n) {
@return $n * $gw-column + ($n - 1) * $gw-gutter;
@warn "The grid-width function is deprecated and will be removed in the next major version release";
}
@function golden-ratio($value, $increment) {
@return modular-scale($increment, $value, $ratio: $golden);
@warn "The golden-ratio function is deprecated and will be removed in the next major version release. Please use the modular-scale function, instead.";
}
@mixin box-sizing($box) {
@include prefixer(box-sizing, $box, webkit moz spec);
@warn "The box-sizing mixin is deprecated and will be removed in the next major version release. This property can now be used un-prefixed.";
}
+87
View File
@@ -0,0 +1,87 @@
// Bourbon 4.2.6
// http://bourbon.io
// Copyright 2011-2015 thoughtbot, inc.
// MIT License
@import "settings/prefixer";
@import "settings/px-to-em";
@import "settings/asset-pipeline";
@import "functions/assign-inputs";
@import "functions/contains";
@import "functions/contains-falsy";
@import "functions/is-length";
@import "functions/is-light";
@import "functions/is-number";
@import "functions/is-size";
@import "functions/px-to-em";
@import "functions/px-to-rem";
@import "functions/shade";
@import "functions/strip-units";
@import "functions/tint";
@import "functions/transition-property-name";
@import "functions/unpack";
@import "functions/modular-scale";
@import "helpers/convert-units";
@import "helpers/directional-values";
@import "helpers/font-source-declaration";
@import "helpers/gradient-positions-parser";
@import "helpers/linear-angle-parser";
@import "helpers/linear-gradient-parser";
@import "helpers/linear-positions-parser";
@import "helpers/linear-side-corner-parser";
@import "helpers/radial-arg-parser";
@import "helpers/radial-positions-parser";
@import "helpers/radial-gradient-parser";
@import "helpers/render-gradients";
@import "helpers/shape-size-stripper";
@import "helpers/str-to-num";
@import "css3/animation";
@import "css3/appearance";
@import "css3/backface-visibility";
@import "css3/background";
@import "css3/background-image";
@import "css3/border-image";
@import "css3/calc";
@import "css3/columns";
@import "css3/filter";
@import "css3/flex-box";
@import "css3/font-face";
@import "css3/font-feature-settings";
@import "css3/hidpi-media-query";
@import "css3/hyphens";
@import "css3/image-rendering";
@import "css3/keyframes";
@import "css3/linear-gradient";
@import "css3/perspective";
@import "css3/placeholder";
@import "css3/radial-gradient";
@import "css3/selection";
@import "css3/text-decoration";
@import "css3/transform";
@import "css3/transition";
@import "css3/user-select";
@import "addons/border-color";
@import "addons/border-radius";
@import "addons/border-style";
@import "addons/border-width";
@import "addons/buttons";
@import "addons/clearfix";
@import "addons/ellipsis";
@import "addons/font-stacks";
@import "addons/hide-text";
@import "addons/margin";
@import "addons/padding";
@import "addons/position";
@import "addons/prefixer";
@import "addons/retina-image";
@import "addons/size";
@import "addons/text-inputs";
@import "addons/timing-functions";
@import "addons/triangle";
@import "addons/word-wrap";
@import "bourbon-deprecated-upcoming";
+26
View File
@@ -0,0 +1,26 @@
@charset "UTF-8";
/// Provides a quick method for targeting `border-color` on specific sides of a box. Use a `null` value to “skip” a side.
///
/// @param {Arglist} $vals
/// List of arguments
///
/// @example scss - Usage
/// .element {
/// @include border-color(#a60b55 #76cd9c null #e8ae1a);
/// }
///
/// @example css - CSS Output
/// .element {
/// border-left-color: #e8ae1a;
/// border-right-color: #76cd9c;
/// border-top-color: #a60b55;
/// }
///
/// @require {mixin} directional-property
///
/// @output `border-color`
@mixin border-color($vals...) {
@include directional-property(border, color, $vals...);
}
+48
View File
@@ -0,0 +1,48 @@
@charset "UTF-8";
/// Provides a quick method for targeting `border-radius` on both corners on the side of a box.
///
/// @param {Number} $radii
/// List of arguments
///
/// @example scss - Usage
/// .element-one {
/// @include border-top-radius(5px);
/// }
///
/// .element-two {
/// @include border-left-radius(3px);
/// }
///
/// @example css - CSS Output
/// .element-one {
/// border-top-left-radius: 5px;
/// border-top-right-radius: 5px;
/// }
///
/// .element-two {
/// border-bottom-left-radius: 3px;
/// border-top-left-radius: 3px;
/// }
///
/// @output `border-radius`
@mixin border-top-radius($radii) {
border-top-left-radius: $radii;
border-top-right-radius: $radii;
}
@mixin border-right-radius($radii) {
border-bottom-right-radius: $radii;
border-top-right-radius: $radii;
}
@mixin border-bottom-radius($radii) {
border-bottom-left-radius: $radii;
border-bottom-right-radius: $radii;
}
@mixin border-left-radius($radii) {
border-bottom-left-radius: $radii;
border-top-left-radius: $radii;
}
+25
View File
@@ -0,0 +1,25 @@
@charset "UTF-8";
/// Provides a quick method for targeting `border-style` on specific sides of a box. Use a `null` value to “skip” a side.
///
/// @param {Arglist} $vals
/// List of arguments
///
/// @example scss - Usage
/// .element {
/// @include border-style(dashed null solid);
/// }
///
/// @example css - CSS Output
/// .element {
/// border-bottom-style: solid;
/// border-top-style: dashed;
/// }
///
/// @require {mixin} directional-property
///
/// @output `border-style`
@mixin border-style($vals...) {
@include directional-property(border, style, $vals...);
}
+25
View File
@@ -0,0 +1,25 @@
@charset "UTF-8";
/// Provides a quick method for targeting `border-width` on specific sides of a box. Use a `null` value to “skip” a side.
///
/// @param {Arglist} $vals
/// List of arguments
///
/// @example scss - Usage
/// .element {
/// @include border-width(1em null 20px);
/// }
///
/// @example css - CSS Output
/// .element {
/// border-bottom-width: 20px;
/// border-top-width: 1em;
/// }
///
/// @require {mixin} directional-property
///
/// @output `border-width`
@mixin border-width($vals...) {
@include directional-property(border, width, $vals...);
}
+64
View File
@@ -0,0 +1,64 @@
@charset "UTF-8";
/// Generates variables for all buttons. Please note that you must use interpolation on the variable: `#{$all-buttons}`.
///
/// @example scss - Usage
/// #{$all-buttons} {
/// background-color: #f00;
/// }
///
/// #{$all-buttons-focus},
/// #{$all-buttons-hover} {
/// background-color: #0f0;
/// }
///
/// #{$all-buttons-active} {
/// background-color: #00f;
/// }
///
/// @example css - CSS Output
/// button,
/// input[type="button"],
/// input[type="reset"],
/// input[type="submit"] {
/// background-color: #f00;
/// }
///
/// button:focus,
/// input[type="button"]:focus,
/// input[type="reset"]:focus,
/// input[type="submit"]:focus,
/// button:hover,
/// input[type="button"]:hover,
/// input[type="reset"]:hover,
/// input[type="submit"]:hover {
/// background-color: #0f0;
/// }
///
/// button:active,
/// input[type="button"]:active,
/// input[type="reset"]:active,
/// input[type="submit"]:active {
/// background-color: #00f;
/// }
///
/// @require assign-inputs
///
/// @type List
///
/// @todo Remove double assigned variables (Lines 5962) in v5.0.0
$buttons-list: 'button',
'input[type="button"]',
'input[type="reset"]',
'input[type="submit"]';
$all-buttons: assign-inputs($buttons-list);
$all-buttons-active: assign-inputs($buttons-list, active);
$all-buttons-focus: assign-inputs($buttons-list, focus);
$all-buttons-hover: assign-inputs($buttons-list, hover);
$all-button-inputs: $all-buttons;
$all-button-inputs-active: $all-buttons-active;
$all-button-inputs-focus: $all-buttons-focus;
$all-button-inputs-hover: $all-buttons-hover;
+25
View File
@@ -0,0 +1,25 @@
@charset "UTF-8";
/// Provides an easy way to include a clearfix for containing floats.
///
/// @link http://cssmojo.com/latest_new_clearfix_so_far/
///
/// @example scss - Usage
/// .element {
/// @include clearfix;
/// }
///
/// @example css - CSS Output
/// .element::after {
/// clear: both;
/// content: "";
/// display: table;
/// }
@mixin clearfix {
&::after {
clear: both;
content: "";
display: table;
}
}
+30
View File
@@ -0,0 +1,30 @@
@charset "UTF-8";
/// Truncates text and adds an ellipsis to represent overflow.
///
/// @param {Number} $width [100%]
/// Max-width for the string to respect before being truncated
///
/// @example scss - Usage
/// .element {
/// @include ellipsis;
/// }
///
/// @example css - CSS Output
/// .element {
/// display: inline-block;
/// max-width: 100%;
/// overflow: hidden;
/// text-overflow: ellipsis;
/// white-space: nowrap;
/// word-wrap: normal;
/// }
@mixin ellipsis($width: 100%) {
display: inline-block;
max-width: $width;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
word-wrap: normal;
}
+31
View File
@@ -0,0 +1,31 @@
@charset "UTF-8";
/// Georgia font stack.
///
/// @type List
$georgia: "Georgia", "Cambria", "Times New Roman", "Times", serif;
/// Helvetica font stack.
///
/// @type List
$helvetica: "Helvetica Neue", "Helvetica", "Roboto", "Arial", sans-serif;
/// Lucida Grande font stack.
///
/// @type List
$lucida-grande: "Lucida Grande", "Tahoma", "Verdana", "Arial", sans-serif;
/// Monospace font stack.
///
/// @type List
$monospace: "Bitstream Vera Sans Mono", "Consolas", "Courier", monospace;
/// Verdana font stack.
///
/// @type List
$verdana: "Verdana", "Geneva", sans-serif;
+27
View File
@@ -0,0 +1,27 @@
/// Hides the text in an element, commonly used to show an image. Some elements will need block-level styles applied.
///
/// @link http://zeldman.com/2012/03/01/replacing-the-9999px-hack-new-image-replacement
///
/// @example scss - Usage
/// .element {
/// @include hide-text;
/// }
///
/// @example css - CSS Output
/// .element {
/// overflow: hidden;
/// text-indent: 101%;
/// white-space: nowrap;
/// }
///
/// @todo Remove height argument in v5.0.0
@mixin hide-text($height: null) {
overflow: hidden;
text-indent: 101%;
white-space: nowrap;
@if $height {
@warn "The `hide-text` mixin has changed and no longer requires a height. The height argument will no longer be accepted in v5.0.0";
}
}
+26
View File
@@ -0,0 +1,26 @@
@charset "UTF-8";
/// Provides a quick method for targeting `margin` on specific sides of a box. Use a `null` value to “skip” a side.
///
/// @param {Arglist} $vals
/// List of arguments
///
/// @example scss - Usage
/// .element {
/// @include margin(null 10px 3em 20vh);
/// }
///
/// @example css - CSS Output
/// .element {
/// margin-bottom: 3em;
/// margin-left: 20vh;
/// margin-right: 10px;
/// }
///
/// @require {mixin} directional-property
///
/// @output `margin`
@mixin margin($vals...) {
@include directional-property(margin, false, $vals...);
}
+26
View File
@@ -0,0 +1,26 @@
@charset "UTF-8";
/// Provides a quick method for targeting `padding` on specific sides of a box. Use a `null` value to “skip” a side.
///
/// @param {Arglist} $vals
/// List of arguments
///
/// @example scss - Usage
/// .element {
/// @include padding(12vh null 10px 5%);
/// }
///
/// @example css - CSS Output
/// .element {
/// padding-bottom: 10px;
/// padding-left: 5%;
/// padding-top: 12vh;
/// }
///
/// @require {mixin} directional-property
///
/// @output `padding`
@mixin padding($vals...) {
@include directional-property(padding, false, $vals...);
}
+48
View File
@@ -0,0 +1,48 @@
@charset "UTF-8";
/// Provides a quick method for setting an elements position. Use a `null` value to “skip” a side.
///
/// @param {Position} $position [relative]
/// A CSS position value
///
/// @param {Arglist} $coordinates [null null null null]
/// List of values that correspond to the 4-value syntax for the edges of a box
///
/// @example scss - Usage
/// .element {
/// @include position(absolute, 0 null null 10em);
/// }
///
/// @example css - CSS Output
/// .element {
/// left: 10em;
/// position: absolute;
/// top: 0;
/// }
///
/// @require {function} is-length
/// @require {function} unpack
@mixin position($position: relative, $coordinates: null null null null) {
@if type-of($position) == list {
$coordinates: $position;
$position: relative;
}
$coordinates: unpack($coordinates);
$offsets: (
top: nth($coordinates, 1),
right: nth($coordinates, 2),
bottom: nth($coordinates, 3),
left: nth($coordinates, 4)
);
position: $position;
@each $offset, $value in $offsets {
@if is-length($value) {
#{$offset}: $value;
}
}
}
+66
View File
@@ -0,0 +1,66 @@
@charset "UTF-8";
/// A mixin for generating vendor prefixes on non-standardized properties.
///
/// @param {String} $property
/// Property to prefix
///
/// @param {*} $value
/// Value to use
///
/// @param {List} $prefixes
/// Prefixes to define
///
/// @example scss - Usage
/// .element {
/// @include prefixer(border-radius, 10px, webkit ms spec);
/// }
///
/// @example css - CSS Output
/// .element {
/// -webkit-border-radius: 10px;
/// -moz-border-radius: 10px;
/// border-radius: 10px;
/// }
///
/// @require {variable} $prefix-for-webkit
/// @require {variable} $prefix-for-mozilla
/// @require {variable} $prefix-for-microsoft
/// @require {variable} $prefix-for-opera
/// @require {variable} $prefix-for-spec
@mixin prefixer($property, $value, $prefixes) {
@each $prefix in $prefixes {
@if $prefix == webkit {
@if $prefix-for-webkit {
-webkit-#{$property}: $value;
}
} @else if $prefix == moz {
@if $prefix-for-mozilla {
-moz-#{$property}: $value;
}
} @else if $prefix == ms {
@if $prefix-for-microsoft {
-ms-#{$property}: $value;
}
} @else if $prefix == o {
@if $prefix-for-opera {
-o-#{$property}: $value;
}
} @else if $prefix == spec {
@if $prefix-for-spec {
#{$property}: $value;
}
} @else {
@warn "Unrecognized prefix: #{$prefix}";
}
}
}
@mixin disable-prefix-for-all() {
$prefix-for-webkit: false !global;
$prefix-for-mozilla: false !global;
$prefix-for-microsoft: false !global;
$prefix-for-opera: false !global;
$prefix-for-spec: false !global;
}
+25
View File
@@ -0,0 +1,25 @@
@mixin retina-image($filename, $background-size, $extension: png, $retina-filename: null, $retina-suffix: _2x, $asset-pipeline: $asset-pipeline) {
@if $asset-pipeline {
background-image: image-url("#{$filename}.#{$extension}");
} @else {
background-image: url("#{$filename}.#{$extension}");
}
@include hidpi {
@if $asset-pipeline {
@if $retina-filename {
background-image: image-url("#{$retina-filename}.#{$extension}");
} @else {
background-image: image-url("#{$filename}#{$retina-suffix}.#{$extension}");
}
} @else {
@if $retina-filename {
background-image: url("#{$retina-filename}.#{$extension}");
} @else {
background-image: url("#{$filename}#{$retina-suffix}.#{$extension}");
}
}
background-size: $background-size;
}
}
+51
View File
@@ -0,0 +1,51 @@
@charset "UTF-8";
/// Sets the `width` and `height` of the element.
///
/// @param {List} $size
/// A list of at most 2 size values.
///
/// If there is only a single value in `$size` it is used for both width and height. All units are supported.
///
/// @example scss - Usage
/// .first-element {
/// @include size(2em);
/// }
///
/// .second-element {
/// @include size(auto 10em);
/// }
///
/// @example css - CSS Output
/// .first-element {
/// width: 2em;
/// height: 2em;
/// }
///
/// .second-element {
/// width: auto;
/// height: 10em;
/// }
///
/// @todo Refactor in 5.0.0 to use a comma-separated argument
@mixin size($value) {
$width: nth($value, 1);
$height: $width;
@if length($value) > 1 {
$height: nth($value, 2);
}
@if is-size($height) {
height: $height;
} @else {
@warn "`#{$height}` is not a valid length for the `$height` parameter in the `size` mixin.";
}
@if is-size($width) {
width: $width;
} @else {
@warn "`#{$width}` is not a valid length for the `$width` parameter in the `size` mixin.";
}
}
+113
View File
@@ -0,0 +1,113 @@
@charset "UTF-8";
/// Generates variables for all text-based inputs. Please note that you must use interpolation on the variable: `#{$all-text-inputs}`.
///
/// @example scss - Usage
/// #{$all-text-inputs} {
/// border: 1px solid #f00;
/// }
///
/// #{$all-text-inputs-focus},
/// #{$all-text-inputs-hover} {
/// border: 1px solid #0f0;
/// }
///
/// #{$all-text-inputs-active} {
/// border: 1px solid #00f;
/// }
///
/// @example css - CSS Output
/// input[type="color"],
/// input[type="date"],
/// input[type="datetime"],
/// input[type="datetime-local"],
/// input[type="email"],
/// input[type="month"],
/// input[type="number"],
/// input[type="password"],
/// input[type="search"],
/// input[type="tel"],
/// input[type="text"],
/// input[type="time"],
/// input[type="url"],
/// input[type="week"],
/// textarea {
/// border: 1px solid #f00;
/// }
///
/// input[type="color"]:focus,
/// input[type="date"]:focus,
/// input[type="datetime"]:focus,
/// input[type="datetime-local"]:focus,
/// input[type="email"]:focus,
/// input[type="month"]:focus,
/// input[type="number"]:focus,
/// input[type="password"]:focus,
/// input[type="search"]:focus,
/// input[type="tel"]:focus,
/// input[type="text"]:focus,
/// input[type="time"]:focus,
/// input[type="url"]:focus,
/// input[type="week"]:focus,
/// textarea:focus,
/// input[type="color"]:hover,
/// input[type="date"]:hover,
/// input[type="datetime"]:hover,
/// input[type="datetime-local"]:hover,
/// input[type="email"]:hover,
/// input[type="month"]:hover,
/// input[type="number"]:hover,
/// input[type="password"]:hover,
/// input[type="search"]:hover,
/// input[type="tel"]:hover,
/// input[type="text"]:hover,
/// input[type="time"]:hover,
/// input[type="url"]:hover,
/// input[type="week"]:hover,
/// textarea:hover {
/// border: 1px solid #0f0;
/// }
///
/// input[type="color"]:active,
/// input[type="date"]:active,
/// input[type="datetime"]:active,
/// input[type="datetime-local"]:active,
/// input[type="email"]:active,
/// input[type="month"]:active,
/// input[type="number"]:active,
/// input[type="password"]:active,
/// input[type="search"]:active,
/// input[type="tel"]:active,
/// input[type="text"]:active,
/// input[type="time"]:active,
/// input[type="url"]:active,
/// input[type="week"]:active,
/// textarea:active {
/// border: 1px solid #00f;
/// }
///
/// @require assign-inputs
///
/// @type List
$text-inputs-list: //'input[type="color"]',
//'input[type="date"]',
//'input[type="datetime"]',
//'input[type="datetime-local"]',
//'input[type="email"]',
//'input[type="month"]',
'input[type="number"]',
'input[type="password"]',
//'input[type="search"]',
//'input[type="tel"]',
'input[type="text"]',
//'input[type="time"]',
//'input[type="url"]',
//'input[type="week"]',
//'input:not([type])',
'textarea';
$all-text-inputs: assign-inputs($text-inputs-list);
$all-text-inputs-active: assign-inputs($text-inputs-list, active);
$all-text-inputs-focus: assign-inputs($text-inputs-list, focus);
$all-text-inputs-hover: assign-inputs($text-inputs-list, hover);
+34
View File
@@ -0,0 +1,34 @@
@charset "UTF-8";
/// CSS cubic-bezier timing functions. Timing functions courtesy of jquery.easie (github.com/jaukia/easie)
///
/// Timing functions are the same as demoed here: http://jqueryui.com/resources/demos/effect/easing.html
///
/// @type cubic-bezier
$ease-in-quad: cubic-bezier(0.550, 0.085, 0.680, 0.530);
$ease-in-cubic: cubic-bezier(0.550, 0.055, 0.675, 0.190);
$ease-in-quart: cubic-bezier(0.895, 0.030, 0.685, 0.220);
$ease-in-quint: cubic-bezier(0.755, 0.050, 0.855, 0.060);
$ease-in-sine: cubic-bezier(0.470, 0.000, 0.745, 0.715);
$ease-in-expo: cubic-bezier(0.950, 0.050, 0.795, 0.035);
$ease-in-circ: cubic-bezier(0.600, 0.040, 0.980, 0.335);
$ease-in-back: cubic-bezier(0.600, -0.280, 0.735, 0.045);
$ease-out-quad: cubic-bezier(0.250, 0.460, 0.450, 0.940);
$ease-out-cubic: cubic-bezier(0.215, 0.610, 0.355, 1.000);
$ease-out-quart: cubic-bezier(0.165, 0.840, 0.440, 1.000);
$ease-out-quint: cubic-bezier(0.230, 1.000, 0.320, 1.000);
$ease-out-sine: cubic-bezier(0.390, 0.575, 0.565, 1.000);
$ease-out-expo: cubic-bezier(0.190, 1.000, 0.220, 1.000);
$ease-out-circ: cubic-bezier(0.075, 0.820, 0.165, 1.000);
$ease-out-back: cubic-bezier(0.175, 0.885, 0.320, 1.275);
$ease-in-out-quad: cubic-bezier(0.455, 0.030, 0.515, 0.955);
$ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1.000);
$ease-in-out-quart: cubic-bezier(0.770, 0.000, 0.175, 1.000);
$ease-in-out-quint: cubic-bezier(0.860, 0.000, 0.070, 1.000);
$ease-in-out-sine: cubic-bezier(0.445, 0.050, 0.550, 0.950);
$ease-in-out-expo: cubic-bezier(1.000, 0.000, 0.000, 1.000);
$ease-in-out-circ: cubic-bezier(0.785, 0.135, 0.150, 0.860);
$ease-in-out-back: cubic-bezier(0.680, -0.550, 0.265, 1.550);
+63
View File
@@ -0,0 +1,63 @@
@mixin triangle($size, $color, $direction) {
$width: nth($size, 1);
$height: nth($size, length($size));
$foreground-color: nth($color, 1);
$background-color: if(length($color) == 2, nth($color, 2), transparent);
height: 0;
width: 0;
@if ($direction == up) or ($direction == down) or ($direction == right) or ($direction == left) {
$width: $width / 2;
$height: if(length($size) > 1, $height, $height/2);
@if $direction == up {
border-bottom: $height solid $foreground-color;
border-left: $width solid $background-color;
border-right: $width solid $background-color;
} @else if $direction == right {
border-bottom: $width solid $background-color;
border-left: $height solid $foreground-color;
border-top: $width solid $background-color;
} @else if $direction == down {
border-left: $width solid $background-color;
border-right: $width solid $background-color;
border-top: $height solid $foreground-color;
} @else if $direction == left {
border-bottom: $width solid $background-color;
border-right: $height solid $foreground-color;
border-top: $width solid $background-color;
}
} @else if ($direction == up-right) or ($direction == up-left) {
border-top: $height solid $foreground-color;
@if $direction == up-right {
border-left: $width solid $background-color;
} @else if $direction == up-left {
border-right: $width solid $background-color;
}
} @else if ($direction == down-right) or ($direction == down-left) {
border-bottom: $height solid $foreground-color;
@if $direction == down-right {
border-left: $width solid $background-color;
} @else if $direction == down-left {
border-right: $width solid $background-color;
}
} @else if ($direction == inset-up) {
border-color: $background-color $background-color $foreground-color;
border-style: solid;
border-width: $height $width;
} @else if ($direction == inset-down) {
border-color: $foreground-color $background-color $background-color;
border-style: solid;
border-width: $height $width;
} @else if ($direction == inset-right) {
border-color: $background-color $background-color $background-color $foreground-color;
border-style: solid;
border-width: $width $height;
} @else if ($direction == inset-left) {
border-color: $background-color $foreground-color $background-color $background-color;
border-style: solid;
border-width: $width $height;
}
}
+29
View File
@@ -0,0 +1,29 @@
@charset "UTF-8";
/// Provides an easy way to change the `word-wrap` property.
///
/// @param {String} $wrap [break-word]
/// Value for the `word-break` property.
///
/// @example scss - Usage
/// .wrapper {
/// @include word-wrap(break-word);
/// }
///
/// @example css - CSS Output
/// .wrapper {
/// overflow-wrap: break-word;
/// word-break: break-all;
/// word-wrap: break-word;
/// }
@mixin word-wrap($wrap: break-word) {
overflow-wrap: $wrap;
word-wrap: $wrap;
@if $wrap == break-word {
word-break: break-all;
} @else {
word-break: $wrap;
}
}
+43
View File
@@ -0,0 +1,43 @@
// http://www.w3.org/TR/css3-animations/#the-animation-name-property-
// Each of these mixins support comma separated lists of values, which allows different transitions for individual properties to be described in a single style rule. Each value in the list corresponds to the value at that same position in the other properties.
@mixin animation($animations...) {
@include prefixer(animation, $animations, webkit moz spec);
}
@mixin animation-name($names...) {
@include prefixer(animation-name, $names, webkit moz spec);
}
@mixin animation-duration($times...) {
@include prefixer(animation-duration, $times, webkit moz spec);
}
@mixin animation-timing-function($motions...) {
// ease | linear | ease-in | ease-out | ease-in-out
@include prefixer(animation-timing-function, $motions, webkit moz spec);
}
@mixin animation-iteration-count($values...) {
// infinite | <number>
@include prefixer(animation-iteration-count, $values, webkit moz spec);
}
@mixin animation-direction($directions...) {
// normal | alternate
@include prefixer(animation-direction, $directions, webkit moz spec);
}
@mixin animation-play-state($states...) {
// running | paused
@include prefixer(animation-play-state, $states, webkit moz spec);
}
@mixin animation-delay($times...) {
@include prefixer(animation-delay, $times, webkit moz spec);
}
@mixin animation-fill-mode($modes...) {
// none | forwards | backwards | both
@include prefixer(animation-fill-mode, $modes, webkit moz spec);
}
+3
View File
@@ -0,0 +1,3 @@
@mixin appearance($value) {
@include prefixer(appearance, $value, webkit moz ms o spec);
}
+3
View File
@@ -0,0 +1,3 @@
@mixin backface-visibility($visibility) {
@include prefixer(backface-visibility, $visibility, webkit spec);
}
+42
View File
@@ -0,0 +1,42 @@
//************************************************************************//
// Background-image property for adding multiple background images with
// gradients, or for stringing multiple gradients together.
//************************************************************************//
@mixin background-image($images...) {
$webkit-images: ();
$spec-images: ();
@each $image in $images {
$webkit-image: ();
$spec-image: ();
@if (type-of($image) == string) {
$url-str: str-slice($image, 1, 3);
$gradient-type: str-slice($image, 1, 6);
@if $url-str == "url" {
$webkit-image: $image;
$spec-image: $image;
}
@else if $gradient-type == "linear" {
$gradients: _linear-gradient-parser($image);
$webkit-image: map-get($gradients, webkit-image);
$spec-image: map-get($gradients, spec-image);
}
@else if $gradient-type == "radial" {
$gradients: _radial-gradient-parser($image);
$webkit-image: map-get($gradients, webkit-image);
$spec-image: map-get($gradients, spec-image);
}
}
$webkit-images: append($webkit-images, $webkit-image, comma);
$spec-images: append($spec-images, $spec-image, comma);
}
background-image: $webkit-images;
background-image: $spec-images;
}
+55
View File
@@ -0,0 +1,55 @@
//************************************************************************//
// Background property for adding multiple backgrounds using shorthand
// notation.
//************************************************************************//
@mixin background($backgrounds...) {
$webkit-backgrounds: ();
$spec-backgrounds: ();
@each $background in $backgrounds {
$webkit-background: ();
$spec-background: ();
$background-type: type-of($background);
@if $background-type == string or $background-type == list {
$background-str: if($background-type == list, nth($background, 1), $background);
$url-str: str-slice($background-str, 1, 3);
$gradient-type: str-slice($background-str, 1, 6);
@if $url-str == "url" {
$webkit-background: $background;
$spec-background: $background;
}
@else if $gradient-type == "linear" {
$gradients: _linear-gradient-parser("#{$background}");
$webkit-background: map-get($gradients, webkit-image);
$spec-background: map-get($gradients, spec-image);
}
@else if $gradient-type == "radial" {
$gradients: _radial-gradient-parser("#{$background}");
$webkit-background: map-get($gradients, webkit-image);
$spec-background: map-get($gradients, spec-image);
}
@else {
$webkit-background: $background;
$spec-background: $background;
}
}
@else {
$webkit-background: $background;
$spec-background: $background;
}
$webkit-backgrounds: append($webkit-backgrounds, $webkit-background, comma);
$spec-backgrounds: append($spec-backgrounds, $spec-background, comma);
}
background: $webkit-backgrounds;
background: $spec-backgrounds;
}
+59
View File
@@ -0,0 +1,59 @@
@mixin border-image($borders...) {
$webkit-borders: ();
$spec-borders: ();
@each $border in $borders {
$webkit-border: ();
$spec-border: ();
$border-type: type-of($border);
@if $border-type == string or list {
$border-str: if($border-type == list, nth($border, 1), $border);
$url-str: str-slice($border-str, 1, 3);
$gradient-type: str-slice($border-str, 1, 6);
@if $url-str == "url" {
$webkit-border: $border;
$spec-border: $border;
}
@else if $gradient-type == "linear" {
$gradients: _linear-gradient-parser("#{$border}");
$webkit-border: map-get($gradients, webkit-image);
$spec-border: map-get($gradients, spec-image);
}
@else if $gradient-type == "radial" {
$gradients: _radial-gradient-parser("#{$border}");
$webkit-border: map-get($gradients, webkit-image);
$spec-border: map-get($gradients, spec-image);
}
@else {
$webkit-border: $border;
$spec-border: $border;
}
}
@else {
$webkit-border: $border;
$spec-border: $border;
}
$webkit-borders: append($webkit-borders, $webkit-border, comma);
$spec-borders: append($spec-borders, $spec-border, comma);
}
-webkit-border-image: $webkit-borders;
border-image: $spec-borders;
border-style: solid;
}
//Examples:
// @include border-image(url("image.png"));
// @include border-image(url("image.png") 20 stretch);
// @include border-image(linear-gradient(45deg, orange, yellow));
// @include border-image(linear-gradient(45deg, orange, yellow) stretch);
// @include border-image(linear-gradient(45deg, orange, yellow) 20 30 40 50 stretch round);
// @include border-image(radial-gradient(top, cover, orange, yellow, orange));
+4
View File
@@ -0,0 +1,4 @@
@mixin calc($property, $value) {
#{$property}: -webkit-calc(#{$value});
#{$property}: calc(#{$value});
}
+47
View File
@@ -0,0 +1,47 @@
@mixin columns($arg: auto) {
// <column-count> || <column-width>
@include prefixer(columns, $arg, webkit moz spec);
}
@mixin column-count($int: auto) {
// auto || integer
@include prefixer(column-count, $int, webkit moz spec);
}
@mixin column-gap($length: normal) {
// normal || length
@include prefixer(column-gap, $length, webkit moz spec);
}
@mixin column-fill($arg: auto) {
// auto || length
@include prefixer(column-fill, $arg, webkit moz spec);
}
@mixin column-rule($arg) {
// <border-width> || <border-style> || <color>
@include prefixer(column-rule, $arg, webkit moz spec);
}
@mixin column-rule-color($color) {
@include prefixer(column-rule-color, $color, webkit moz spec);
}
@mixin column-rule-style($style: none) {
// none | hidden | dashed | dotted | double | groove | inset | inset | outset | ridge | solid
@include prefixer(column-rule-style, $style, webkit moz spec);
}
@mixin column-rule-width ($width: none) {
@include prefixer(column-rule-width, $width, webkit moz spec);
}
@mixin column-span($arg: none) {
// none || all
@include prefixer(column-span, $arg, webkit moz spec);
}
@mixin column-width($length: auto) {
// auto || length
@include prefixer(column-width, $length, webkit moz spec);
}
+4
View File
@@ -0,0 +1,4 @@
@mixin filter($function: none) {
// <filter-function> [<filter-function]* | none
@include prefixer(filter, $function, webkit spec);
}
+287
View File
@@ -0,0 +1,287 @@
// CSS3 Flexible Box Model and property defaults
// Custom shorthand notation for flexbox
@mixin box($orient: inline-axis, $pack: start, $align: stretch) {
@include display-box;
@include box-orient($orient);
@include box-pack($pack);
@include box-align($align);
}
@mixin display-box {
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox; // IE 10
display: box;
}
@mixin box-orient($orient: inline-axis) {
// horizontal|vertical|inline-axis|block-axis|inherit
@include prefixer(box-orient, $orient, webkit moz spec);
}
@mixin box-pack($pack: start) {
// start|end|center|justify
@include prefixer(box-pack, $pack, webkit moz spec);
-ms-flex-pack: $pack; // IE 10
}
@mixin box-align($align: stretch) {
// start|end|center|baseline|stretch
@include prefixer(box-align, $align, webkit moz spec);
-ms-flex-align: $align; // IE 10
}
@mixin box-direction($direction: normal) {
// normal|reverse|inherit
@include prefixer(box-direction, $direction, webkit moz spec);
-ms-flex-direction: $direction; // IE 10
}
@mixin box-lines($lines: single) {
// single|multiple
@include prefixer(box-lines, $lines, webkit moz spec);
}
@mixin box-ordinal-group($int: 1) {
@include prefixer(box-ordinal-group, $int, webkit moz spec);
-ms-flex-order: $int; // IE 10
}
@mixin box-flex($value: 0) {
@include prefixer(box-flex, $value, webkit moz spec);
-ms-flex: $value; // IE 10
}
@mixin box-flex-group($int: 1) {
@include prefixer(box-flex-group, $int, webkit moz spec);
}
// CSS3 Flexible Box Model and property defaults
// Unified attributes for 2009, 2011, and 2012 flavours.
// 2009 - display (box | inline-box)
// 2011 - display (flexbox | inline-flexbox)
// 2012 - display (flex | inline-flex)
@mixin display($value) {
// flex | inline-flex
@if $value == "flex" {
// 2009
display: -webkit-box;
display: -moz-box;
display: box;
// 2012
display: -webkit-flex;
display: -moz-flex;
display: -ms-flexbox; // 2011 (IE 10)
display: flex;
} @else if $value == "inline-flex" {
display: -webkit-inline-box;
display: -moz-inline-box;
display: inline-box;
display: -webkit-inline-flex;
display: -moz-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
} @else {
display: $value;
}
}
// 2009 - box-flex (integer)
// 2011 - flex (decimal | width decimal)
// 2012 - flex (integer integer width)
@mixin flex($value) {
// Grab flex-grow for older browsers.
$flex-grow: nth($value, 1);
// 2009
@include prefixer(box-flex, $flex-grow, webkit moz spec);
// 2011 (IE 10), 2012
@include prefixer(flex, $value, webkit moz ms spec);
}
// 2009 - box-orient ( horizontal | vertical | inline-axis | block-axis)
// - box-direction (normal | reverse)
// 2011 - flex-direction (row | row-reverse | column | column-reverse)
// 2012 - flex-direction (row | row-reverse | column | column-reverse)
@mixin flex-direction($value: row) {
// Alt values.
$value-2009: $value;
$value-2011: $value;
$direction: normal;
@if $value == row {
$value-2009: horizontal;
} @else if $value == "row-reverse" {
$value-2009: horizontal;
$direction: reverse;
} @else if $value == column {
$value-2009: vertical;
} @else if $value == "column-reverse" {
$value-2009: vertical;
$direction: reverse;
}
// 2009
@include prefixer(box-orient, $value-2009, webkit moz spec);
@include prefixer(box-direction, $direction, webkit moz spec);
// 2012
@include prefixer(flex-direction, $value, webkit moz spec);
// 2011 (IE 10)
-ms-flex-direction: $value;
}
// 2009 - box-lines (single | multiple)
// 2011 - flex-wrap (nowrap | wrap | wrap-reverse)
// 2012 - flex-wrap (nowrap | wrap | wrap-reverse)
@mixin flex-wrap($value: nowrap) {
// Alt values
$alt-value: $value;
@if $value == nowrap {
$alt-value: single;
} @else if $value == wrap {
$alt-value: multiple;
} @else if $value == "wrap-reverse" {
$alt-value: multiple;
}
@include prefixer(box-lines, $alt-value, webkit moz spec);
@include prefixer(flex-wrap, $value, webkit moz ms spec);
}
// 2009 - TODO: parse values into flex-direction/flex-wrap
// 2011 - TODO: parse values into flex-direction/flex-wrap
// 2012 - flex-flow (flex-direction || flex-wrap)
@mixin flex-flow($value) {
@include prefixer(flex-flow, $value, webkit moz spec);
}
// 2009 - box-ordinal-group (integer)
// 2011 - flex-order (integer)
// 2012 - order (integer)
@mixin order($int: 0) {
// 2009
@include prefixer(box-ordinal-group, $int, webkit moz spec);
// 2012
@include prefixer(order, $int, webkit moz spec);
// 2011 (IE 10)
-ms-flex-order: $int;
}
// 2012 - flex-grow (number)
@mixin flex-grow($number: 0) {
@include prefixer(flex-grow, $number, webkit moz spec);
-ms-flex-positive: $number;
}
// 2012 - flex-shrink (number)
@mixin flex-shrink($number: 1) {
@include prefixer(flex-shrink, $number, webkit moz spec);
-ms-flex-negative: $number;
}
// 2012 - flex-basis (number)
@mixin flex-basis($width: auto) {
@include prefixer(flex-basis, $width, webkit moz spec);
-ms-flex-preferred-size: $width;
}
// 2009 - box-pack (start | end | center | justify)
// 2011 - flex-pack (start | end | center | justify)
// 2012 - justify-content (flex-start | flex-end | center | space-between | space-around)
@mixin justify-content($value: flex-start) {
// Alt values.
$alt-value: $value;
@if $value == "flex-start" {
$alt-value: start;
} @else if $value == "flex-end" {
$alt-value: end;
} @else if $value == "space-between" {
$alt-value: justify;
} @else if $value == "space-around" {
$alt-value: distribute;
}
// 2009
@include prefixer(box-pack, $alt-value, webkit moz spec);
// 2012
@include prefixer(justify-content, $value, webkit moz ms o spec);
// 2011 (IE 10)
-ms-flex-pack: $alt-value;
}
// 2009 - box-align (start | end | center | baseline | stretch)
// 2011 - flex-align (start | end | center | baseline | stretch)
// 2012 - align-items (flex-start | flex-end | center | baseline | stretch)
@mixin align-items($value: stretch) {
$alt-value: $value;
@if $value == "flex-start" {
$alt-value: start;
} @else if $value == "flex-end" {
$alt-value: end;
}
// 2009
@include prefixer(box-align, $alt-value, webkit moz spec);
// 2012
@include prefixer(align-items, $value, webkit moz ms o spec);
// 2011 (IE 10)
-ms-flex-align: $alt-value;
}
// 2011 - flex-item-align (auto | start | end | center | baseline | stretch)
// 2012 - align-self (auto | flex-start | flex-end | center | baseline | stretch)
@mixin align-self($value: auto) {
$value-2011: $value;
@if $value == "flex-start" {
$value-2011: start;
} @else if $value == "flex-end" {
$value-2011: end;
}
// 2012
@include prefixer(align-self, $value, webkit moz spec);
// 2011 (IE 10)
-ms-flex-item-align: $value-2011;
}
// 2011 - flex-line-pack (start | end | center | justify | distribute | stretch)
// 2012 - align-content (flex-start | flex-end | center | space-between | space-around | stretch)
@mixin align-content($value: stretch) {
$value-2011: $value;
@if $value == "flex-start" {
$value-2011: start;
} @else if $value == "flex-end" {
$value-2011: end;
} @else if $value == "space-between" {
$value-2011: justify;
} @else if $value == "space-around" {
$value-2011: distribute;
}
// 2012
@include prefixer(align-content, $value, webkit moz spec);
// 2011 (IE 10)
-ms-flex-line-pack: $value-2011;
}
+24
View File
@@ -0,0 +1,24 @@
@mixin font-face(
$font-family,
$file-path,
$weight: normal,
$style: normal,
$asset-pipeline: $asset-pipeline,
$file-formats: eot woff2 woff ttf svg) {
$font-url-prefix: font-url-prefixer($asset-pipeline);
@font-face {
font-family: $font-family;
font-style: $style;
font-weight: $weight;
src: font-source-declaration(
$font-family,
$file-path,
$asset-pipeline,
$file-formats,
$font-url-prefix
);
}
}
+4
View File
@@ -0,0 +1,4 @@
@mixin font-feature-settings($settings...) {
@if length($settings) == 0 { $settings: none; }
@include prefixer(font-feature-settings, $settings, webkit moz ms spec);
}
+10
View File
@@ -0,0 +1,10 @@
// HiDPI mixin. Default value set to 1.3 to target Google Nexus 7 (http://bjango.com/articles/min-device-pixel-ratio/)
@mixin hidpi($ratio: 1.3) {
@media only screen and (-webkit-min-device-pixel-ratio: $ratio),
only screen and (min--moz-device-pixel-ratio: $ratio),
only screen and (-o-min-device-pixel-ratio: #{$ratio}/1),
only screen and (min-resolution: round($ratio * 96dpi)),
only screen and (min-resolution: $ratio * 1dppx) {
@content;
}
}
+4
View File
@@ -0,0 +1,4 @@
@mixin hyphens($hyphenation: none) {
// none | manual | auto
@include prefixer(hyphens, $hyphenation, webkit moz ms spec);
}
+14
View File
@@ -0,0 +1,14 @@
@mixin image-rendering ($mode:auto) {
@if ($mode == crisp-edges) {
-ms-interpolation-mode: nearest-neighbor; // IE8+
image-rendering: -moz-crisp-edges;
image-rendering: -o-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
}
@else {
image-rendering: $mode;
}
}
+36
View File
@@ -0,0 +1,36 @@
// Adds keyframes blocks for supported prefixes, removing redundant prefixes in the block's content
@mixin keyframes($name) {
$original-prefix-for-webkit: $prefix-for-webkit;
$original-prefix-for-mozilla: $prefix-for-mozilla;
$original-prefix-for-microsoft: $prefix-for-microsoft;
$original-prefix-for-opera: $prefix-for-opera;
$original-prefix-for-spec: $prefix-for-spec;
@if $original-prefix-for-webkit {
@include disable-prefix-for-all();
$prefix-for-webkit: true !global;
@-webkit-keyframes #{$name} {
@content;
}
}
@if $original-prefix-for-mozilla {
@include disable-prefix-for-all();
$prefix-for-mozilla: true !global;
@-moz-keyframes #{$name} {
@content;
}
}
$prefix-for-webkit: $original-prefix-for-webkit !global;
$prefix-for-mozilla: $original-prefix-for-mozilla !global;
$prefix-for-microsoft: $original-prefix-for-microsoft !global;
$prefix-for-opera: $original-prefix-for-opera !global;
$prefix-for-spec: $original-prefix-for-spec !global;
@if $original-prefix-for-spec {
@keyframes #{$name} {
@content;
}
}
}
+38
View File
@@ -0,0 +1,38 @@
@mixin linear-gradient($pos, $g1, $g2: null,
$g3: null, $g4: null,
$g5: null, $g6: null,
$g7: null, $g8: null,
$g9: null, $g10: null,
$fallback: null) {
// Detect what type of value exists in $pos
$pos-type: type-of(nth($pos, 1));
$pos-spec: null;
$pos-degree: null;
// If $pos is missing from mixin, reassign vars and add default position
@if ($pos-type == color) or (nth($pos, 1) == "transparent") {
$g10: $g9; $g9: $g8; $g8: $g7; $g7: $g6; $g6: $g5;
$g5: $g4; $g4: $g3; $g3: $g2; $g2: $g1; $g1: $pos;
$pos: null;
}
@if $pos {
$positions: _linear-positions-parser($pos);
$pos-degree: nth($positions, 1);
$pos-spec: nth($positions, 2);
}
$full: $g1, $g2, $g3, $g4, $g5, $g6, $g7, $g8, $g9, $g10;
// Set $g1 as the default fallback color
$fallback-color: nth($g1, 1);
// If $fallback is a color use that color as the fallback color
@if (type-of($fallback) == color) or ($fallback == "transparent") {
$fallback-color: $fallback;
}
background-color: $fallback-color;
background-image: -webkit-linear-gradient($pos-degree $full); // Safari 5.1+, Chrome
background-image: unquote("linear-gradient(#{$pos-spec}#{$full})");
}
+8
View File
@@ -0,0 +1,8 @@
@mixin perspective($depth: none) {
// none | <length>
@include prefixer(perspective, $depth, webkit moz spec);
}
@mixin perspective-origin($value: 50% 50%) {
@include prefixer(perspective-origin, $value, webkit moz spec);
}
+8
View File
@@ -0,0 +1,8 @@
@mixin placeholder {
$placeholders: ":-webkit-input" ":-moz" "-moz" "-ms-input";
@each $placeholder in $placeholders {
&:#{$placeholder}-placeholder {
@content;
}
}
}
+39
View File
@@ -0,0 +1,39 @@
// Requires Sass 3.1+
@mixin radial-gradient($g1, $g2,
$g3: null, $g4: null,
$g5: null, $g6: null,
$g7: null, $g8: null,
$g9: null, $g10: null,
$pos: null,
$shape-size: null,
$fallback: null) {
$data: _radial-arg-parser($g1, $g2, $pos, $shape-size);
$g1: nth($data, 1);
$g2: nth($data, 2);
$pos: nth($data, 3);
$shape-size: nth($data, 4);
$full: $g1, $g2, $g3, $g4, $g5, $g6, $g7, $g8, $g9, $g10;
// Strip deprecated cover/contain for spec
$shape-size-spec: _shape-size-stripper($shape-size);
// Set $g1 as the default fallback color
$first-color: nth($full, 1);
$fallback-color: nth($first-color, 1);
@if (type-of($fallback) == color) or ($fallback == "transparent") {
$fallback-color: $fallback;
}
// Add Commas and spaces
$shape-size: if($shape-size, "#{$shape-size}, ", null);
$pos: if($pos, "#{$pos}, ", null);
$pos-spec: if($pos, "at #{$pos}", null);
$shape-size-spec: if(($shape-size-spec != " ") and ($pos == null), "#{$shape-size-spec}, ", "#{$shape-size-spec} ");
background-color: $fallback-color;
background-image: -webkit-radial-gradient(unquote(#{$pos}#{$shape-size}#{$full}));
background-image: unquote("radial-gradient(#{$shape-size-spec}#{$pos-spec}#{$full})");
}
+42
View File
@@ -0,0 +1,42 @@
@charset "UTF-8";
/// Outputs the spec and prefixed versions of the `::selection` pseudo-element.
///
/// @param {Bool} $current-selector [false]
/// If set to `true`, it takes the current element into consideration.
///
/// @example scss - Usage
/// .element {
/// @include selection(true) {
/// background-color: #ffbb52;
/// }
/// }
///
/// @example css - CSS Output
/// .element::-moz-selection {
/// background-color: #ffbb52;
/// }
///
/// .element::selection {
/// background-color: #ffbb52;
/// }
@mixin selection($current-selector: false) {
@if $current-selector {
&::-moz-selection {
@content;
}
&::selection {
@content;
}
} @else {
::-moz-selection {
@content;
}
::selection {
@content;
}
}
}
+19
View File
@@ -0,0 +1,19 @@
@mixin text-decoration($value) {
// <text-decoration-line> || <text-decoration-style> || <text-decoration-color>
@include prefixer(text-decoration, $value, moz);
}
@mixin text-decoration-line($line: none) {
// none || underline || overline || line-through
@include prefixer(text-decoration-line, $line, moz);
}
@mixin text-decoration-style($style: solid) {
// solid || double || dotted || dashed || wavy
@include prefixer(text-decoration-style, $style, moz webkit);
}
@mixin text-decoration-color($color: currentColor) {
// currentColor || <color>
@include prefixer(text-decoration-color, $color, moz);
}
+15
View File
@@ -0,0 +1,15 @@
@mixin transform($property: none) {
// none | <transform-function>
@include prefixer(transform, $property, webkit moz ms o spec);
}
@mixin transform-origin($axes: 50%) {
// x-axis - left | center | right | length | %
// y-axis - top | center | bottom | length | %
// z-axis - length
@include prefixer(transform-origin, $axes, webkit moz ms o spec);
}
@mixin transform-style($style: flat) {
@include prefixer(transform-style, $style, webkit moz ms o spec);
}
+71
View File
@@ -0,0 +1,71 @@
// Shorthand mixin. Supports multiple parentheses-deliminated values for each variable.
// Example: @include transition (all 2s ease-in-out);
// @include transition (opacity 1s ease-in 2s, width 2s ease-out);
// @include transition-property (transform, opacity);
@mixin transition($properties...) {
// Fix for vendor-prefix transform property
$needs-prefixes: false;
$webkit: ();
$moz: ();
$spec: ();
// Create lists for vendor-prefixed transform
@each $list in $properties {
@if nth($list, 1) == "transform" {
$needs-prefixes: true;
$list1: -webkit-transform;
$list2: -moz-transform;
$list3: ();
@each $var in $list {
$list3: join($list3, $var);
@if $var != "transform" {
$list1: join($list1, $var);
$list2: join($list2, $var);
}
}
$webkit: append($webkit, $list1);
$moz: append($moz, $list2);
$spec: append($spec, $list3);
} @else {
$webkit: append($webkit, $list, comma);
$moz: append($moz, $list, comma);
$spec: append($spec, $list, comma);
}
}
@if $needs-prefixes {
-webkit-transition: $webkit;
-moz-transition: $moz;
transition: $spec;
} @else {
@if length($properties) >= 1 {
@include prefixer(transition, $properties, webkit moz spec);
} @else {
$properties: all 0.15s ease-out 0s;
@include prefixer(transition, $properties, webkit moz spec);
}
}
}
@mixin transition-property($properties...) {
-webkit-transition-property: transition-property-names($properties, "webkit");
-moz-transition-property: transition-property-names($properties, "moz");
transition-property: transition-property-names($properties, false);
}
@mixin transition-duration($times...) {
@include prefixer(transition-duration, $times, webkit moz spec);
}
@mixin transition-timing-function($motions...) {
// ease | linear | ease-in | ease-out | ease-in-out | cubic-bezier()
@include prefixer(transition-timing-function, $motions, webkit moz spec);
}
@mixin transition-delay($times...) {
@include prefixer(transition-delay, $times, webkit moz spec);
}
+3
View File
@@ -0,0 +1,3 @@
@mixin user-select($value: none) {
@include prefixer(user-select, $value, webkit moz ms spec);
}
+11
View File
@@ -0,0 +1,11 @@
@function assign-inputs($inputs, $pseudo: null) {
$list: ();
@each $input in $inputs {
$input: unquote($input);
$input: if($pseudo, $input + ":" + $pseudo, $input);
$list: append($list, $input, comma);
}
@return $list;
}
+20
View File
@@ -0,0 +1,20 @@
@charset "UTF-8";
/// Checks if a list does not contains a value.
///
/// @access private
///
/// @param {List} $list
/// The list to check against.
///
/// @return {Bool}
@function contains-falsy($list) {
@each $item in $list {
@if not $item {
@return true;
}
}
@return false;
}
+26
View File
@@ -0,0 +1,26 @@
@charset "UTF-8";
/// Checks if a list contains a value(s).
///
/// @access private
///
/// @param {List} $list
/// The list to check against.
///
/// @param {List} $values
/// A single value or list of values to check for.
///
/// @example scss - Usage
/// contains($list, $value)
///
/// @return {Bool}
@function contains($list, $values...) {
@each $value in $values {
@if type-of(index($list, $value)) != "number" {
@return false;
}
}
@return true;
}
+11
View File
@@ -0,0 +1,11 @@
@charset "UTF-8";
/// Checks for a valid CSS length.
///
/// @param {String} $value
@function is-length($value) {
@return type-of($value) != "null" and (str-slice($value + "", 1, 4) == "calc"
or index(auto inherit initial 0, $value)
or (type-of($value) == "number" and not(unitless($value))));
}
+21
View File
@@ -0,0 +1,21 @@
@charset "UTF-8";
/// Programatically determines whether a color is light or dark.
///
/// @link http://robots.thoughtbot.com/closer-look-color-lightness
///
/// @param {Color (Hex)} $color
///
/// @example scss - Usage
/// is-light($color)
///
/// @return {Bool}
@function is-light($hex-color) {
$-local-red: red(rgba($hex-color, 1));
$-local-green: green(rgba($hex-color, 1));
$-local-blue: blue(rgba($hex-color, 1));
$-local-lightness: ($-local-red * 0.2126 + $-local-green * 0.7152 + $-local-blue * 0.0722) / 255;
@return $-local-lightness > 0.6;
}
+11
View File
@@ -0,0 +1,11 @@
@charset "UTF-8";
/// Checks for a valid number.
///
/// @param {Number} $value
///
/// @require {function} contains
@function is-number($value) {
@return contains("0" "1" "2" "3" "4" "5" "6" "7" "8" "9" 0 1 2 3 4 5 6 7 8 9, $value);
}
+13
View File
@@ -0,0 +1,13 @@
@charset "UTF-8";
/// Checks for a valid CSS size.
///
/// @param {String} $value
///
/// @require {function} contains
/// @require {function} is-length
@function is-size($value) {
@return is-length($value)
or contains("fill" "fit-content" "min-content" "max-content", $value);
}
+69
View File
@@ -0,0 +1,69 @@
// Scaling Variables
$golden: 1.618;
$minor-second: 1.067;
$major-second: 1.125;
$minor-third: 1.2;
$major-third: 1.25;
$perfect-fourth: 1.333;
$augmented-fourth: 1.414;
$perfect-fifth: 1.5;
$minor-sixth: 1.6;
$major-sixth: 1.667;
$minor-seventh: 1.778;
$major-seventh: 1.875;
$octave: 2;
$major-tenth: 2.5;
$major-eleventh: 2.667;
$major-twelfth: 3;
$double-octave: 4;
$modular-scale-ratio: $perfect-fourth !default;
$modular-scale-base: em($em-base) !default;
@function modular-scale($increment, $value: $modular-scale-base, $ratio: $modular-scale-ratio) {
$v1: nth($value, 1);
$v2: nth($value, length($value));
$value: $v1;
// scale $v2 to just above $v1
@while $v2 > $v1 {
$v2: ($v2 / $ratio); // will be off-by-1
}
@while $v2 < $v1 {
$v2: ($v2 * $ratio); // will fix off-by-1
}
// check AFTER scaling $v2 to prevent double-counting corner-case
$double-stranded: $v2 > $v1;
@if $increment > 0 {
@for $i from 1 through $increment {
@if $double-stranded and ($v1 * $ratio) > $v2 {
$value: $v2;
$v2: ($v2 * $ratio);
} @else {
$v1: ($v1 * $ratio);
$value: $v1;
}
}
}
@if $increment < 0 {
// adjust $v2 to just below $v1
@if $double-stranded {
$v2: ($v2 / $ratio);
}
@for $i from $increment through -1 {
@if $double-stranded and ($v1 / $ratio) < $v2 {
$value: $v2;
$v2: ($v2 / $ratio);
} @else {
$v1: ($v1 / $ratio);
$value: $v1;
}
}
}
@return $value;
}
+13
View File
@@ -0,0 +1,13 @@
// Convert pixels to ems
// eg. for a relational value of 12px write em(12) when the parent is 16px
// if the parent is another value say 24px write em(12, 24)
@function em($pxval, $base: $em-base) {
@if not unitless($pxval) {
$pxval: strip-units($pxval);
}
@if not unitless($base) {
$base: strip-units($base);
}
@return ($pxval / $base) * 1em;
}
+15
View File
@@ -0,0 +1,15 @@
// Convert pixels to rems
// eg. for a relational value of 12px write rem(12)
// Assumes $em-base is the font-size of <html>
@function rem($pxval) {
@if not unitless($pxval) {
$pxval: strip-units($pxval);
}
$base: $em-base;
@if not unitless($base) {
$base: strip-units($base);
}
@return ($pxval / $base) * 1rem;
}
+24
View File
@@ -0,0 +1,24 @@
@charset "UTF-8";
/// Mixes a color with black.
///
/// @param {Color} $color
///
/// @param {Number (Percentage)} $percent
/// The amount of black to be mixed in.
///
/// @example scss - Usage
/// .element {
/// background-color: shade(#ffbb52, 60%);
/// }
///
/// @example css - CSS Output
/// .element {
/// background-color: #664a20;
/// }
///
/// @return {Color}
@function shade($color, $percent) {
@return mix(#000, $color, $percent);
}
+17
View File
@@ -0,0 +1,17 @@
@charset "UTF-8";
/// Strips the unit from a number.
///
/// @param {Number (With Unit)} $value
///
/// @example scss - Usage
/// $dimension: strip-units(10em);
///
/// @example css - CSS Output
/// $dimension: 10;
///
/// @return {Number (Unitless)}
@function strip-units($value) {
@return ($value / ($value * 0 + 1));
}
+24
View File
@@ -0,0 +1,24 @@
@charset "UTF-8";
/// Mixes a color with white.
///
/// @param {Color} $color
///
/// @param {Number (Percentage)} $percent
/// The amount of white to be mixed in.
///
/// @example scss - Usage
/// .element {
/// background-color: tint(#6ecaa6, 40%);
/// }
///
/// @example css - CSS Output
/// .element {
/// background-color: #a8dfc9;
/// }
///
/// @return {Color}
@function tint($color, $percent) {
@return mix(#fff, $color, $percent);
}
+22
View File
@@ -0,0 +1,22 @@
// Return vendor-prefixed property names if appropriate
// Example: transition-property-names((transform, color, background), moz) -> -moz-transform, color, background
//************************************************************************//
@function transition-property-names($props, $vendor: false) {
$new-props: ();
@each $prop in $props {
$new-props: append($new-props, transition-property-name($prop, $vendor), comma);
}
@return $new-props;
}
@function transition-property-name($prop, $vendor: false) {
// put other properties that need to be prefixed here aswell
@if $vendor and $prop == transform {
@return unquote('-'+$vendor+'-'+$prop);
}
@else {
@return $prop;
}
}
+27
View File
@@ -0,0 +1,27 @@
@charset "UTF-8";
/// Converts shorthand to the 4-value syntax.
///
/// @param {List} $shorthand
///
/// @example scss - Usage
/// .element {
/// margin: unpack(1em 2em);
/// }
///
/// @example css - CSS Output
/// .element {
/// margin: 1em 2em 1em 2em;
/// }
@function unpack($shorthand) {
@if length($shorthand) == 1 {
@return nth($shorthand, 1) nth($shorthand, 1) nth($shorthand, 1) nth($shorthand, 1);
} @else if length($shorthand) == 2 {
@return nth($shorthand, 1) nth($shorthand, 2) nth($shorthand, 1) nth($shorthand, 2);
} @else if length($shorthand) == 3 {
@return nth($shorthand, 1) nth($shorthand, 2) nth($shorthand, 3) nth($shorthand, 2);
} @else {
@return $shorthand;
}
}
+21
View File
@@ -0,0 +1,21 @@
//************************************************************************//
// Helper function for str-to-num fn.
// Source: http://sassmeister.com/gist/9647408
//************************************************************************//
@function _convert-units($number, $unit) {
$strings: "px", "cm", "mm", "%", "ch", "pica", "in", "em", "rem", "pt", "pc", "ex", "vw", "vh", "vmin", "vmax", "deg", "rad", "grad", "turn";
$units: 1px, 1cm, 1mm, 1%, 1ch, 1pica, 1in, 1em, 1rem, 1pt, 1pc, 1ex, 1vw, 1vh, 1vmin, 1vmax, 1deg, 1rad, 1grad, 1turn;
$index: index($strings, $unit);
@if not $index {
@warn "Unknown unit `#{$unit}`.";
@return false;
}
@if type-of($number) != "number" {
@warn "`#{$number} is not a number`";
@return false;
}
@return $number * nth($units, $index);
}
+96
View File
@@ -0,0 +1,96 @@
@charset "UTF-8";
/// Directional-property mixins are shorthands for writing properties like the following
///
/// @ignore You can also use `false` instead of `null`.
///
/// @param {List} $vals
/// List of directional values
///
/// @example scss - Usage
/// .element {
/// @include border-style(dotted null);
/// @include margin(null 0 10px);
/// }
///
/// @example css - CSS Output
/// .element {
/// border-bottom-style: dotted;
/// border-top-style: dotted;
/// margin-bottom: 10px;
/// margin-left: 0;
/// margin-right: 0;
/// }
///
/// @require {function} contains-falsy
///
/// @return {List}
@function collapse-directionals($vals) {
$output: null;
$a: nth($vals, 1);
$b: if(length($vals) < 2, $a, nth($vals, 2));
$c: if(length($vals) < 3, $a, nth($vals, 3));
$d: if(length($vals) < 2, $a, nth($vals, if(length($vals) < 4, 2, 4)));
@if $a == 0 { $a: 0; }
@if $b == 0 { $b: 0; }
@if $c == 0 { $c: 0; }
@if $d == 0 { $d: 0; }
@if $a == $b and $a == $c and $a == $d { $output: $a; }
@else if $a == $c and $b == $d { $output: $a $b; }
@else if $b == $d { $output: $a $b $c; }
@else { $output: $a $b $c $d; }
@return $output;
}
/// Output directional properties, for instance `margin`.
///
/// @access private
///
/// @param {String} $pre
/// Prefix to use
/// @param {String} $suf
/// Suffix to use
/// @param {List} $vals
/// List of values
///
/// @require {function} collapse-directionals
/// @require {function} contains-falsy
@mixin directional-property($pre, $suf, $vals) {
// Property Names
$top: $pre + "-top" + if($suf, "-#{$suf}", "");
$bottom: $pre + "-bottom" + if($suf, "-#{$suf}", "");
$left: $pre + "-left" + if($suf, "-#{$suf}", "");
$right: $pre + "-right" + if($suf, "-#{$suf}", "");
$all: $pre + if($suf, "-#{$suf}", "");
$vals: collapse-directionals($vals);
@if contains-falsy($vals) {
@if nth($vals, 1) { #{$top}: nth($vals, 1); }
@if length($vals) == 1 {
@if nth($vals, 1) { #{$right}: nth($vals, 1); }
} @else {
@if nth($vals, 2) { #{$right}: nth($vals, 2); }
}
@if length($vals) == 2 {
@if nth($vals, 1) { #{$bottom}: nth($vals, 1); }
@if nth($vals, 2) { #{$left}: nth($vals, 2); }
} @else if length($vals) == 3 {
@if nth($vals, 3) { #{$bottom}: nth($vals, 3); }
@if nth($vals, 2) { #{$left}: nth($vals, 2); }
} @else if length($vals) == 4 {
@if nth($vals, 3) { #{$bottom}: nth($vals, 3); }
@if nth($vals, 4) { #{$left}: nth($vals, 4); }
}
} @else {
#{$all}: $vals;
}
}
+43
View File
@@ -0,0 +1,43 @@
// Used for creating the source string for fonts using @font-face
// Reference: http://goo.gl/Ru1bKP
@function font-url-prefixer($asset-pipeline) {
@if $asset-pipeline == true {
@return font-url;
} @else {
@return url;
}
}
@function font-source-declaration(
$font-family,
$file-path,
$asset-pipeline,
$file-formats,
$font-url) {
$src: ();
$formats-map: (
eot: "#{$file-path}.eot?#iefix" format("embedded-opentype"),
woff2: "#{$file-path}.woff2" format("woff2"),
woff: "#{$file-path}.woff" format("woff"),
ttf: "#{$file-path}.ttf" format("truetype"),
svg: "#{$file-path}.svg##{$font-family}" format("svg")
);
@each $key, $values in $formats-map {
@if contains($file-formats, $key) {
$file-path: nth($values, 1);
$font-format: nth($values, 2);
@if $asset-pipeline == true {
$src: append($src, font-url($file-path) $font-format, comma);
} @else {
$src: append($src, url($file-path) $font-format, comma);
}
}
}
@return $src;
}
+13
View File
@@ -0,0 +1,13 @@
@function _gradient-positions-parser($gradient-type, $gradient-positions) {
@if $gradient-positions
and ($gradient-type == linear)
and (type-of($gradient-positions) != color) {
$gradient-positions: _linear-positions-parser($gradient-positions);
}
@else if $gradient-positions
and ($gradient-type == radial)
and (type-of($gradient-positions) != color) {
$gradient-positions: _radial-positions-parser($gradient-positions);
}
@return $gradient-positions;
}
+25
View File
@@ -0,0 +1,25 @@
// Private function for linear-gradient-parser
@function _linear-angle-parser($image, $first-val, $prefix, $suffix) {
$offset: null;
$unit-short: str-slice($first-val, str-length($first-val) - 2, str-length($first-val));
$unit-long: str-slice($first-val, str-length($first-val) - 3, str-length($first-val));
@if ($unit-long == "grad") or
($unit-long == "turn") {
$offset: if($unit-long == "grad", -100grad * 3, -0.75turn);
}
@else if ($unit-short == "deg") or
($unit-short == "rad") {
$offset: if($unit-short == "deg", -90 * 3, 1.6rad);
}
@if $offset {
$num: _str-to-num($first-val);
@return (
webkit-image: -webkit- + $prefix + ($offset - $num) + $suffix,
spec-image: $image
);
}
}

Some files were not shown because too many files have changed in this diff Show More