commit
cc50f69236
|
|
@ -1,2 +1,3 @@
|
||||||
_output
|
_output
|
||||||
_site
|
_site
|
||||||
|
.jekyll-metadata
|
||||||
|
|
|
||||||
37
Readme.md
37
Readme.md
|
|
@ -1 +1,38 @@
|
||||||
:)
|
:)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
`h2` supports these:
|
||||||
|
|
||||||
|
{: .-two-column}
|
||||||
|
{: .-three-column}
|
||||||
|
{: .-left-reference}
|
||||||
|
|
||||||
|
`h3` supports these:
|
||||||
|
|
||||||
|
{: .-prime}
|
||||||
|
|
||||||
|
`table` supports these:
|
||||||
|
|
||||||
|
{: .-shortcuts}
|
||||||
|
|
||||||
|
`pre` supports these:
|
||||||
|
|
||||||
|
{: .-setup}
|
||||||
|
|
||||||
|
`ul` supports these:
|
||||||
|
|
||||||
|
{: .-also-see}
|
||||||
|
|
||||||
|
Each sheet supports these metadata:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
---
|
||||||
|
title: React.js
|
||||||
|
category: React
|
||||||
|
layout: 2017/sheet # 'default' | '2017/sheet'
|
||||||
|
ads: true # Add this for ads
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ exclude:
|
||||||
- _deprecated
|
- _deprecated
|
||||||
|
|
||||||
# Markdown
|
# Markdown
|
||||||
highlighter: rouge
|
highlighter: false
|
||||||
markdown: kramdown
|
markdown: kramdown
|
||||||
kramdown:
|
kramdown:
|
||||||
input: GFM
|
input: GFM
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang='en' class='no-js {{ page.html_class }}'>
|
||||||
|
<head>
|
||||||
|
{% include meta.html %}
|
||||||
|
{% include polyfills.html %}
|
||||||
|
|
||||||
|
<!-- 3rd-party libs -->
|
||||||
|
<script src='https://code.jquery.com/jquery-3.1.0.js'></script>
|
||||||
|
<script src='https://unpkg.com/isotope-layout@3.0.4/dist/isotope.pkgd.min.js'></script>
|
||||||
|
<script src='https://unpkg.com/prismjs@1.6.0'></script>
|
||||||
|
<script src='https://unpkg.com/prismjs@1.6.0/components/prism-jsx.min.js'></script>
|
||||||
|
<script src='https://unpkg.com/prismjs@1.6.0/components/prism-bash.min.js'></script>
|
||||||
|
<script src='https://unpkg.com/prismjs@1.6.0/components/prism-scss.min.js'></script>
|
||||||
|
<script src='https://unpkg.com/prismjs@1.6.0/components/prism-elixir.min.js'></script>
|
||||||
|
<script src='https://unpkg.com/prismjs@1.6.0/plugins/line-highlight/prism-line-highlight.min.js'></script>
|
||||||
|
<link rel='stylesheet' href='https://unpkg.com/sanitize.css@5.0.0/sanitize.css'>
|
||||||
|
<!-- <link rel='stylesheet' href='https://unpkg.com/prismjs@1.6.0/themes/prism.css'> -->
|
||||||
|
<link rel='stylesheet' href='https://unpkg.com/prismjs@1.6.0/plugins/line-highlight/prism-line-highlight.css'>
|
||||||
|
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Fira+Code:400'>
|
||||||
|
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Roboto:300,400,700'>
|
||||||
|
|
||||||
|
<!-- 2017 layout -->
|
||||||
|
<link href='{{base}}/assets/2017/style.css?t={{ timestamp }}' rel='stylesheet'>
|
||||||
|
<script src='{{base}}/assets/2017/script.js?t={{ timestamp }}'></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
<div class='top-nav'>
|
||||||
|
<div class='container'>
|
||||||
|
<a class='brand' href='{{base}}'>
|
||||||
|
Rico's cheatsheets
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class='actions'>
|
||||||
|
{% include social-list.html class="social page-actions" page=include.page %}
|
||||||
|
<ul class='page-actions'>
|
||||||
|
<li class='link github -button hint--bottom' data-hint='Edit this page on GitHub'>
|
||||||
|
<a href='https://github.com/rstacruz/cheatsheets/blob/gh-pages/{{ page.path | remove: '.html' }}'>
|
||||||
|
<span class='text -visible'>Edit</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{% assign description = "The ultimate cheatsheet for " | append: include.page.title | append: "." %}
|
{% assign description = "The ultimate cheatsheet for " | append: include.page.title | append: "." %}
|
||||||
<ul class="social-list {{ include.class }}">
|
<ul class="social-list {{ include.class }}">
|
||||||
<li class="facebook hint--bottom" data-hint="Share on Facebook"><a href="https://www.facebook.com/sharer/sharer.php?u={{ site.url }}{{ include.page.url }}" target="share"><span class="text">Like</span></a></li>
|
<li class="facebook link hint--bottom" data-hint="Share on Facebook"><a href="https://www.facebook.com/sharer/sharer.php?u={{ site.url }}{{ include.page.url }}" target="share"><span class="text">Like</span></a></li>
|
||||||
<li class="twitter hint--bottom" data-hint="Share on Twitter"><a href="https://twitter.com/intent/tweet?text={{ description }} {{ site.url }}{{ include.page.url }}" target="share"><span class="text">Tweet</span></a></li>
|
<li class="twitter link hint--bottom" data-hint="Share on Twitter"><a href="https://twitter.com/intent/tweet?text={{ description }} {{ site.url }}{{ include.page.url }}" target="share"><span class="text">Tweet</span></a></li>
|
||||||
<li class="googleplus hint--bottom" data-hint="Share on Google Plus"><a href="https://plus.google.com/share?url={{ site.url }}{{ include.page.url }}" target="share"><span class="text">+1</span></a></li>
|
<!--<li class="googleplus link hint--bottom" data-hint="Share on Google Plus"><a href="https://plus.google.com/share?url={{ site.url }}{{ include.page.url }}" target="share"><span class="text">+1</span></a></li>-->
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
type: article
|
||||||
|
---
|
||||||
|
{% include 2017/head.html %}
|
||||||
|
|
||||||
|
{% include 2017/top-nav.html page=page %}
|
||||||
|
|
||||||
|
<div class='body-area'>
|
||||||
|
<div class='main-heading {% if page.ads %}-with-ads{% endif %}'>
|
||||||
|
<h1 class='h1'>{{ page.title }} <em>cheatsheet</em></h1>
|
||||||
|
{% if page.ads %}
|
||||||
|
<div class='HeadlineAd ad'>
|
||||||
|
<script async src='//cdn.carbonads.com/carbon.js?zoneid=1673&serve=C6AILKT&placement=ricostacruzcom' id="_carbonads_js"></script>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='post-content MarkdownBody' data-js-main-body>
|
||||||
|
{{ content }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% include 2017/foot.html %}
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Base
|
||||||
|
*/
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
background: $base-body;
|
||||||
|
font-family: $body-font;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: $base-text;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
@include font-size(0);
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Code
|
||||||
|
*/
|
||||||
|
|
||||||
|
pre, code {
|
||||||
|
font-family: $monospace-font;
|
||||||
|
letter-spacing: -0.03em;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
font-size: 0.92em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Antialias
|
||||||
|
*/
|
||||||
|
|
||||||
|
* {
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Links
|
||||||
|
*/
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: $base-b;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:visited {
|
||||||
|
color: $base-b7;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: $base-b3;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
.body-area {
|
||||||
|
max-width: $area-width;
|
||||||
|
margin: 0 auto;
|
||||||
|
@include gutter(padding);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* h2 section
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Hide the first h2 heading */
|
||||||
|
.h2-section {
|
||||||
|
&:first-child > h2 {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 481px) {
|
||||||
|
& + & {
|
||||||
|
margin-top: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* H3 section list:
|
||||||
|
* The body that is isotoped.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.h3-section-list {
|
||||||
|
& {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clearfix
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
zoom: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each section
|
||||||
|
& > .h3-section {
|
||||||
|
@include gutter(padding);
|
||||||
|
float: left;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .h3-section {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Two column (default)
|
||||||
|
*/
|
||||||
|
|
||||||
|
.h3-section-list,
|
||||||
|
.h3-section-list.-two-column {
|
||||||
|
@media (min-width: 769px) {
|
||||||
|
& > .h3-section {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* One column
|
||||||
|
*/
|
||||||
|
|
||||||
|
.h3-section-list.-one-column {
|
||||||
|
& > .h3-section {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Three column
|
||||||
|
*/
|
||||||
|
|
||||||
|
.h3-section-list.-three-column {
|
||||||
|
@media (min-width: 769px) {
|
||||||
|
& > .h3-section {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 961px) {
|
||||||
|
& > .h3-section {
|
||||||
|
width: 33.33%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Three column, left reference
|
||||||
|
*/
|
||||||
|
|
||||||
|
.h3-section-list.-left-reference {
|
||||||
|
@media (min-width: 769px) {
|
||||||
|
& > .h3-section {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 961px) {
|
||||||
|
& > .h3-section {
|
||||||
|
width: 66.67%;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .h3-section:first-child {
|
||||||
|
width: 33.33%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
* H3 section
|
||||||
|
*/
|
||||||
|
|
||||||
|
.h3-section > .body {
|
||||||
|
& > pre {
|
||||||
|
margin: 0;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& {
|
||||||
|
background: white;
|
||||||
|
box-shadow: $shadow3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Collapse/flush */
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
margin: 0 -16px;
|
||||||
|
box-shadow: $shadow2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Border radius */
|
||||||
|
@media (min-width: 481px) {
|
||||||
|
& {
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > :first-child {
|
||||||
|
border-top-left-radius: 3px;
|
||||||
|
border-top-right-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > :last-child {
|
||||||
|
border-bottom-left-radius: 3px;
|
||||||
|
border-bottom-right-radius: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Children
|
||||||
|
*/
|
||||||
|
|
||||||
|
.h3-section > .body {
|
||||||
|
/* Lists */
|
||||||
|
& > ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > ul > li {
|
||||||
|
padding: 8px;
|
||||||
|
padding-left: 32px + 4px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > ul > li::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
display: inline-block;
|
||||||
|
width: 4px;
|
||||||
|
height: 4px;
|
||||||
|
background: $gray-text;
|
||||||
|
border-radius: 50%;
|
||||||
|
left: 16px;
|
||||||
|
top: 16px + 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > ul > li + li {
|
||||||
|
border-top: solid 1px $line-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Paragraphs */
|
||||||
|
& > p {
|
||||||
|
padding: 16px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Description paragraphs */
|
||||||
|
& > pre ~ p,
|
||||||
|
& > ul ~ p,
|
||||||
|
& > iframe ~ p,
|
||||||
|
& > table ~ p {
|
||||||
|
background: $gray-bg;
|
||||||
|
color: $gray-text;
|
||||||
|
|
||||||
|
/* Links */
|
||||||
|
& a,
|
||||||
|
& a:visited {
|
||||||
|
color: $base-text;
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: solid 1px $line-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
& a:hover {
|
||||||
|
color: $base-b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Line divisions */
|
||||||
|
& > *:not(:first-child) {
|
||||||
|
border-top: solid 1px $line-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prime
|
||||||
|
*/
|
||||||
|
|
||||||
|
.h3-section.-prime > .body {
|
||||||
|
@media (min-width: 481px) {
|
||||||
|
border-radius: 2px;
|
||||||
|
box-shadow: $shadow6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.-also-see.-also-see.-also-see {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
background: $gray-bg;
|
||||||
|
|
||||||
|
& > li {
|
||||||
|
flex: 1 0 20%;
|
||||||
|
padding: 24px;
|
||||||
|
border-top: solid 1px $dark-line-color;
|
||||||
|
|
||||||
|
& + li {
|
||||||
|
border-left: solid 1px $dark-line-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&,
|
||||||
|
& > li {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > li::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > li > a {
|
||||||
|
@include font-size(1);
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > li > em {
|
||||||
|
@include font-size(-1);
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Carbon ads
|
||||||
|
*
|
||||||
|
* .headline-ad
|
||||||
|
* #carbonads
|
||||||
|
* span
|
||||||
|
* span.carbon-wrap
|
||||||
|
* a.carbon-img > img
|
||||||
|
* a.carbon-text {description}
|
||||||
|
* a.carbon-poweredby {powered by Carbon}
|
||||||
|
*/
|
||||||
|
|
||||||
|
.HeadlineAd {
|
||||||
|
@include font-size(-1);
|
||||||
|
|
||||||
|
& {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&,
|
||||||
|
& > div > span {
|
||||||
|
min-width: 130px + 16px + 64px;
|
||||||
|
max-width: 400px;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > div > span {
|
||||||
|
display: inline-block;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > div > span::after {
|
||||||
|
content: '';
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
zoom: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carbon-img,
|
||||||
|
.carbon-text,
|
||||||
|
.carbon-poweredby {
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carbon-img {
|
||||||
|
float: right;
|
||||||
|
margin-left: 16px;
|
||||||
|
width: 130px;
|
||||||
|
height: 100px;
|
||||||
|
box-shadow: $shadow3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carbon-img > img {
|
||||||
|
border-radius: 3px;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carbon-img:hover {
|
||||||
|
transform: translate3d(0, -1px, 0);
|
||||||
|
box-shadow: $shadow6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carbon-text,
|
||||||
|
.carbon-text:visited {
|
||||||
|
color: $gray-text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carbon-poweredby,
|
||||||
|
.carbon-poweredby:visited {
|
||||||
|
color: lighten($gray-text, 20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.carbon-text:hover,
|
||||||
|
.carbon-poweredby:hover {
|
||||||
|
color: $base-a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* The top-level heading
|
||||||
|
*/
|
||||||
|
|
||||||
|
.main-heading {
|
||||||
|
@include heading-style;
|
||||||
|
|
||||||
|
& > h1 {
|
||||||
|
@include font-size(6);
|
||||||
|
line-height: 1.2;
|
||||||
|
font-weight: 300;
|
||||||
|
font-family: $body-font;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > h1 > em {
|
||||||
|
font-style: normal;
|
||||||
|
color: lighten($gray-text, 20%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* With ads
|
||||||
|
*/
|
||||||
|
|
||||||
|
.main-heading.-with-ads {
|
||||||
|
& {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Desktop
|
||||||
|
@media (min-width: 541px) {
|
||||||
|
& {
|
||||||
|
align-items: flex-end; // bottom alighn
|
||||||
|
}
|
||||||
|
|
||||||
|
& > h1 {
|
||||||
|
flex: 1 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advertisement
|
||||||
|
& > .ad {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 540px) {
|
||||||
|
& {
|
||||||
|
flex-direction: column;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > h1,
|
||||||
|
& > .ad {
|
||||||
|
flex: 1 0 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > h1 {
|
||||||
|
order: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .ad {
|
||||||
|
order: 1;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
@mixin action-bar {
|
||||||
|
& {
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .link.link > a,
|
||||||
|
& > .link.link > a::before {
|
||||||
|
display: inline-block;
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
vertical-align: top;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .link.link > a {
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&,
|
||||||
|
& > li {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > li > a,
|
||||||
|
& > li > a:visited {
|
||||||
|
color: $base-mute;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > li > a:hover,
|
||||||
|
& > li > a:focus {
|
||||||
|
color: $base-b3;
|
||||||
|
|
||||||
|
& > .text {
|
||||||
|
color: $base-b3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > li > a::before {
|
||||||
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > li > a > .text {
|
||||||
|
@include font-size(-1);
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > li > a > .text.-visible {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-actions {
|
||||||
|
& {
|
||||||
|
@include action-bar;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .facebook > a::before {
|
||||||
|
@include ion-icon('logo-facebook');
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .twitter > a::before {
|
||||||
|
@include ion-icon('logo-twitter');
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .github > a::before {
|
||||||
|
@include ion-icon('logo-github');
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .link.-button > a {
|
||||||
|
box-shadow: inset 0 0 0 1px $dark-line-color;
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 0 16px;
|
||||||
|
margin: 0 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
.top-nav {
|
||||||
|
& {
|
||||||
|
border-bottom: solid 1px $dark-line-color;
|
||||||
|
height: 48px;
|
||||||
|
line-height: 48px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
>.container {
|
||||||
|
@include gutter(padding-left);
|
||||||
|
@include gutter(padding-right);
|
||||||
|
max-width: $area-width;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-nav > .container {
|
||||||
|
& {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .brand {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .actions {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .brand {
|
||||||
|
@include font-size(-1);
|
||||||
|
display: inline-block;
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&,
|
||||||
|
&:visited {
|
||||||
|
color: $base-text;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $base-a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .actions > .social {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// page-actions.scss
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
.MarkdownBody code {
|
||||||
|
color: $gray-text;
|
||||||
|
font-size: 0.86em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MarkdownBody pre,
|
||||||
|
.MarkdownBody code {
|
||||||
|
font-family: $monospace-font;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Undo prism theme crap
|
||||||
|
*/
|
||||||
|
|
||||||
|
.MarkdownBody {
|
||||||
|
pre {
|
||||||
|
box-shadow: none;
|
||||||
|
border-left: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
overflow-x: auto;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre > code {
|
||||||
|
color: $base-text;
|
||||||
|
max-height: auto;
|
||||||
|
padding: 0;
|
||||||
|
background: transparent;
|
||||||
|
overflow: visible;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Line highlight
|
||||||
|
.line-highlight {
|
||||||
|
transform: translate3d(0, 1px, 0);
|
||||||
|
background: linear-gradient(
|
||||||
|
to right,
|
||||||
|
rgba($base-c, 0.05) 25%,
|
||||||
|
rgba($base-c, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Line highlight ranges
|
||||||
|
.line-highlight[data-end] {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-highlight::before,
|
||||||
|
.line-highlight::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.MarkdownBody pre.-setup {
|
||||||
|
background: $gray-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Syntax kighlight
|
||||||
|
*/
|
||||||
|
|
||||||
|
.token {
|
||||||
|
$cA: $base-b;
|
||||||
|
$cA-3: adjust-color($cA, $lightness: 15%, $hue: -10deg);
|
||||||
|
$cA-7: adjust-color($cA, $lightness: -15%, $hue: 10deg);
|
||||||
|
|
||||||
|
$cB: $base-c;
|
||||||
|
$cB-3: adjust-color($cB, $lightness: 15%, $hue: -10deg);
|
||||||
|
|
||||||
|
$cM: #aaa; // Mute
|
||||||
|
|
||||||
|
&.tag,
|
||||||
|
&.keyword {
|
||||||
|
color: $cA;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.tag {
|
||||||
|
color: $cA-7;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.value,
|
||||||
|
&.string,
|
||||||
|
&.number,
|
||||||
|
&.attr-value,
|
||||||
|
&.boolean,
|
||||||
|
&.regex {
|
||||||
|
color: $cB;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.function,
|
||||||
|
&.attr-name {
|
||||||
|
color: $cA-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.comment,
|
||||||
|
&.punctuation,
|
||||||
|
&.operator {
|
||||||
|
color: $cM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* MarkdownBody context
|
||||||
|
*/
|
||||||
|
|
||||||
|
.MarkdownBody h2 {
|
||||||
|
@include heading-style;
|
||||||
|
@include font-size(5);
|
||||||
|
line-height: 1.2;
|
||||||
|
font-weight: 300;
|
||||||
|
font-family: $heading-font;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MarkdownBody h3 {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-family: $heading-font;
|
||||||
|
@include font-size(2);
|
||||||
|
font-weight: 300;
|
||||||
|
color: $base-a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MarkdownBody {
|
||||||
|
a,
|
||||||
|
a:visited {
|
||||||
|
color: $base-b;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
em {
|
||||||
|
font-style: normal;
|
||||||
|
color: $gray-text;
|
||||||
|
}
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Table
|
||||||
|
*/
|
||||||
|
|
||||||
|
.MarkdownBody table {
|
||||||
|
& {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
& tr + tr {
|
||||||
|
border-top: solid 1px $line-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Horizontal lines */
|
||||||
|
& tbody + tbody {
|
||||||
|
border-top: solid 1px $dark-line-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
& td,
|
||||||
|
& th {
|
||||||
|
padding: 8px 16px;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
& tr td:last-child {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
& td:first-child {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
& td:first-child > code {
|
||||||
|
font-size: 0.86em;
|
||||||
|
color: #35a;
|
||||||
|
}
|
||||||
|
|
||||||
|
& a,
|
||||||
|
& a:visited {
|
||||||
|
color: #35a;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& td:first-child > code ~ em {
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 0.86em;
|
||||||
|
color: $gray-text;
|
||||||
|
}
|
||||||
|
|
||||||
|
& thead {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.MarkdownBody table.-shortcuts {
|
||||||
|
code {
|
||||||
|
font-size: 1em;
|
||||||
|
padding: 5px 6px;
|
||||||
|
padding-left: 8px; // compensation
|
||||||
|
background: $gray-bg;
|
||||||
|
border-radius: 3px;
|
||||||
|
margin-right: 2px;
|
||||||
|
letter-spacing: 0.2em;
|
||||||
|
font-family: $body-font;
|
||||||
|
color: $base-text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
@import url('https://unpkg.com/hint.css@2.5.0/hint.min.css');
|
||||||
|
@import './variables';
|
||||||
|
@import '../vendor/modularscale/modularscale';
|
||||||
|
@import '../vendor/iconfonts/ionicons@3';
|
||||||
|
@import './utils/font-size';
|
||||||
|
@import './utils/gutter';
|
||||||
|
@import './utils/heading-style';
|
||||||
|
@include ion-font;
|
||||||
|
@import './base/base';
|
||||||
|
@import './markdown/code';
|
||||||
|
@import './markdown/headings';
|
||||||
|
@import './markdown/table';
|
||||||
|
@import './components/body-area';
|
||||||
|
@import './components/h2-section';
|
||||||
|
@import './components/h3-section';
|
||||||
|
@import './components/h3-section-list';
|
||||||
|
@import './components/headline-ad';
|
||||||
|
@import './components/main-heading';
|
||||||
|
@import './components/page-actions';
|
||||||
|
@import './components/top-nav';
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
@mixin font-size ($n) {
|
||||||
|
@include ms-respond(font-size, $n);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
@mixin gutter ($property, $multiplier: 1) {
|
||||||
|
#{$property}: $gut * $multiplier;
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
#{$property}: $gut-small * $multiplier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
@mixin heading-style {
|
||||||
|
margin: $gut;
|
||||||
|
padding: 0;
|
||||||
|
margin-bottom: 16px + 8px;
|
||||||
|
padding-bottom: 16px + 8px;
|
||||||
|
margin-top: 64px;
|
||||||
|
border-bottom: solid 1px $dark-line-color;
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
margin: $gut;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
margin-top: 32px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
margin: $gut-small;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
margin-top: 32px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* Metrics
|
||||||
|
*/
|
||||||
|
|
||||||
|
$gut-small: 8px; // max 480px width
|
||||||
|
$gut: 16px;
|
||||||
|
$column: 400px;
|
||||||
|
|
||||||
|
$area-width: $column * 3 + 32px;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fonts
|
||||||
|
*/
|
||||||
|
|
||||||
|
$system-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
||||||
|
$body-font: 'Roboto', $system-font;
|
||||||
|
$heading-font: 'Roboto', $system-font;
|
||||||
|
$monospace-font: 'Fira Mono', Consolas, menlo, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Base colors
|
||||||
|
*/
|
||||||
|
|
||||||
|
$base-body: #f1f3f5;
|
||||||
|
$base-panel: white;
|
||||||
|
$base-head: #111;
|
||||||
|
$base-text: #345;
|
||||||
|
$base-mute: #667788; // gray
|
||||||
|
|
||||||
|
$base-a: #8370bd; // indigo
|
||||||
|
$base-b: #2b72a2; // blue
|
||||||
|
$base-c: #17c694; // teal
|
||||||
|
|
||||||
|
$base-b3: adjust-color($base-b, $lightness: 16%, $hue: -20deg);
|
||||||
|
$base-b7: adjust-color($base-b, $lightness: -16%, $hue: 20deg);
|
||||||
|
$base-mute3: adjust-color($base-mute, $lightness: -16%);
|
||||||
|
$base-mute4: adjust-color($base-mute, $lightness: -8%);
|
||||||
|
$base-mute6: adjust-color($base-mute, $lightness: 8%);
|
||||||
|
$base-mute7: adjust-color($base-mute, $lightness: 16%);
|
||||||
|
|
||||||
|
$body-bg: $base-body;
|
||||||
|
$gray-bg: mix($base-body, $base-panel, 50%);
|
||||||
|
$gray-text: $base-mute;
|
||||||
|
|
||||||
|
$line-color: rgba($base-mute, 0.05);
|
||||||
|
$dark-line-color: rgba($base-mute, 0.14);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Shadows
|
||||||
|
//
|
||||||
|
|
||||||
|
$shadow2:
|
||||||
|
0 1px 1px rgba($base-mute, 0.30);
|
||||||
|
|
||||||
|
$shadow3:
|
||||||
|
0 6px 8px rgba($base-mute, 0.02),
|
||||||
|
0 1px 2px rgba($base-mute, 0.20);
|
||||||
|
|
||||||
|
$shadow6:
|
||||||
|
0 8px 12px rgba($base-b3, 0.1),
|
||||||
|
0 2px 3px rgba($base-b, 0.18);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mod scale
|
||||||
|
*/
|
||||||
|
|
||||||
|
$modularscale: (
|
||||||
|
base: 14px, ratio: 1.2,
|
||||||
|
480px: (base: 13px, ratio: 1.15),
|
||||||
|
768px: (base: 14px, ratio: 1.17),
|
||||||
|
1280px: (base: 14px, ratio: 1.2)
|
||||||
|
);
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,312 @@
|
||||||
|
// https://github.com/modularscale/modularscale-sass v3.0.3
|
||||||
|
|
||||||
|
// Ratios
|
||||||
|
$double-octave : 4 ;
|
||||||
|
$pi : 3.14159265359 ;
|
||||||
|
$major-twelfth : 3 ;
|
||||||
|
$major-eleventh : 2.666666667 ;
|
||||||
|
$major-tenth : 2.5 ;
|
||||||
|
$octave : 2 ;
|
||||||
|
$major-seventh : 1.875 ;
|
||||||
|
$minor-seventh : 1.777777778 ;
|
||||||
|
$major-sixth : 1.666666667 ;
|
||||||
|
$phi : 1.618034 ;
|
||||||
|
$golden : $phi ;
|
||||||
|
$minor-sixth : 1.6 ;
|
||||||
|
$fifth : 1.5 ;
|
||||||
|
$augmented-fourth : 1.41421 ;
|
||||||
|
$fourth : 1.333333333 ;
|
||||||
|
$major-third : 1.25 ;
|
||||||
|
$minor-third : 1.2 ;
|
||||||
|
$major-second : 1.125 ;
|
||||||
|
$minor-second : 1.066666667 ;
|
||||||
|
|
||||||
|
// Base config
|
||||||
|
$ms-base : 1em !default;
|
||||||
|
$ms-ratio : $fifth !default;
|
||||||
|
$modularscale : () !default;// Parse settings starting with defaults.
|
||||||
|
// Settings should cascade down like you would expect in CSS.
|
||||||
|
// More specific overrides previous settings.
|
||||||
|
|
||||||
|
@function ms-settings($b: false, $r: false, $t: false, $m: $modularscale) {
|
||||||
|
$base: $ms-base;
|
||||||
|
$ratio: $ms-ratio;
|
||||||
|
$thread: map-get($m, $t);
|
||||||
|
|
||||||
|
// Override with user settings
|
||||||
|
@if map-get($m, base) {
|
||||||
|
$base: map-get($m, base);
|
||||||
|
}
|
||||||
|
@if map-get($m, ratio) {
|
||||||
|
$ratio: map-get($m, ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override with thread settings
|
||||||
|
@if $thread {
|
||||||
|
@if map-get($thread, base) {
|
||||||
|
$base: map-get($thread, base);
|
||||||
|
}
|
||||||
|
@if map-get($thread, ratio) {
|
||||||
|
$ratio: map-get($thread, ratio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override with inline settings
|
||||||
|
@if $b {
|
||||||
|
$base: $b;
|
||||||
|
}
|
||||||
|
@if $r {
|
||||||
|
$ratio: $r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@return $base $ratio;
|
||||||
|
}// Sass does not have native pow() support so this needs to be added.
|
||||||
|
// Compass and other libs implement this more extensively.
|
||||||
|
// In order to keep this simple, use those when they are avalible.
|
||||||
|
// Issue for pow() support in Sass: https://github.com/sass/sass/issues/684
|
||||||
|
|
||||||
|
@function ms-pow($b,$e) {
|
||||||
|
|
||||||
|
// Return 1 if exponent is 0
|
||||||
|
@if $e == 0 {
|
||||||
|
@return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If pow() exists (compass or mathsass) use that.
|
||||||
|
@if function-exists('pow') {
|
||||||
|
@return pow($b,$e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This does not support non-integer exponents,
|
||||||
|
// Check and return an error if a non-integer exponent is passed.
|
||||||
|
@if (floor($e) != $e) {
|
||||||
|
@error '
|
||||||
|
======================================================================
|
||||||
|
Non-integer values are not supported in modularscale by default.
|
||||||
|
|
||||||
|
Try using mathsass in your project to add non-integer scale support.
|
||||||
|
https://github.com/terkel/mathsass
|
||||||
|
======================================================================
|
||||||
|
'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seed the return.
|
||||||
|
$ms-return: $b;
|
||||||
|
|
||||||
|
// Multiply or divide by the specified number of times.
|
||||||
|
@if $e > 0 {
|
||||||
|
@for $i from 1 to $e {
|
||||||
|
$ms-return: $ms-return * $b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@if $e < 0 {
|
||||||
|
@for $i from $e through 0 {
|
||||||
|
$ms-return: $ms-return / $b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@return $ms-return;
|
||||||
|
}// Stripping units is not a best practice
|
||||||
|
// This function should not be used elsewhere
|
||||||
|
// It is used here because calc() doesn't do unit logic
|
||||||
|
// AND target ratios use units as a hack to get a number.
|
||||||
|
@function ms-unitless($val) {
|
||||||
|
@return ($val / ($val - $val + 1));
|
||||||
|
}// Basic list sorting
|
||||||
|
// Would like to replace with http://sassmeister.com/gist/30e4863bd03ce0e1617c
|
||||||
|
// Unfortunately libsass has a bug with passing arguments into the min() funciton.
|
||||||
|
|
||||||
|
@function ms-sort($l) {
|
||||||
|
|
||||||
|
// loop until the list is confirmed to be sorted
|
||||||
|
$sorted: false;
|
||||||
|
@while $sorted == false {
|
||||||
|
|
||||||
|
// Start with the assumption that the lists are sorted.
|
||||||
|
$sorted: true;
|
||||||
|
|
||||||
|
// Loop through the list, checking each value with the one next to it.
|
||||||
|
// Swap the values if they need to be swapped.
|
||||||
|
// Not super fast but simple and modular scale doesn't lean hard on sorting.
|
||||||
|
@for $i from 2 through length($l) {
|
||||||
|
$n1: nth($l,$i - 1);
|
||||||
|
$n2: nth($l,$i);
|
||||||
|
|
||||||
|
// If the first value is greater than the 2nd, swap them.
|
||||||
|
@if $n1 > $n2 {
|
||||||
|
$l: set-nth($l, $i, $n1);
|
||||||
|
$l: set-nth($l, $i - 1, $n2);
|
||||||
|
|
||||||
|
// The list isn't sorted and needs to be looped through again.
|
||||||
|
$sorted: false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the sorted list.
|
||||||
|
@return $l;
|
||||||
|
}// No reason to have decimal pixel values,
|
||||||
|
// normalize them to whole numbers.
|
||||||
|
|
||||||
|
@function ms-round-px($r) {
|
||||||
|
@if unit($r) == 'px' {
|
||||||
|
@return round($r);
|
||||||
|
}
|
||||||
|
@return $r;
|
||||||
|
}// Convert number string to number
|
||||||
|
@function ms-to-num($n) {
|
||||||
|
$l: str-length($n);
|
||||||
|
$r: 0;
|
||||||
|
$m: str-index($n,'.');
|
||||||
|
@if $m == null {
|
||||||
|
$m: $l + 1;
|
||||||
|
}
|
||||||
|
// Loop through digits and convert to numbers
|
||||||
|
@for $i from 1 through $l {
|
||||||
|
$v: str-slice($n,$i,$i);
|
||||||
|
@if $v == '1' { $v: 1; }
|
||||||
|
@elseif $v == '2' { $v: 2; }
|
||||||
|
@elseif $v == '3' { $v: 3; }
|
||||||
|
@elseif $v == '4' { $v: 4; }
|
||||||
|
@elseif $v == '5' { $v: 5; }
|
||||||
|
@elseif $v == '6' { $v: 6; }
|
||||||
|
@elseif $v == '7' { $v: 7; }
|
||||||
|
@elseif $v == '8' { $v: 8; }
|
||||||
|
@elseif $v == '9' { $v: 9; }
|
||||||
|
@elseif $v == '0' { $v: 0; }
|
||||||
|
@else { $v: null; }
|
||||||
|
@if $v != null {
|
||||||
|
$m: $m - 1;
|
||||||
|
$r: $r + ms-pow(10,$m - 1) * $v;
|
||||||
|
} @else {
|
||||||
|
$l: $l - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@return $r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find a ratio based on a target value
|
||||||
|
@function ms-target($t,$b) {
|
||||||
|
// Convert to string
|
||||||
|
$t: $t + '';
|
||||||
|
// Remove base units to calulate ratio
|
||||||
|
$b: ms-unitless(nth($b,1));
|
||||||
|
// Find where 'at' is in the string
|
||||||
|
$at: str-index($t,'at');
|
||||||
|
|
||||||
|
// Slice the value and target out
|
||||||
|
// and convert strings to numbers
|
||||||
|
$v: ms-to-num(str-slice($t,0,$at - 1));
|
||||||
|
$t: ms-to-num(str-slice($t,$at + 2));
|
||||||
|
|
||||||
|
// Solve the modular scale function for the ratio.
|
||||||
|
@return ms-pow(($v/$b),(1/$t));
|
||||||
|
}@function ms-function($v: 0, $base: false, $ratio: false, $thread: false, $settings: $modularscale) {
|
||||||
|
|
||||||
|
// Parse settings
|
||||||
|
$ms-settings: ms-settings($base,$ratio,$thread,$settings);
|
||||||
|
$base: nth($ms-settings, 1);
|
||||||
|
$ratio: nth($ms-settings, 2);
|
||||||
|
|
||||||
|
// Render target values from settings.
|
||||||
|
@if unit($ratio) != '' {
|
||||||
|
$ratio: ms-target($ratio,$base)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fast calc if not multi stranded
|
||||||
|
@if(length($base) == 1) {
|
||||||
|
@return ms-round-px(ms-pow($ratio, $v) * $base);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new base array
|
||||||
|
$ms-bases: nth($base,1);
|
||||||
|
|
||||||
|
// Normalize base values
|
||||||
|
@for $i from 2 through length($base) {
|
||||||
|
// initial base value
|
||||||
|
$ms-base: nth($base,$i);
|
||||||
|
// If the base is bigger than the main base
|
||||||
|
@if($ms-base > nth($base,1)) {
|
||||||
|
// divide the value until it aligns with main base.
|
||||||
|
@while($ms-base > nth($base,1)) {
|
||||||
|
$ms-base: $ms-base / $ratio;
|
||||||
|
}
|
||||||
|
$ms-base: $ms-base * $ratio;
|
||||||
|
}
|
||||||
|
// If the base is smaller than the main base.
|
||||||
|
@elseif ($ms-base < nth($base,1)) {
|
||||||
|
// pump up the value until it aligns with main base.
|
||||||
|
@while $ms-base < nth($base,1) {
|
||||||
|
$ms-base: $ms-base * $ratio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Push into new array
|
||||||
|
$ms-bases: append($ms-bases,$ms-base);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort array from smallest to largest.
|
||||||
|
$ms-bases: ms-sort($ms-bases);
|
||||||
|
|
||||||
|
// Find step to use in calculation
|
||||||
|
$vtep: floor($v / length($ms-bases));
|
||||||
|
// Find base to use in calculation
|
||||||
|
$ms-base: round(($v / length($ms-bases) - $vtep) * length($ms-bases)) + 1;
|
||||||
|
|
||||||
|
@return ms-round-px(ms-pow($ratio, $vtep) * nth($ms-bases,$ms-base));
|
||||||
|
}// Generate calc() function
|
||||||
|
// based on Mike Riethmuller's Precise control over responsive typography
|
||||||
|
// http://madebymike.com.au/writing/precise-control-responsive-typography/
|
||||||
|
@function ms-fluid($val1: 1em, $val2: 1em, $break1: 0, $break2: 0) {
|
||||||
|
$diff: ms-unitless($val2) - ms-unitless($val1);
|
||||||
|
|
||||||
|
// v1 + (v2 - v1) * ( (100vw - b1) / b2 - b1 )
|
||||||
|
@return calc( #{$val1} + #{ms-unitless($val2) - ms-unitless($val1)} * ( ( 100vw - #{$break1}) / #{ms-unitless($break2) - ms-unitless($break1)} ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main responsive mixin
|
||||||
|
@mixin ms-respond($prop, $val, $map: $modularscale) {
|
||||||
|
$base: $ms-base;
|
||||||
|
$ratio: $ms-ratio;
|
||||||
|
|
||||||
|
$first-write: true;
|
||||||
|
$last-break: null;
|
||||||
|
|
||||||
|
// loop through all settings with a breakpoint type value
|
||||||
|
@each $v, $s in $map {
|
||||||
|
@if type-of($v) == number {
|
||||||
|
@if unit($v) != '' {
|
||||||
|
|
||||||
|
// Write out the first value without a media query.
|
||||||
|
@if $first-write {
|
||||||
|
#{$prop}: ms-function($val, $thread: $v, $settings: $map);
|
||||||
|
|
||||||
|
// Not the first write anymore, reset to false to move on.
|
||||||
|
$first-write: false;
|
||||||
|
$last-break: $v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write intermediate breakpoints.
|
||||||
|
@else {
|
||||||
|
@media (min-width: $last-break) and (max-width: $v) {
|
||||||
|
$val1: ms-function($val, $thread: $last-break, $settings: $map);
|
||||||
|
$val2: ms-function($val, $thread: $v, $settings: $map);
|
||||||
|
#{$prop}: ms-fluid($val1,$val2,$last-break,$v);
|
||||||
|
}
|
||||||
|
$last-break: $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the last breakpoint.
|
||||||
|
@if $last-break {
|
||||||
|
@media (min-width: $last-break) {
|
||||||
|
#{$prop}: ms-function($val, $thread: $last-break, $settings: $map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}// To attempt to avoid conflicts with other libraries
|
||||||
|
// all funcitons are namespaced with `ms-`.
|
||||||
|
// However, to increase usability, a shorthand function is included here.
|
||||||
|
|
||||||
|
@function ms($v: 0, $base: false, $ratio: false, $thread: false, $settings: $modularscale) {
|
||||||
|
@return ms-function($v, $base, $ratio, $thread, $settings);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
$(function () {
|
||||||
|
const $root = $('[data-js-main-body]')
|
||||||
|
wrapify($root)
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Isotope
|
||||||
|
*/
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
$('[data-js-h3-section-list]').each(function () {
|
||||||
|
var iso = new Isotope(this, {
|
||||||
|
itemSelector: '.h3-section',
|
||||||
|
transitionDuration: 0
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wraps h2 sections into h2-section.
|
||||||
|
* Wraps h3 sections into h3-section.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function wrapify ($root) {
|
||||||
|
const $h2sections = groupify($root, {
|
||||||
|
tag: 'h2',
|
||||||
|
wrapper: '<div class="h2-section">',
|
||||||
|
body: '<div class="body h3-section-list" data-js-h3-section-list>'
|
||||||
|
})
|
||||||
|
|
||||||
|
$h2sections.each(function () {
|
||||||
|
const $body = $(this).children('[data-js-h3-section-list]')
|
||||||
|
|
||||||
|
groupify($body, {
|
||||||
|
tag: 'h3',
|
||||||
|
wrapper: '<div class="h3-section">',
|
||||||
|
body: '<div class="body">'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Groups stuff
|
||||||
|
*/
|
||||||
|
|
||||||
|
function groupify ($this, { tag, wrapper, body }) {
|
||||||
|
const $first = $this.children(':first-child')
|
||||||
|
let $result = $()
|
||||||
|
|
||||||
|
// Handle the markup before the first h2
|
||||||
|
if (!$first.is(tag)) {
|
||||||
|
const $sibs = $first.nextUntil(tag)
|
||||||
|
$result = $result.add(wrap($first, null, $first.add($sibs)))
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.children(tag).each(function () {
|
||||||
|
const $sibs = $(this).nextUntil(tag)
|
||||||
|
const $heading = $(this)
|
||||||
|
$result = $result.add(wrap($heading, $heading, $sibs))
|
||||||
|
})
|
||||||
|
|
||||||
|
return $result
|
||||||
|
|
||||||
|
function wrap ($pivot, $first, $sibs) {
|
||||||
|
const $wrap = $(wrapper)
|
||||||
|
$wrap.addClass($pivot.attr('class'))
|
||||||
|
$pivot.before($wrap)
|
||||||
|
|
||||||
|
const $body = $(body)
|
||||||
|
$body.addClass($pivot.attr('class'))
|
||||||
|
$body.append($sibs)
|
||||||
|
|
||||||
|
if ($first) $wrap.append($first)
|
||||||
|
$wrap.append($body)
|
||||||
|
|
||||||
|
return $wrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
---
|
||||||
|
@import '2017/style.scss';
|
||||||
194
elixir.md
194
elixir.md
|
|
@ -1,29 +1,26 @@
|
||||||
---
|
---
|
||||||
title: Elixir
|
title: Elixir
|
||||||
category: Development
|
category: Development
|
||||||
|
layout: 2017/sheet
|
||||||
---
|
---
|
||||||
|
|
||||||
## Importing
|
## Reference
|
||||||
|
|
||||||
```elixir
|
### Primitives
|
||||||
require Redux # compiles a module
|
|
||||||
import Redux # compiles, and you can use without the `Redux.` prefix
|
|
||||||
|
|
||||||
use Redux # compiles, and runs Redux.__using__/1
|
| `nil` | Nil/null |
|
||||||
use Redux, async: true
|
| `true` _/_ `false` | Boolean |
|
||||||
|
| `'hello'` | Char list |
|
||||||
|
| `<<2, 3>>` | Binary |
|
||||||
|
| `"hello"` | Binary string |
|
||||||
|
| `:hello` | Atom |
|
||||||
|
| `[a, b]` | List |
|
||||||
|
| `{a, b}` | Tuple |
|
||||||
|
| `%{a: "hello"}` | Map |
|
||||||
|
| `%MyStruct{a: "hello"}` | Struct |
|
||||||
|
| `fn -> ... end` | Function |
|
||||||
|
|
||||||
import Redux, only: [duplicate: 2]
|
### Type checks
|
||||||
import Redux, only: :functions
|
|
||||||
import Redux, only: :macros
|
|
||||||
|
|
||||||
alias Foo.Bar, as: Bar
|
|
||||||
alias Foo.Bar # same as above
|
|
||||||
|
|
||||||
alias Foo.{Bar, Baz}
|
|
||||||
import Foo.{Bar, Baz}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Type checks
|
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
is_atom/1
|
is_atom/1
|
||||||
|
|
@ -33,12 +30,16 @@ is_function/1
|
||||||
is_function/2
|
is_function/2
|
||||||
is_integer/1
|
is_integer/1
|
||||||
is_float/1
|
is_float/1
|
||||||
|
```
|
||||||
|
|
||||||
|
```elixir
|
||||||
is_binary/1
|
is_binary/1
|
||||||
is_list/1
|
is_list/1
|
||||||
is_map/1
|
is_map/1
|
||||||
is_tuple/1
|
is_tuple/1
|
||||||
|
```
|
||||||
|
|
||||||
|
```elixir
|
||||||
is_nil/1
|
is_nil/1
|
||||||
is_number/1
|
is_number/1
|
||||||
is_pid/1
|
is_pid/1
|
||||||
|
|
@ -56,16 +57,40 @@ left <> right # concat string/binary
|
||||||
left =~ right # regexp
|
left =~ right # regexp
|
||||||
```
|
```
|
||||||
|
|
||||||
### Inspecting
|
### Importing
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
inspect(arg, opts \\ [])
|
require Redux # compiles a module
|
||||||
|
import Redux # compiles, and you can use without the `Redux.` prefix
|
||||||
|
|
||||||
|
use Redux # compiles, and runs Redux.__using__/1
|
||||||
|
use Redux, async: true
|
||||||
|
|
||||||
|
import Redux, only: [duplicate: 2]
|
||||||
|
import Redux, only: :functions
|
||||||
|
import Redux, only: :macros
|
||||||
|
|
||||||
|
import Foo.{Bar, Baz}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Aliases
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
alias Foo.Bar, as: Bar
|
||||||
|
alias Foo.Bar # same as above
|
||||||
|
|
||||||
|
alias Foo.{Bar, Baz}
|
||||||
```
|
```
|
||||||
|
|
||||||
## String
|
## String
|
||||||
|
|
||||||
|
### Functions
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
import String
|
import String
|
||||||
|
```
|
||||||
|
|
||||||
|
```elixir
|
||||||
str = "hello"
|
str = "hello"
|
||||||
str |> length() #=> 5
|
str |> length() #=> 5
|
||||||
str |> codepoints() #=> ["h", "e", "l", "l", "o"]
|
str |> codepoints() #=> ["h", "e", "l", "l", "o"]
|
||||||
|
|
@ -75,19 +100,33 @@ str |> capitalize() #=> "Hello"
|
||||||
str |> match(regex)
|
str |> match(regex)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Inspecting objects
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
inspect(object, opts \\ [])
|
||||||
|
```
|
||||||
|
```elixir
|
||||||
|
value |> IO.inspect()
|
||||||
|
```
|
||||||
|
|
||||||
## Numbers
|
## Numbers
|
||||||
|
|
||||||
|
### Operations
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
abs(n)
|
abs(n)
|
||||||
|
round(n)
|
||||||
rem(a, b) # remainder (modulo)
|
rem(a, b) # remainder (modulo)
|
||||||
div(a, b) # integer division
|
div(a, b) # integer division
|
||||||
round(n)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Float
|
### Float
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
import Float
|
import Float
|
||||||
|
```
|
||||||
|
|
||||||
|
```elixir
|
||||||
n = 10.3
|
n = 10.3
|
||||||
n |> ceil() #=> 11.0
|
n |> ceil() #=> 11.0
|
||||||
n |> ceil(2) #=> 11.30
|
n |> ceil(2) #=> 11.30
|
||||||
|
|
@ -101,17 +140,20 @@ Float.parse("34") #=> { 34.0, "" }
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
import Integer
|
import Integer
|
||||||
|
```
|
||||||
|
|
||||||
|
```elixir
|
||||||
n = 12
|
n = 12
|
||||||
digits(n) #=> [1, 2]
|
n |> digits() #=> [1, 2]
|
||||||
to_char_list(n) #=> '12'
|
n |> to_char_list() #=> '12'
|
||||||
to_string(n)
|
n |> to_string() #=> "12"
|
||||||
is_even(n)
|
n |> is_even()
|
||||||
is_odd(n)
|
n |> is_odd()
|
||||||
|
|
||||||
# Different base:
|
# Different base:
|
||||||
digits(n, 2) #=> [1, 1, 0, 0]
|
n |> digits(2) #=> [1, 1, 0, 0]
|
||||||
to_char_list(n, 2) #=> '1100'
|
n |> to_char_list(2) #=> '1100'
|
||||||
to_string(n, 2)
|
n |> to_string(2) #=> "1100"
|
||||||
|
|
||||||
parse("12") #=> 12
|
parse("12") #=> 12
|
||||||
undigits([1, 2]) #=> 12
|
undigits([1, 2]) #=> 12
|
||||||
|
|
@ -129,42 +171,46 @@ Float.to_string(34.1, [decimals: 2, compact: true]) #=> "34.1"
|
||||||
|
|
||||||
## Map
|
## Map
|
||||||
|
|
||||||
|
### Defining
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
map = %{name: "hi"} # atom keys (:name)
|
map = %{name: "hi"} # atom keys (:name)
|
||||||
map = %{"name" => "hi"} # string keys ("name")
|
map = %{"name" => "hi"} # string keys ("name")
|
||||||
```
|
```
|
||||||
|
|
||||||
### Updating
|
### Updating
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
import Map
|
import Map
|
||||||
|
|
||||||
map = %{map | name: "yo"} # key must exist
|
map = %{map | name: "yo"} # key must exist
|
||||||
|
|
||||||
put(map, :id, 2) #=> %{id: 2, name: "hi"}
|
map |> put(:id, 2) #=> %{id: 2, name: "hi"}
|
||||||
put_new(map, :id, 2) # only if `id` doesn't exist (`||=`)
|
map |> put_new(:id, 2) # only if `id` doesn't exist (`||=`)
|
||||||
|
|
||||||
put(map, :b, "Banana")
|
map |> put(:b, "Banana")
|
||||||
merge(map, %{b: "Banana"})
|
map |> merge(%{b: "Banana"})
|
||||||
update(map, :a, &(&1 + 1))
|
map |> update(:a, &(&1 + 1))
|
||||||
update(map, :a, fun a -> a + 1 end)
|
map |> update(:a, fun a -> a + 1 end)
|
||||||
|
|
||||||
{old, new} = get_and_update(map, :a, &(&1 || "default"))
|
{old, new} = map |> get_and_update(:a, &(&1 || "default"))
|
||||||
```
|
```
|
||||||
|
|
||||||
### Deleting
|
### Deleting
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
delete(map, :name) #=> "hi"
|
map |> delete(:name) #=> "hi"
|
||||||
pop(map, :name) #=> %{id: 1}
|
map |> pop(:name) #=> %{id: 1}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Reading
|
### Reading
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
get(map, :id) #=> 1
|
map |> get(:id) #=> 1
|
||||||
keys(map) #=> [:id, :name]
|
map |> keys() #=> [:id, :name]
|
||||||
values(map) #=> [1, "hi"]
|
map |> values() #=> [1, "hi"]
|
||||||
|
|
||||||
to_list(map) #=> [id: 1, name: "hi"]
|
map |> to_list() #=> [id: 1, name: "hi"]
|
||||||
#=> [{:id, 1}, {:name, "hi"}]
|
#=> [{:id, 1}, {:name, "hi"}]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -186,8 +232,6 @@ Map.new([:a, :b], fn x -> {x, x} end) #=> %{a: :a, b: :b}
|
||||||
|
|
||||||
## List
|
## List
|
||||||
|
|
||||||
Also see [Enum](#enum).
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import List
|
import List
|
||||||
list = [ 1, 2, 3, 4 ]
|
list = [ 1, 2, 3, 4 ]
|
||||||
|
|
@ -201,10 +245,12 @@ flatten(list)
|
||||||
flatten(list, tail)
|
flatten(list, tail)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Also see [Enum](#enum).
|
||||||
|
|
||||||
|
|
||||||
## Enum
|
## Enum
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
# consider streams instead
|
|
||||||
import Enum
|
import Enum
|
||||||
|
|
||||||
# High-order
|
# High-order
|
||||||
|
|
@ -223,14 +269,18 @@ any?(list) #=> true
|
||||||
concat(list, [:d]) #=> [:d]
|
concat(list, [:d]) #=> [:d]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Also, consider streams instead.
|
||||||
|
|
||||||
## Tuples
|
## Tuples
|
||||||
|
|
||||||
|
### Tuples
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
tuple = { :a, :b }
|
tuple = { :a, :b }
|
||||||
|
|
||||||
elem(tuple, 1) # like tuple[1]
|
tuple |> elem(1) # like tuple[1]
|
||||||
put_elem(tuple, index, value)
|
tuple |> put_elem(index, value)
|
||||||
tuple_size(tuple)
|
tuple |> tuple_size()
|
||||||
```
|
```
|
||||||
|
|
||||||
### Keyword lists
|
### Keyword lists
|
||||||
|
|
@ -270,9 +320,17 @@ apply(fun, args)
|
||||||
apply(module, fun, args)
|
apply(module, fun, args)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Syntax
|
### Function heads
|
||||||
|
|
||||||
### [Structs](http://elixir-lang.org/getting-started/structs.html)
|
```elixir
|
||||||
|
def join(a, b \\ nil)
|
||||||
|
def join(a, b) when is_nil(b) do: a
|
||||||
|
def join(a, b) do: a <> b
|
||||||
|
```
|
||||||
|
|
||||||
|
## Structs
|
||||||
|
|
||||||
|
### Structs
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
defmodule User do
|
defmodule User do
|
||||||
|
|
@ -284,18 +342,12 @@ end
|
||||||
%User{}.struct #=> User
|
%User{}.struct #=> User
|
||||||
```
|
```
|
||||||
|
|
||||||
## Functions
|
See: [Structs](http://elixir-lang.org/getting-started/structs.html)
|
||||||
|
|
||||||
### Function heads
|
|
||||||
|
|
||||||
```elixir
|
|
||||||
def join(a, b \\ nil)
|
|
||||||
def join(a, b) when is_nil(b) do: a
|
|
||||||
def join(a, b) do: a <> b
|
|
||||||
```
|
|
||||||
|
|
||||||
## Protocols
|
## Protocols
|
||||||
|
|
||||||
|
### Defining protocols
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
defprotocol Blank do
|
defprotocol Blank do
|
||||||
@doc "Returns true if data is considered blank/empty"
|
@doc "Returns true if data is considered blank/empty"
|
||||||
|
|
@ -330,6 +382,8 @@ end
|
||||||
|
|
||||||
## Comprehensions
|
## Comprehensions
|
||||||
|
|
||||||
|
### For
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
for n <- [1, 2, 3, 4], do: n * n
|
for n <- [1, 2, 3, 4], do: n * n
|
||||||
for n <- 1..4, do: n * n
|
for n <- 1..4, do: n * n
|
||||||
|
|
@ -356,7 +410,7 @@ for dir <- dirs,
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
## Modules
|
## Misc
|
||||||
|
|
||||||
### Metaprogramming
|
### Metaprogramming
|
||||||
|
|
||||||
|
|
@ -376,7 +430,7 @@ def on_def(_env, kind, name, args, guards, body)
|
||||||
def load_check
|
def load_check
|
||||||
```
|
```
|
||||||
|
|
||||||
## Regexp
|
### Regexp
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
exp = ~r/hello/
|
exp = ~r/hello/
|
||||||
|
|
@ -384,7 +438,7 @@ exp = ~r/hello/i
|
||||||
"hello world" =~ exp
|
"hello world" =~ exp
|
||||||
```
|
```
|
||||||
|
|
||||||
## [Sigils](http://elixir-lang.org/getting-started/sigils.html)
|
### Sigils
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
~r/regexp/
|
~r/regexp/
|
||||||
|
|
@ -394,11 +448,10 @@ exp = ~r/hello/i
|
||||||
~c(char list)
|
~c(char list)
|
||||||
```
|
```
|
||||||
|
|
||||||
Allowed chars: `/` `|` `"` `'` `(` `[` `{` `<` `"""`
|
Allowed chars: `/` `|` `"` `'` `(` `[` `{` `<` `"""`.
|
||||||
|
See: [Sigils](http://elixir-lang.org/getting-started/sigils.html)
|
||||||
|
|
||||||
## [Typespecs](http://elixir-lang.org/getting-started/typespecs-and-behaviours.html)
|
### Type specs
|
||||||
|
|
||||||
Useful for [dialyzer](http://www.erlang.org/doc/man/dialyzer.html)
|
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
@spec round(number) :: integer
|
@spec round(number) :: integer
|
||||||
|
|
@ -407,7 +460,10 @@ Useful for [dialyzer](http://www.erlang.org/doc/man/dialyzer.html)
|
||||||
@spec add(number, number) :: number_with_remark
|
@spec add(number, number) :: number_with_remark
|
||||||
```
|
```
|
||||||
|
|
||||||
## Behaviours
|
Useful for [dialyzer](http://www.erlang.org/doc/man/dialyzer.html).
|
||||||
|
See: [Typespecs](http://elixir-lang.org/getting-started/typespecs-and-behaviours.html)
|
||||||
|
|
||||||
|
### Behaviours
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
defmodule Parser do
|
defmodule Parser do
|
||||||
|
|
@ -425,9 +481,9 @@ defmodule JSONParser do
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
[Reference](http://elixir-lang.org/docs/stable/elixir/Module.html)
|
See: [Module](http://elixir-lang.org/docs/stable/elixir/Module.html)
|
||||||
|
|
||||||
## References
|
## References
|
||||||
|
{: .-one-column}
|
||||||
|
|
||||||
- [Learn Elixir in Y minutes](https://learnxinyminutes.com/docs/elixir/)
|
- [Learn Elixir in Y minutes](https://learnxinyminutes.com/docs/elixir/)
|
||||||
|
|
||||||
|
|
|
||||||
340
es6.md
340
es6.md
|
|
@ -1,16 +1,11 @@
|
||||||
---
|
---
|
||||||
title: ES2015
|
title: ES2015
|
||||||
category: JavaScript
|
category: JavaScript
|
||||||
layout: default-ad
|
layout: 2017/sheet
|
||||||
|
ads: true
|
||||||
---
|
---
|
||||||
|
|
||||||
## Stable in io.js
|
### Promises
|
||||||
|
|
||||||
New features you can use on [io.js](http://iojs.org/).
|
|
||||||
{:.brief-intro.center.top-space-0}
|
|
||||||
|
|
||||||
### [Promises](http://babeljs.io/docs/learn-es2015/#promises)
|
|
||||||
For asynchronous programming.
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
new Promise(fn)
|
new Promise(fn)
|
||||||
|
|
@ -25,42 +20,57 @@ Promise.reject(/*...*/)
|
||||||
Promise.resolve(/*...*/)
|
Promise.resolve(/*...*/)
|
||||||
```
|
```
|
||||||
|
|
||||||
### [Block scoping](http://babeljs.io/docs/learn-es2015/#let-const)
|
For asynchronous programming.
|
||||||
`let` is the new `var`.
|
See: [Promises](http://babeljs.io/docs/learn-es2015/#promises)
|
||||||
|
|
||||||
|
### Block scoping
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// Block scoping (let)
|
|
||||||
function fn () {
|
function fn () {
|
||||||
let x = 0;
|
let x = 0
|
||||||
if (true) {
|
if (true) {
|
||||||
let x = 1; // only inside this `if`
|
let x = 1 // only inside this `if`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
{: data-line="2,4"}
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// Constants
|
// Constants
|
||||||
const a = 1;
|
const a = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
### [Backtick strings](http://babeljs.io/docs/learn-es2015/#template-strings)
|
`let` is the new `var`.
|
||||||
Templates and multiline strings.
|
See: [Let and const](http://babeljs.io/docs/learn-es2015/#let-const)
|
||||||
|
|
||||||
|
### Backtick strings
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// Interpolation
|
// Interpolation
|
||||||
var message = `Hello ${name}`;
|
var message = `Hello ${name}`
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// Multiline
|
// Multiline strings
|
||||||
var str = `
|
var str = `
|
||||||
hello
|
hello
|
||||||
world
|
world
|
||||||
`;
|
`
|
||||||
```
|
```
|
||||||
|
|
||||||
### Other improvements
|
Templates and multiline strings.
|
||||||
New string [methods](http://babeljs.io/docs/learn-es2015/#math-number-string-object-apis), [binary and octal](http://babeljs.io/docs/learn-es2015/#binary-and-octal-literals) numbers.
|
See: [Template strings](http://babeljs.io/docs/learn-es2015/#template-strings)
|
||||||
|
|
||||||
|
### Binary and octal literals
|
||||||
|
|
||||||
|
```js
|
||||||
|
let bin = 0b1010010
|
||||||
|
let oct = 0755
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [Binary and octal literals](http://babeljs.io/docs/learn-es2015/#binary-and-octal-literals)
|
||||||
|
|
||||||
|
### New methods
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// New string methods
|
// New string methods
|
||||||
|
|
@ -69,134 +79,43 @@ New string [methods](http://babeljs.io/docs/learn-es2015/#math-number-string-obj
|
||||||
"\u1E9B\u0323".normalize("NFC")
|
"\u1E9B\u0323".normalize("NFC")
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
See: [New methods](http://babeljs.io/docs/learn-es2015/#math-number-string-object-apis)
|
||||||
// Binary/octal literals
|
|
||||||
var bin = 0b1010010;
|
|
||||||
var oct = 0755;
|
|
||||||
```
|
|
||||||
|
|
||||||
### [Object literal enhancements](http://babeljs.io/docs/learn-es2015/#enhanced-object-literals)
|
### Classes
|
||||||
Adds support for getters, setters, methods, shorthand.
|
|
||||||
|
|
||||||
```js
|
|
||||||
// Short object syntax
|
|
||||||
// aka: `exports = { hello:hello, bye:bye }`
|
|
||||||
module.exports = { hello, bye };
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
App = {
|
|
||||||
// shorthand for `handler: handler`
|
|
||||||
handler,
|
|
||||||
|
|
||||||
// methods
|
|
||||||
start() {
|
|
||||||
this.go();
|
|
||||||
},
|
|
||||||
|
|
||||||
// getter/setter
|
|
||||||
get closed() {
|
|
||||||
return this.status === 'closed';
|
|
||||||
},
|
|
||||||
|
|
||||||
// custom prototypes
|
|
||||||
__proto__: protoObj,
|
|
||||||
|
|
||||||
// computed property names
|
|
||||||
[ "prop_"+n ]: 42
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### [Generators](http://babeljs.io/docs/learn-es2015/#generators)
|
|
||||||
It's complicated.
|
|
||||||
|
|
||||||
```js
|
|
||||||
function* idMaker() {
|
|
||||||
var id = 0;
|
|
||||||
while (true) { yield id++; }
|
|
||||||
}
|
|
||||||
|
|
||||||
var gen = idMaker();
|
|
||||||
gen.next().value // 0
|
|
||||||
gen.next().value // 1
|
|
||||||
gen.next().value // 2
|
|
||||||
```
|
|
||||||
|
|
||||||
### [Classes](http://babeljs.io/docs/learn-es2015/#classes)
|
|
||||||
Syntactic sugar for prototypes.
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
class Circle extends Shape {
|
class Circle extends Shape {
|
||||||
// ctor
|
// ctor
|
||||||
constructor(radius) {
|
constructor (radius) {
|
||||||
this.radius = radius;
|
this.radius = radius
|
||||||
}
|
}
|
||||||
|
|
||||||
// methods
|
// methods
|
||||||
getArea() {
|
getArea () {
|
||||||
return Math.PI * 2 * this.radius;
|
return Math.PI * 2 * this.radius
|
||||||
}
|
}
|
||||||
|
|
||||||
// calling super methods
|
// calling super methods
|
||||||
expand(n) {
|
expand (n) {
|
||||||
return super.expand(n) * Math.PI;
|
return super.expand(n) * Math.PI
|
||||||
}
|
}
|
||||||
|
|
||||||
// static methods
|
// static methods
|
||||||
static createFromDiameter(diameter) {
|
static createFromDiameter(diameter) {
|
||||||
return new Circle(diameter / 2);
|
return new Circle(diameter / 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<br>
|
Syntactic sugar for prototypes.
|
||||||
|
See: [Classes](http://babeljs.io/docs/learn-es2015/#classes)
|
||||||
|
|
||||||
## Stable in Babel
|
### Destructuring
|
||||||
|
|
||||||
Available via the [Babel] transpiler.
|
|
||||||
{:.brief-intro.center.top-space-0}
|
|
||||||
|
|
||||||
### [Module imports](http://babeljs.io/docs/learn-es2015/#modules)
|
|
||||||
`import` is the new `require()`.
|
|
||||||
|
|
||||||
```js
|
|
||||||
// aka: require('...')
|
|
||||||
import 'helpers';
|
|
||||||
|
|
||||||
// aka: Express = require('...')
|
|
||||||
import Express from 'express';
|
|
||||||
|
|
||||||
// aka: indent = require('...').indent
|
|
||||||
import { indent } from 'helpers';
|
|
||||||
|
|
||||||
// aka: indent = require('...').indentSpaces
|
|
||||||
import { indentSpaces as indent } from 'helpers';
|
|
||||||
```
|
|
||||||
|
|
||||||
### [Module exports](http://babeljs.io/docs/learn-es2015/#modules)
|
|
||||||
`export` is the new `module.exports =`.
|
|
||||||
|
|
||||||
```js
|
|
||||||
// aka: module.exports = ...
|
|
||||||
export default function () {
|
|
||||||
// ...
|
|
||||||
};
|
|
||||||
|
|
||||||
// aka: exports.mymethod = ...
|
|
||||||
export function mymethod () {
|
|
||||||
};
|
|
||||||
|
|
||||||
// aka: exports.pi = ...
|
|
||||||
export var pi = 3.14159;
|
|
||||||
```
|
|
||||||
|
|
||||||
### [Destructuring](http://babeljs.io/docs/learn-es2015/#destructuring)
|
|
||||||
Supports for matching arrays and objects.
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// Destructuring assignment
|
// Destructuring assignment
|
||||||
var [first, last] = ["Nikola", "Tesla"];
|
var [first, last] = ['Nikola', 'Tesla']
|
||||||
let {title, author} = { title: "The Silkworm", author: "R. Galbraith" };
|
let {title, author} = { title: 'The Silkworm', author: 'R. Galbraith' }
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
|
@ -212,16 +131,21 @@ function greet({ name, greeting }) {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
greet({ name: "Larry", greeting: "Ahoy" });
|
greet({ name: 'Larry', greeting: 'Ahoy' })
|
||||||
```
|
```
|
||||||
|
|
||||||
### [Function arguments](http://babeljs.io/docs/learn-es2015/#default-rest-spread)
|
Supports for matching arrays and objects.
|
||||||
Default, rest, spread. (iojs: `--harmony-rest-parameters`)
|
See: [Destructuring](http://babeljs.io/docs/learn-es2015/#destructuring)
|
||||||
|
|
||||||
|
Functions
|
||||||
|
---------
|
||||||
|
|
||||||
|
### Function arguments
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// Default arguments
|
// Default arguments
|
||||||
function greet(name = "Jerry") {
|
function greet (name = "Jerry") {
|
||||||
return `Hello ${name}`;
|
return `Hello ${name}`
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -229,39 +153,174 @@ function greet(name = "Jerry") {
|
||||||
// Rest arguments
|
// Rest arguments
|
||||||
function fn(x, ...y) {
|
function fn(x, ...y) {
|
||||||
// y is an Array
|
// y is an Array
|
||||||
return x * y.length;
|
return x * y.length
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// Spread
|
// Spread
|
||||||
fn(...[1,2,3]) // same as fn(1,2,3)
|
fn(...[1, 2, 3]) // same as fn(1, 2, 3)
|
||||||
```
|
```
|
||||||
|
|
||||||
### [Fat arrows](http://babeljs.io/docs/learn-es2015/#arrows)
|
Default, rest, spread.
|
||||||
Like functions but with `this` preserved.
|
See: [Function arguments](http://babeljs.io/docs/learn-es2015/#default-rest-spread)
|
||||||
|
|
||||||
|
### Fat arrows
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// Fat arrows
|
// Fat arrows
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
...
|
...
|
||||||
});
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// With arguments
|
// With arguments
|
||||||
readFile('text.txt', (err, data) => {
|
readFile('text.txt', (err, data) => {
|
||||||
...
|
...
|
||||||
});
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// Short syntax (no `return` without `{}`)
|
// Short syntax (no `return` without `{}`)
|
||||||
numbers.map(n => n * 2)
|
numbers.map(n => n * 2)
|
||||||
|
// Same as: numbers.map(function (n) { return n * 2 })
|
||||||
```
|
```
|
||||||
|
|
||||||
### [For..of iteration](http://babeljs.io/docs/learn-es2015/#iterators-for-of)
|
Like functions but with `this` preserved.
|
||||||
For iterating through generators and arrays.
|
See: [Fat arrows](http://babeljs.io/docs/learn-es2015/#arrows)
|
||||||
|
|
||||||
|
Objects
|
||||||
|
-------
|
||||||
|
|
||||||
|
### Shorthand syntax
|
||||||
|
|
||||||
|
```js
|
||||||
|
module.exports = { hello, bye }
|
||||||
|
// Same as: module.exports = { hello: hello, bye: bye }
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [Object literal enhancements](http://babeljs.io/docs/learn-es2015/#enhanced-object-literals)
|
||||||
|
|
||||||
|
### Methods
|
||||||
|
|
||||||
|
```js
|
||||||
|
const App = {
|
||||||
|
start () {
|
||||||
|
console.log('running')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Same as: App = { start: function () {···} }
|
||||||
|
```
|
||||||
|
{: data-line="2"}
|
||||||
|
|
||||||
|
See: [Object literal enhancements](http://babeljs.io/docs/learn-es2015/#enhanced-object-literals)
|
||||||
|
|
||||||
|
### Getters and setters
|
||||||
|
|
||||||
|
```js
|
||||||
|
const App = {
|
||||||
|
get closed () {
|
||||||
|
return this.status === 'closed'
|
||||||
|
},
|
||||||
|
set closed (value) {
|
||||||
|
this.status === value ? 'closed' : 'open'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
{: data-line="2,5"}
|
||||||
|
|
||||||
|
See: [Object literal enhancements](http://babeljs.io/docs/learn-es2015/#enhanced-object-literals)
|
||||||
|
|
||||||
|
### Computed property names
|
||||||
|
|
||||||
|
```js
|
||||||
|
let event = 'click'
|
||||||
|
let handlers = {
|
||||||
|
['on' + event]: true
|
||||||
|
}
|
||||||
|
// Same as: handlers = { 'onclick': true }
|
||||||
|
```
|
||||||
|
{: data-line="3"}
|
||||||
|
|
||||||
|
See: [Object literal enhancements](http://babeljs.io/docs/learn-es2015/#enhanced-object-literals)
|
||||||
|
|
||||||
|
Modules
|
||||||
|
-------
|
||||||
|
|
||||||
|
### Imports
|
||||||
|
|
||||||
|
```js
|
||||||
|
import 'helpers'
|
||||||
|
// aka: require('···')
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
import Express from 'express'
|
||||||
|
// aka: Express = require('···').default || require('···')
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { indent } from 'helpers'
|
||||||
|
// aka: indent = require('···').indent
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
import * as Helpers from 'helpers'
|
||||||
|
// aka: Helpers = require('···')
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { indentSpaces as indent } from 'helpers'
|
||||||
|
// aka: indent = require('···').indentSpaces
|
||||||
|
```
|
||||||
|
|
||||||
|
`import` is the new `require()`.
|
||||||
|
See: [Module imports](http://babeljs.io/docs/learn-es2015/#modules)
|
||||||
|
|
||||||
|
### Exports
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default function () { ··· }
|
||||||
|
// aka: module.exports.default = ···
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
export function mymethod () { ··· }
|
||||||
|
// aka: module.exports.mymethod = ···
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
export const pi = 3.14159
|
||||||
|
// aka: module.exports.pi = ···
|
||||||
|
```
|
||||||
|
|
||||||
|
`export` is the new `module.exports`.
|
||||||
|
See: [Module exports](http://babeljs.io/docs/learn-es2015/#modules)
|
||||||
|
|
||||||
|
Generators
|
||||||
|
----------
|
||||||
|
|
||||||
|
### Generators
|
||||||
|
|
||||||
|
```js
|
||||||
|
function* idMaker () {
|
||||||
|
var id = 0
|
||||||
|
while (true) { yield id++ }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
var gen = idMaker()
|
||||||
|
gen.next().value // 0
|
||||||
|
gen.next().value // 1
|
||||||
|
gen.next().value // 2
|
||||||
|
```
|
||||||
|
|
||||||
|
It's complicated.
|
||||||
|
See: [Generators](http://babeljs.io/docs/learn-es2015/#generators)
|
||||||
|
|
||||||
|
### For..of iteration
|
||||||
|
|
||||||
```js
|
```js
|
||||||
for (let i of iterable) {
|
for (let i of iterable) {
|
||||||
|
|
@ -269,4 +328,5 @@ for (let i of iterable) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[Babel]: http://babeljs.io
|
For iterating through generators and arrays.
|
||||||
|
See: [For..of iteration](http://babeljs.io/docs/learn-es2015/#iterators-for-of)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
---
|
---
|
||||||
title: ExUnit
|
title: ExUnit
|
||||||
category: Elixir
|
category: Elixir
|
||||||
|
layout: 2017/sheet
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### Test cases
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
defmodule MyTest do
|
defmodule MyTest do
|
||||||
use ExUnit.Case
|
use ExUnit.Case
|
||||||
|
|
@ -43,7 +46,7 @@ defmodule AssertionTest do
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
### [Assertions](http://devdocs.io/elixir/ex_unit/exunit.assertions)
|
### Assertions
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
assert x == y
|
assert x == y
|
||||||
|
|
@ -57,8 +60,11 @@ assert_raise ArithmeticError, "message", fn -> ...
|
||||||
assert_raise ArithmeticError, ~r/message/, fn -> ...
|
assert_raise ArithmeticError, ~r/message/, fn -> ...
|
||||||
|
|
||||||
flunk "This should've been an error"
|
flunk "This should've been an error"
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [Assertions](http://devdocs.io/elixir/ex_unit/exunit.assertions)
|
||||||
|
|
||||||
## Also see
|
## Also see
|
||||||
|
{: .-one-column}
|
||||||
|
|
||||||
- <http://devdocs.io/elixir/ex_unit/exunit#configure/1>
|
- <http://devdocs.io/elixir/ex_unit/exunit#configure/1>
|
||||||
|
|
|
||||||
503
jekyll.md
503
jekyll.md
|
|
@ -1,12 +1,55 @@
|
||||||
---
|
---
|
||||||
title: Jekyll
|
title: Jekyll
|
||||||
jekyll_escape: true
|
jekyll_escape: true
|
||||||
|
layout: 2017/sheet
|
||||||
---
|
---
|
||||||
|
|
||||||
{% raw %}
|
{% raw %}
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
$ gem install jekyll
|
```bash
|
||||||
|
# Install the gems
|
||||||
|
gem install jekyll bundler
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create a new site at `./myblog`
|
||||||
|
jekyll new myblog
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd myblog
|
||||||
|
bundle exec jekyll serve
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [Jekyll quickstart](http://jekyllrb.com/docs/quickstart/)
|
||||||
|
|
||||||
|
### Installation (GitHub pages version)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Requires bundler
|
||||||
|
gem install bundler
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build the Gemfile
|
||||||
|
echo "source 'https://rubygems.org'" > Gemfile
|
||||||
|
echo "gem 'github-pages', group: :jekyll_plugins" >> Gemfile
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install gems
|
||||||
|
bundle
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Start server
|
||||||
|
bundle exec jekyll serve
|
||||||
|
```
|
||||||
|
|
||||||
|
This is the recommended setup, especially if you're using GitHub pages.
|
||||||
|
See: [github/pages-gem](https://github.com/github/pages-gem)
|
||||||
|
|
||||||
### Directories
|
### Directories
|
||||||
|
|
||||||
|
|
@ -33,13 +76,18 @@ jekyll_escape: true
|
||||||
└── _site/
|
└── _site/
|
||||||
└── ...
|
└── ...
|
||||||
|
|
||||||
## [Front-matter](http://jekyllrb.com/docs/frontmatter/)
|
## Front-matter
|
||||||
|
{: .-three-column}
|
||||||
|
|
||||||
|
### Basic frontmatter
|
||||||
|
|
||||||
---
|
---
|
||||||
layout: post
|
layout: post
|
||||||
title: Hello
|
title: Hello
|
||||||
---
|
---
|
||||||
|
|
||||||
|
See: [Front-matter](http://jekyllrb.com/docs/frontmatter/)
|
||||||
|
|
||||||
### Other frontmatter stuff
|
### Other frontmatter stuff
|
||||||
|
|
||||||
permalink: '/hello'
|
permalink: '/hello'
|
||||||
|
|
@ -48,86 +96,29 @@ jekyll_escape: true
|
||||||
categories: ['html', 'css']
|
categories: ['html', 'css']
|
||||||
tags: ['html', 'css']
|
tags: ['html', 'css']
|
||||||
|
|
||||||
## [Configuration](http://jekyllrb.com/docs/configuration/)
|
### Configuration
|
||||||
|
|
||||||
source: .
|
source: .
|
||||||
destination: _site
|
destination: _site
|
||||||
exclude: [dir, file, ...]
|
exclude: [dir, file, ...]
|
||||||
include: ['.htaccess']
|
include: ['.htaccess']
|
||||||
|
|
||||||
## [Variables](http://jekyllrb.com/docs/variables/)
|
See: [Configuration](http://jekyllrb.com/docs/configuration/)
|
||||||
|
|
||||||
{{ site }} - from config.yml
|
|
||||||
{{ page }} - from frontmatter, and page-specific info
|
|
||||||
{{ content }} - html content (use in layouts)
|
|
||||||
{{ paginator }} - ...
|
|
||||||
|
|
||||||
### Site
|
|
||||||
|
|
||||||
{{ site.time }} - current time
|
|
||||||
{{ site.pages }} - list of pages
|
|
||||||
{{ site.posts }} - list of posts
|
|
||||||
{{ site.related_posts }} - list
|
|
||||||
{{ site.categories.CATEGORY }} - list
|
|
||||||
{{ site.tags.TAG }} - list
|
|
||||||
|
|
||||||
{{ site.static_files }}
|
|
||||||
|
|
||||||
### Page
|
|
||||||
|
|
||||||
{{ page.content }} - un-rendered content
|
|
||||||
{{ page.title }}
|
|
||||||
{{ page.excerpt }} - un-rendered excerpt
|
|
||||||
{{ page.url }}
|
|
||||||
{{ page.date }}
|
|
||||||
{{ page.id }} - unique id for RSS feeds
|
|
||||||
{{ page.categories }}
|
|
||||||
{{ page.tags }}
|
|
||||||
{{ page.path }}
|
|
||||||
{{ post.excerpt | remove: '<p>' | remove: '</p>' }}
|
|
||||||
{{ post.excerpt | strip_html }}
|
|
||||||
|
|
||||||
<!-- blog pagination: -->
|
|
||||||
{{ page.next }}
|
|
||||||
{{ page.previous }}
|
|
||||||
|
|
||||||
### [Paginator](http://jekyllrb.com/docs/pagination/)
|
|
||||||
|
|
||||||
{{ paginator.page }} - page number
|
|
||||||
{{ paginator.total_posts }}
|
|
||||||
{{ paginator.total_pages }}
|
|
||||||
{{ paginator.per_page }}
|
|
||||||
|
|
||||||
{% for post in paginator.posts %} ... {% endfor %}
|
|
||||||
|
|
||||||
{% if paginator.previous_page %}
|
|
||||||
<a href="{{ paginator.previous_page_path }}">Previous</a>
|
|
||||||
{% else %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{{ paginator.next_page }} - page number
|
|
||||||
{{ paginator.next_page_path }}
|
|
||||||
...
|
|
||||||
|
|
||||||
{% if paginator.total_pages > 1 %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
Add this to `_config.yml`:
|
|
||||||
|
|
||||||
paginate: 5
|
|
||||||
paginate_path: "blog/:num"
|
|
||||||
|
|
||||||
### Code
|
|
||||||
|
|
||||||
{% highlight ruby linenos %}
|
|
||||||
def show
|
|
||||||
...
|
|
||||||
end
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
Markup
|
Markup
|
||||||
------
|
------
|
||||||
|
|
||||||
|
### Page variables
|
||||||
|
|
||||||
|
```html
|
||||||
|
<title>{{ page.title }}</title>
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- Filters -->
|
||||||
|
<p>{{ page.description | truncate_words: 20 }}
|
||||||
|
```
|
||||||
|
|
||||||
### Loops
|
### Loops
|
||||||
|
|
||||||
{% for post in site.posts %}
|
{% for post in site.posts %}
|
||||||
|
|
@ -150,37 +141,174 @@ Markup
|
||||||
|
|
||||||
### Includes (partials)
|
### Includes (partials)
|
||||||
|
|
||||||
{% include header.html %}
|
```
|
||||||
|
{% include header.html %}
|
||||||
|
```
|
||||||
|
|
||||||
## [Blogging](http://jekyllrb.com/docs/posts/)
|
```html
|
||||||
|
<!-- Including local vars -->
|
||||||
|
{% include header.html page=page %}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Comments
|
||||||
|
|
||||||
|
```html
|
||||||
|
{% comment %}
|
||||||
|
{% endcomment %}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Expression
|
||||||
|
|
||||||
|
### Top-level variables
|
||||||
|
|
||||||
|
{{ site }} - from config.yml
|
||||||
|
{{ page }} - from frontmatter, and page-specific info
|
||||||
|
{{ content }} - html content (use in layouts)
|
||||||
|
{{ paginator }} - ...
|
||||||
|
|
||||||
|
See: [Variables](http://jekyllrb.com/docs/variables/)
|
||||||
|
|
||||||
|
### Site
|
||||||
|
|
||||||
|
{{ site.time }} - current time
|
||||||
|
{{ site.pages }} - list of pages
|
||||||
|
{{ site.posts }} - list of posts
|
||||||
|
{{ site.related_posts }} - list
|
||||||
|
{{ site.categories.CATEGORY }} - list
|
||||||
|
{{ site.tags.TAG }} - list
|
||||||
|
|
||||||
|
{{ site.static_files }}
|
||||||
|
|
||||||
|
### Page
|
||||||
|
|
||||||
|
```html
|
||||||
|
{{ page.content }} - un-rendered content
|
||||||
|
{{ page.title }}
|
||||||
|
{{ page.excerpt }} - un-rendered excerpt
|
||||||
|
{{ page.url }}
|
||||||
|
{{ page.date }}
|
||||||
|
{{ page.id }} - unique id for RSS feeds
|
||||||
|
{{ page.categories }}
|
||||||
|
{{ page.tags }}
|
||||||
|
{{ page.path }}
|
||||||
|
{{ post.excerpt | remove: '<p>' | remove: '</p>' }}
|
||||||
|
{{ post.excerpt | strip_html }}
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- blog pagination: -->
|
||||||
|
{{ page.next }}
|
||||||
|
{{ page.previous }}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Paginator
|
||||||
|
|
||||||
|
### Paginator setup
|
||||||
|
|
||||||
|
Add this to `_config.yml`:
|
||||||
|
{: .-setup}
|
||||||
|
|
||||||
|
```yml
|
||||||
|
paginate: 5
|
||||||
|
paginate_path: "blog/:num"
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [Paginator](http://jekyllrb.com/docs/pagination/)
|
||||||
|
|
||||||
|
|
||||||
|
### Numbers
|
||||||
|
|
||||||
|
```
|
||||||
|
{{ paginator.page }} - page number
|
||||||
|
{{ paginator.total_posts }}
|
||||||
|
{{ paginator.total_pages }}
|
||||||
|
{{ paginator.per_page }}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Iterating through posts
|
||||||
|
|
||||||
|
```
|
||||||
|
{% for post in paginator.posts %} ... {% endfor %}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Previous button
|
||||||
|
|
||||||
|
```
|
||||||
|
{% if paginator.total_pages > 1 %}
|
||||||
|
{% if paginator.previous_page %}
|
||||||
|
<a href="{{ paginator.previous_page_path }}">Previous</a>
|
||||||
|
{% else %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
{{ paginator.next_page }} - page number
|
||||||
|
{{ paginator.next_page_path }}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Blogging
|
||||||
|
|
||||||
|
### Paths
|
||||||
|
|
||||||
_posts/YEAR-MONTH-DAY-title.md
|
_posts/YEAR-MONTH-DAY-title.md
|
||||||
|
|
||||||
### [Image paths](http://jekyllrb.com/docs/posts/#including-images-and-resources)
|
See: [Blogging](http://jekyllrb.com/docs/posts/)
|
||||||
|
|
||||||
|
### Image paths
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
### [Drafts](http://jekyllrb.com/docs/drafts/)
|
See: [Image paths](http://jekyllrb.com/docs/posts/#including-images-and-resources)
|
||||||
|
|
||||||
|
### Drafts
|
||||||
|
|
||||||
vi _drafts/a-draft-post.md
|
vi _drafts/a-draft-post.md
|
||||||
jekyll build --drafts
|
jekyll build --drafts
|
||||||
|
|
||||||
### [Excerpts](http://jekyllrb.com/docs/posts/#post-excerpts)
|
Posts in `_drafts` only show up in development, but not production.
|
||||||
|
See: [Drafts](http://jekyllrb.com/docs/drafts/)
|
||||||
|
|
||||||
{{ post.excerpt | remove: '<p>' | remove: '</p>' }}
|
### Defining excerpts
|
||||||
{{ post.excerpt | strip_html }}
|
|
||||||
|
```
|
||||||
|
---
|
||||||
|
title: My blog post
|
||||||
|
excerpt: This post is about cats
|
||||||
|
---
|
||||||
|
|
||||||
|
Hello, let's talk about cats. (···)
|
||||||
|
```
|
||||||
|
|
||||||
|
Put a key `excerpt` in the frontmatter.
|
||||||
|
See: [Excerpts](http://jekyllrb.com/docs/posts/#post-excerpts)
|
||||||
|
|
||||||
|
### Displaying excerpts
|
||||||
|
|
||||||
|
```html
|
||||||
|
{{ post.excerpt }}
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
{{ post.excerpt | remove: '<p>' | remove: '</p>' }}
|
||||||
|
{{ post.excerpt | strip_html }}
|
||||||
|
```
|
||||||
|
|
||||||
### Excerpt separator
|
### Excerpt separator
|
||||||
|
|
||||||
---
|
```html
|
||||||
excerpt_separator: <!--more-->
|
---
|
||||||
---
|
excerpt_separator: <!--more-->
|
||||||
|
---
|
||||||
|
|
||||||
Excerpt
|
Excerpt here
|
||||||
<!--more-->
|
<!--more-->
|
||||||
Out-of-excerpt
|
More post body here
|
||||||
|
```
|
||||||
|
|
||||||
### [Permalinks](http://jekyllrb.com/docs/permalinks/)
|
Alternatively, you can put excerpts inline in your post by defining `excerpt_separator`.
|
||||||
|
|
||||||
|
### Permalinks
|
||||||
|
|
||||||
# _config.yml
|
# _config.yml
|
||||||
permalink: date # /:categories/:year/:month/:day/:title.html
|
permalink: date # /:categories/:year/:month/:day/:title.html
|
||||||
|
|
@ -188,21 +316,35 @@ Markup
|
||||||
permalink: none # /:categories/:title.html
|
permalink: none # /:categories/:title.html
|
||||||
permalink: "/:title"
|
permalink: "/:title"
|
||||||
|
|
||||||
## [Data](http://jekyllrb.com/docs/datafiles/)
|
See: [Permalinks](http://jekyllrb.com/docs/permalinks/)
|
||||||
|
|
||||||
_data/members.yml
|
## More features
|
||||||
|
|
||||||
{% for member in site.data.members %}
|
### Data
|
||||||
|
|
||||||
## [Collections](http://jekyllrb.com/docs/collections/)
|
```
|
||||||
|
_data/members.yml
|
||||||
|
```
|
||||||
|
{: .-setup}
|
||||||
|
|
||||||
```yaml
|
```
|
||||||
|
{% for member in site.data.members %}
|
||||||
|
...
|
||||||
|
{% endfor %}
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [Data](http://jekyllrb.com/docs/datafiles/)
|
||||||
|
|
||||||
|
### Collections
|
||||||
|
|
||||||
|
```yml
|
||||||
# _config.yml
|
# _config.yml
|
||||||
collections:
|
collections:
|
||||||
- authors
|
- authors
|
||||||
```
|
```
|
||||||
|
{: .-setup}
|
||||||
|
|
||||||
```yaml
|
```yml
|
||||||
# _/authors/a-n-roquelaire.md
|
# _/authors/a-n-roquelaire.md
|
||||||
---
|
---
|
||||||
name: A. N. Roquelaire
|
name: A. N. Roquelaire
|
||||||
|
|
@ -214,79 +356,115 @@ real_name: Anne Rice
|
||||||
{% for author in site.authors %}
|
{% for author in site.authors %}
|
||||||
```
|
```
|
||||||
|
|
||||||
Helpers and Filters
|
See: [Collections](http://jekyllrb.com/docs/collections/)
|
||||||
|
|
||||||
|
Helpers and filters
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
### Dates
|
### Dates
|
||||||
|
|
||||||
{{ site.time | date_to_xmlschema }} #=> 2008-11-07T13:07:54-08:00
|
```
|
||||||
{{ site.time | date_to_rfc822 }} #=> Mon, 07 Nov 2008 13:07:54 -0800
|
{{ site.time | date_to_xmlschema }} #=> 2008-11-07T13:07:54-08:00
|
||||||
{{ site.time | date_to_string }} #=> 07 Nov 2008
|
{{ site.time | date_to_rfc822 }} #=> Mon, 07 Nov 2008 13:07:54 -0800
|
||||||
{{ site.time | date_to_long_string }} #=> 07 November 2008
|
{{ site.time | date_to_string }} #=> 07 Nov 2008
|
||||||
| date: "%Y %m %d"
|
{{ site.time | date_to_long_string }} #=> 07 November 2008
|
||||||
|
{{ site.time | date: "%Y %m %d" }}
|
||||||
|
```
|
||||||
|
|
||||||
### Preprocessors
|
### Preprocessors
|
||||||
|
|
||||||
| textilize
|
```
|
||||||
| markdownify
|
| textilize
|
||||||
| jsonify
|
| markdownify
|
||||||
| sassify
|
| jsonify
|
||||||
| scssify
|
| sassify
|
||||||
|
| scssify
|
||||||
|
```
|
||||||
|
|
||||||
### Array
|
### Array filters
|
||||||
|
|
||||||
site.posts | where:"year","2014"
|
```
|
||||||
site.posts | group_by:"genre" #=> { name, items }
|
site.posts | where:"year","2014"
|
||||||
site.posts | sort
|
site.posts | group_by:"genre" #=> { name, items }
|
||||||
|
site.posts | sort
|
||||||
|
```
|
||||||
|
|
||||||
| first
|
```
|
||||||
| last
|
| first
|
||||||
| join: ","
|
| last
|
||||||
| array_to_sentence_string #=> CSS, JavaScript and HTML
|
| join: ","
|
||||||
|
| array_to_sentence_string #=> CSS, JavaScript and HTML
|
||||||
|
```
|
||||||
|
|
||||||
| map: "post" # works like 'pluck'
|
```
|
||||||
| size
|
| map: "post" # works like 'pluck'
|
||||||
|
| size
|
||||||
|
```
|
||||||
|
|
||||||
### [String filters](http://docs.shopify.com/themes/liquid-documentation/filters)
|
### String filters
|
||||||
|
|
||||||
| default: "xxx"
|
```rb
|
||||||
|
| default: "xxx"
|
||||||
|
```
|
||||||
|
|
||||||
| upcase
|
```rb
|
||||||
| downcase
|
| upcase
|
||||||
|
| downcase
|
||||||
|
```
|
||||||
|
|
||||||
| remove: "<p>"
|
```rb
|
||||||
| replace: "super", "mega"
|
| remove: "<p>"
|
||||||
| remove_first: "<p>"
|
| replace: "super", "mega"
|
||||||
| replace_first: "super", "mega"
|
| remove_first: "<p>"
|
||||||
|
| replace_first: "super", "mega"
|
||||||
|
```
|
||||||
|
|
||||||
| truncate: 5
|
```rb
|
||||||
| truncatewords: 20
|
| truncate: 5
|
||||||
|
| truncatewords: 20
|
||||||
|
```
|
||||||
|
|
||||||
| prepend: "Mr. "
|
```rb
|
||||||
| append: " Sr."
|
| prepend: "Mr. "
|
||||||
|
| append: " Sr."
|
||||||
|
```
|
||||||
|
|
||||||
| camelize
|
```rb
|
||||||
| capitalize
|
| camelize
|
||||||
| pluralize
|
| capitalize
|
||||||
| strip_html
|
| pluralize
|
||||||
| strip_newlines
|
| strip_html
|
||||||
| newline_to_br
|
| strip_newlines
|
||||||
|
| newline_to_br
|
||||||
|
```
|
||||||
|
|
||||||
| split: ','
|
```rb
|
||||||
|
| split: ','
|
||||||
|
```
|
||||||
|
|
||||||
| escape
|
```rb
|
||||||
| escape_once
|
| escape
|
||||||
|
| escape_once
|
||||||
|
```
|
||||||
|
|
||||||
| slice: -3, 3
|
```rb
|
||||||
|
| slice: -3, 3
|
||||||
|
```
|
||||||
|
|
||||||
### String filters, Jekyll-only
|
See: [String filters](http://docs.shopify.com/themes/liquid-documentation/filters)
|
||||||
|
|
||||||
| number_of_words
|
### String filters (Jekyll-only)
|
||||||
| slugify
|
|
||||||
|
|
||||||
| xml_escape #=> CDATA
|
```
|
||||||
| cgi_escape #=> foo%2Cbar
|
| number_of_words
|
||||||
| uri_escape #=> foo,%20bar
|
| slugify
|
||||||
|
```
|
||||||
|
|
||||||
|
```rb
|
||||||
|
| xml_escape #=> CDATA
|
||||||
|
| cgi_escape #=> foo%2Cbar
|
||||||
|
| uri_escape #=> foo,%20bar
|
||||||
|
```
|
||||||
|
|
||||||
### Numbers
|
### Numbers
|
||||||
|
|
||||||
|
|
@ -295,33 +473,44 @@ Helpers and Filters
|
||||||
| time: 4
|
| time: 4
|
||||||
| divided_by: 3
|
| divided_by: 3
|
||||||
| modulo: 2
|
| modulo: 2
|
||||||
|
|
||||||
Comments
|
|
||||||
--------
|
|
||||||
|
|
||||||
{% comment %}
|
### Code highlighter
|
||||||
{% endcomment %}
|
|
||||||
|
```html
|
||||||
|
{% highlight ruby linenos %}
|
||||||
|
def show
|
||||||
|
...
|
||||||
|
end
|
||||||
|
{% endhighlight %}
|
||||||
|
```
|
||||||
|
|
||||||
Integration
|
Integration
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
### Bundler
|
### Bundler
|
||||||
|
|
||||||
# _plugins/bundler.rb
|
In `_plugins/bundler.rb`:
|
||||||
require "bunder/setup"
|
|
||||||
Bundler.require :default
|
```rb
|
||||||
|
require "bunder/setup"
|
||||||
|
Bundler.require :default
|
||||||
|
```
|
||||||
|
|
||||||
### Compass
|
### Compass
|
||||||
|
|
||||||
* [Compass](https://gist.github.com/parkr/2874934)
|
* [Compass](https://gist.github.com/parkr/2874934)
|
||||||
* [Asset pipeline](https://github.com/matthodan/jekyll-asset-pipeline)
|
* [Asset pipeline](https://github.com/matthodan/jekyll-asset-pipeline)
|
||||||
|
|
||||||
### References
|
Also see
|
||||||
|
--------
|
||||||
|
{: .-one-column}
|
||||||
|
|
||||||
|
* [Jekyll docs](http://jekyllrb.com/docs/home/) _jekyllrb.com_
|
||||||
|
* [Jekyll: templates](http://jekyllrb.com/docs/templates/) _jekyllrb.com_
|
||||||
|
* [Liquid: output](http://docs.shopify.com/themes/liquid-basics/output) _shopify.com_
|
||||||
|
* [Liquid: logic](http://docs.shopify.com/themes/liquid-basics/logic) _shopify.com_
|
||||||
|
* [Liquid: filters](http://docs.shopify.com/themes/liquid-documentation/filters) _shopify.com_
|
||||||
|
* [Liquid for designers](https://github.com/Shopify/liquid/wiki/Liquid-for-Designers) _github.com/Shopify_
|
||||||
|
{: .-also-see}
|
||||||
|
|
||||||
* http://jekyllrb.com/docs/home/
|
|
||||||
* http://jekyllrb.com/docs/templates/
|
|
||||||
* http://docs.shopify.com/themes/liquid-basics/output
|
|
||||||
* http://docs.shopify.com/themes/liquid-basics/logic
|
|
||||||
* https://github.com/Shopify/liquid/wiki/Liquid-for-Designers
|
|
||||||
* http://docs.shopify.com/themes/liquid-documentation/filters
|
|
||||||
{% endraw %}
|
{% endraw %}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,22 @@
|
||||||
---
|
---
|
||||||
title: Stream
|
title: Node.js streams
|
||||||
category: Node.js
|
category: Node.js
|
||||||
|
layout: 2017/sheet
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### Types
|
||||||
|
|
||||||
|
| Stream | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `Readable` | Data emitter |
|
||||||
|
| `Writable` | Data receiver |
|
||||||
|
| `Transform` | Emitter and receiver |
|
||||||
|
| `Duplex` | Emitter and receiver (independent) |
|
||||||
|
|
||||||
|
See: [Stream](https://nodejs.org/api/stream.html#stream_stream) _(nodejs.org)_
|
||||||
|
|
||||||
|
### Streams
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const Readable = require('stream').Readable
|
const Readable = require('stream').Readable
|
||||||
const Writable = require('stream').Writable
|
const Writable = require('stream').Writable
|
||||||
|
|
@ -12,36 +26,71 @@ const Transform = require('stream').Transform
|
||||||
### Piping
|
### Piping
|
||||||
|
|
||||||
```js
|
```js
|
||||||
clock() // Readable stream
|
clock() // Readable stream
|
||||||
.pipe(xformer()) // Transform stream
|
.pipe(xformer()) // Transform stream
|
||||||
.pipe(renderer()) // Writable stream
|
.pipe(renderer()) // Writable stream
|
||||||
```
|
```
|
||||||
|
|
||||||
### Readable streams
|
### Methods
|
||||||
|
|
||||||
Readable streams are generators of data. Write data using `stream.push()`.
|
```js
|
||||||
|
stream.push(/*...*/) // Emit a chunk
|
||||||
|
stream.emit('error', error) // Raise an error
|
||||||
|
stream.push(null) // Close a stream
|
||||||
|
```
|
||||||
|
|
||||||
|
### Events
|
||||||
|
|
||||||
|
```js
|
||||||
|
const st = source()
|
||||||
|
st.on('data', (data) => { console.log('<-', data) })
|
||||||
|
st.on('error', (err) => { console.log('!', err.message) })
|
||||||
|
st.on('close', () => { console.log('** bye') })
|
||||||
|
st.on('finish', () => { console.log('** bye') })
|
||||||
|
```
|
||||||
|
|
||||||
|
Assuming `source()` is a readable stream.
|
||||||
|
|
||||||
|
### Flowing mode
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Toggle flowing mode
|
||||||
|
st.resume()
|
||||||
|
st.pause()
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Automatically turns on flowing mode
|
||||||
|
st.on('data', /*...*/)
|
||||||
|
```
|
||||||
|
|
||||||
|
Stream types
|
||||||
|
------------
|
||||||
|
{: .-three-column}
|
||||||
|
|
||||||
|
### Readable
|
||||||
|
|
||||||
```js
|
```js
|
||||||
function clock () {
|
function clock () {
|
||||||
const stream = new Readable({
|
const stream = new Readable({
|
||||||
objectMode: true,
|
objectMode: true,
|
||||||
read: () => {} // implement this if you need on-demand reading
|
read() {}
|
||||||
})
|
})
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
stream.push({ time: new Date() })
|
stream.push({ time: new Date() })
|
||||||
|
|
||||||
if (error) return stream.emit('error', error)
|
|
||||||
if (eof) return stream.push(null)
|
|
||||||
}, 1000)
|
}, 1000)
|
||||||
|
|
||||||
return stream
|
return stream
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implement read() if you
|
||||||
|
// need on-demand reading.
|
||||||
```
|
```
|
||||||
|
|
||||||
### Transform streams
|
Readable streams are generators of data. Write data using `stream.push()`.
|
||||||
|
|
||||||
Pass the updated chunk to `done(null, chunk)`.
|
### Transform
|
||||||
|
|
||||||
```js
|
```js
|
||||||
function xformer () {
|
function xformer () {
|
||||||
|
|
@ -50,13 +99,15 @@ function xformer () {
|
||||||
return new Transform({
|
return new Transform({
|
||||||
objectMode: true,
|
objectMode: true,
|
||||||
transform: (data, _, done) => {
|
transform: (data, _, done) => {
|
||||||
done(null, { time: data.time, index: count++ })
|
done(null, { ...data, index: count++ })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Writable streams
|
Pass the updated chunk to `done(null, chunk)`.
|
||||||
|
|
||||||
|
### Writable
|
||||||
|
|
||||||
```js
|
```js
|
||||||
function renderer () {
|
function renderer () {
|
||||||
|
|
@ -70,14 +121,16 @@ function renderer () {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Reading
|
### All together now
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const st = source()
|
clock() // Readable stream
|
||||||
st.on('data', (data) => { console.log('<-', data) })
|
.pipe(xformer()) // Transform stream
|
||||||
st.on('close', () => { console.log('** bye') })
|
.pipe(renderer()) // Writable stream
|
||||||
```
|
```
|
||||||
|
|
||||||
## Also see
|
## Also see
|
||||||
|
{: .-one-column}
|
||||||
|
|
||||||
|
- <https://nodejs.org/api/stream.html>
|
||||||
- <https://github.com/substack/stream-handbook>
|
- <https://github.com/substack/stream-handbook>
|
||||||
|
|
|
||||||
76
rdoc.md
76
rdoc.md
|
|
@ -1,6 +1,7 @@
|
||||||
---
|
---
|
||||||
title: Rdoc
|
title: Rdoc
|
||||||
category: Markup
|
category: Markup
|
||||||
|
layout: 2017/sheet
|
||||||
---
|
---
|
||||||
|
|
||||||
### Basic RDoc format
|
### Basic RDoc format
|
||||||
|
|
@ -17,31 +18,45 @@ category: Markup
|
||||||
# @see http://url.com
|
# @see http://url.com
|
||||||
#
|
#
|
||||||
# @return [true] if so
|
# @return [true] if so
|
||||||
#
|
|
||||||
# == Definition lists
|
|
||||||
#
|
|
||||||
# list:: hi.
|
|
||||||
# +foo+:: parameterized
|
|
||||||
#
|
|
||||||
# == Definition lists
|
|
||||||
# [foo] also
|
|
||||||
# [bar] like this
|
|
||||||
|
|
||||||
### Inline
|
### Inline
|
||||||
|
|
||||||
*bold*
|
```
|
||||||
_emphasized_
|
*bold*
|
||||||
+code+
|
_emphasized_
|
||||||
|
+code+
|
||||||
|
```
|
||||||
|
|
||||||
http://www.link.com
|
```
|
||||||
See Models::User@Examples
|
http://www.link.com
|
||||||
{Google}[http://google.com]
|
See Models::User@Examples
|
||||||
|
{Google}[http://google.com]
|
||||||
|
```
|
||||||
|
|
||||||
### Skip
|
### Skip
|
||||||
|
|
||||||
def input # :nodoc:
|
```rb
|
||||||
|
def input # :nodoc:
|
||||||
|
```
|
||||||
|
|
||||||
module MyModule # :nodoc: all
|
```rb
|
||||||
|
module MyModule # :nodoc: all
|
||||||
|
```
|
||||||
|
|
||||||
|
### Definition lists
|
||||||
|
|
||||||
|
```
|
||||||
|
# == Definition lists
|
||||||
|
#
|
||||||
|
# list:: hi.
|
||||||
|
# +foo+:: parameterized
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
# == Definition lists
|
||||||
|
# [foo] also
|
||||||
|
# [bar] like this
|
||||||
|
```
|
||||||
|
|
||||||
### Return types
|
### Return types
|
||||||
|
|
||||||
|
|
@ -65,17 +80,26 @@ category: Markup
|
||||||
|
|
||||||
### Sections
|
### Sections
|
||||||
|
|
||||||
# :section: Expiry methods
|
```rb
|
||||||
# methods relating to expiring
|
# :section: Expiry methods
|
||||||
|
# methods relating to expiring
|
||||||
|
|
||||||
def expire!
|
def expire!
|
||||||
def expired?
|
def expired?
|
||||||
...
|
...
|
||||||
|
```
|
||||||
|
|
||||||
### Using tomdoc
|
### Using tomdoc
|
||||||
|
|
||||||
# :markup: TomDoc
|
```
|
||||||
# at the beginning ofthe file
|
# :markup: TomDoc
|
||||||
|
```
|
||||||
|
|
||||||
http://rdoc.rubyforge.org/RDoc/Markup.html
|
Plase this at the beginning of the file.
|
||||||
http://www.rubydoc.info/gems/yard/file/docs/GettingStarted.md
|
|
||||||
|
## Also see
|
||||||
|
{: .-one-column}
|
||||||
|
|
||||||
|
* <http://rdoc.rubyforge.org/RDoc/Markup.html>
|
||||||
|
* <http://www.rubydoc.info/gems/yard/file/docs/GettingStarted.md>
|
||||||
|
{: .-also-see}
|
||||||
|
|
|
||||||
719
react.md
719
react.md
|
|
@ -1,416 +1,491 @@
|
||||||
---
|
---
|
||||||
title: React.js
|
title: React.js
|
||||||
category: React
|
category: React
|
||||||
layout: default-ad
|
layout: 2017/sheet
|
||||||
|
ads: true
|
||||||
---
|
---
|
||||||
|
|
||||||
{%raw%}
|
{%raw%}
|
||||||
|
|
||||||
Use the [React.js jsfiddle](http://jsfiddle.net/reactjs/69z2wepo/) to start hacking. (or the unofficial [jsbin](http://jsbin.com/yafixat/edit?js,output))
|
Components
|
||||||
{:.brief-intro.center}
|
----------
|
||||||
|
{: .-three-column}
|
||||||
|
|
||||||
```js
|
### Components
|
||||||
var Component = React.createClass({
|
{: .-prime}
|
||||||
render: function () {
|
|
||||||
return <div>Hello {this.props.name}</div>;
|
```jsx
|
||||||
|
import React from 'react'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
```
|
||||||
|
{: .-setup}
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class Hello extends React.Component {
|
||||||
|
render () {
|
||||||
|
return <div className='message-box'>
|
||||||
|
Hello {this.props.name}
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
ReactDOM.render(<Component name="John" />, document.body);
|
|
||||||
```
|
|
||||||
{:.light}
|
|
||||||
|
|
||||||
## Nesting
|
|
||||||
Nest components to separate concerns. See [multiple components](http://facebook.github.io/react/docs/multiple-components.html).
|
|
||||||
{:.center}
|
|
||||||
|
|
||||||
```js
|
|
||||||
var UserAvatar = React.createClass({...});
|
|
||||||
var UserProfile = React.createClass({...});
|
|
||||||
```
|
|
||||||
{:.light}
|
|
||||||
|
|
||||||
```js
|
|
||||||
var Info = React.createClass({
|
|
||||||
render() {
|
|
||||||
return <div>
|
|
||||||
<UserAvatar src={this.props.avatar} />
|
|
||||||
<UserProfile username={this.props.username} />
|
|
||||||
</div>;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## States & Properties
|
|
||||||
Use [props](https://facebook.github.io/react/docs/tutorial.html#using-props) (`this.props`) to access parameters passed from the parent.
|
|
||||||
Use [states](https://facebook.github.io/react/docs/tutorial.html#reactive-state) (`this.state`) to manage dynamic data.
|
|
||||||
{:.center}
|
|
||||||
|
|
||||||
```html
|
|
||||||
<MyComponent fullscreen={true} />
|
|
||||||
```
|
|
||||||
{:.light}
|
|
||||||
|
|
||||||
```js
|
|
||||||
// props
|
|
||||||
this.props.fullscreen //=> true
|
|
||||||
|
|
||||||
// state
|
|
||||||
this.setState({ username: 'rstacruz' });
|
|
||||||
this.replaceState({ ... });
|
|
||||||
this.state.username //=> 'rstacruz'
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
render: function () {
|
|
||||||
return <div className={this.props.fullscreen ? 'full' : ''}>
|
|
||||||
Welcome, {this.state.username}
|
|
||||||
</div>;
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Setting defaults
|
```jsx
|
||||||
Pre-populates `this.state.comments` and `this.props.name`.
|
const el = document.body
|
||||||
|
ReactDOM.render(<Hello name='John' />, el)
|
||||||
|
```
|
||||||
|
|
||||||
```js
|
Use the [React.js jsfiddle](http://jsfiddle.net/reactjs/69z2wepo/) to start hacking. (or the unofficial [jsbin](http://jsbin.com/yafixat/edit?js,output))
|
||||||
React.createClass({
|
|
||||||
getInitialState: function () {
|
|
||||||
return { comments: [] };
|
|
||||||
},
|
|
||||||
|
|
||||||
getDefaultProps: function () {
|
### Properties
|
||||||
return { name: "Hello" };
|
|
||||||
|
```html
|
||||||
|
<Video fullscreen={true} />
|
||||||
|
```
|
||||||
|
{: .-setup}
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
render () {
|
||||||
|
this.props.fullscreen
|
||||||
|
···
|
||||||
|
}
|
||||||
|
```
|
||||||
|
{: data-line="2"}
|
||||||
|
|
||||||
|
Use `this.props` to access properties passed to the component.
|
||||||
|
See: [Properties](https://facebook.github.io/react/docs/tutorial.html#using-props)
|
||||||
|
|
||||||
|
### States
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
this.setState({ username: 'rstacruz' })
|
||||||
|
```
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
render () {
|
||||||
|
this.state.username
|
||||||
|
···
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Use states (`this.state`) to manage dynamic data.
|
||||||
|
See: [States](https://facebook.github.io/react/docs/tutorial.html#reactive-state)
|
||||||
|
|
||||||
|
### Function components
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
function MyComponent ({ name }) {
|
||||||
|
return <div className='message-box'>
|
||||||
|
Hello {name}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Functional components have no state. Also, their `props` are passed as the first parameter to a function.
|
||||||
|
See: [Function and Class Components](https://facebook.github.io/react/docs/components-and-props.html#functional-and-class-components)
|
||||||
|
|
||||||
|
### Nesting
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class Info extends React.Component {
|
||||||
|
render () {
|
||||||
|
const { avatar, username } = this.props
|
||||||
|
|
||||||
|
return <div>
|
||||||
|
<UserAvatar src={avatar} />
|
||||||
|
<UserProfile username={username} />
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
);
|
}
|
||||||
|
```
|
||||||
|
{: data-line="6,7"}
|
||||||
|
|
||||||
|
Nest components to separate concerns. See: [Composing Components](https://facebook.github.io/react/docs/components-and-props.html#composing-components)
|
||||||
|
|
||||||
|
|
||||||
|
### Setting default props
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
Hello.defaultProps = {
|
||||||
|
color: 'blue'
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Component API
|
See: [defaultProps](https://facebook.github.io/react/docs/react-component.html#defaultprops)
|
||||||
|
|
||||||
These are methods available for `Component` instances. See [Component API](http://facebook.github.io/react/docs/component-api.html).
|
### Setting default state
|
||||||
{:.center}
|
|
||||||
|
|
||||||
```js
|
```jsx
|
||||||
ReactDOM.findDOMNode(c) // 0.14+
|
class Hello extends React.Component {
|
||||||
React.findDOMNode(c) // 0.13
|
constructor (props) {
|
||||||
c.getDOMNode() // 0.12 below
|
super(props)
|
||||||
|
this.state = { visible: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
{:.light}
|
{: data-line="4"}
|
||||||
|
|
||||||
```js
|
Set the default state in the `constructor()`.
|
||||||
c.forceUpdate()
|
|
||||||
c.isMounted()
|
|
||||||
|
|
||||||
c.state
|
### Children
|
||||||
c.props
|
|
||||||
|
|
||||||
c.setState({ ... })
|
```jsx
|
||||||
c.replaceState({ ... })
|
class AlertBox extends React.Component {
|
||||||
|
render () {
|
||||||
|
return <div className='alert-box'>
|
||||||
|
{this.props.children}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
{: data-line="4"}
|
||||||
|
|
||||||
c.setProps({ ... }) // for deprecation
|
```jsx
|
||||||
c.replaceProps({ ... }) // for deprecation
|
<AlertBox>
|
||||||
|
<h1>You have pending notifications</h1>
|
||||||
c.refs
|
</AlertBox>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Component specs
|
Children are passed as the `children` property.
|
||||||
Methods and properties you can override. See [component specs](http://facebook.github.io/react/docs/component-specs.html).
|
|
||||||
|
|
||||||
| Method | What |
|
### Component API
|
||||||
| ---- | ---- |
|
|
||||||
| [`render()`](http://facebook.github.io/react/docs/component-specs.html#render) | |
|
|
||||||
| ---- | ---- |
|
|
||||||
| [`getInitialState()`](http://facebook.github.io/react/docs/component-specs.html#getinitialstate) | |
|
|
||||||
| [`getDefaultProps()`](http://facebook.github.io/react/docs/component-specs.html#getdefaultprops) | |
|
|
||||||
| ---- | ---- |
|
|
||||||
| [`mixins: [ ... ]`](http://facebook.github.io/react/docs/component-specs.html#mixins) | Mixins ... [more](#mixins) |
|
|
||||||
| [`propTypes: { ... }`](http://facebook.github.io/react/docs/component-specs.html#proptypes) | Validation ... [more](#property-validation) |
|
|
||||||
| [`statics: { ... }`](http://facebook.github.io/react/docs/component-specs.html#statics) | Static methods |
|
|
||||||
| [`displayName: "..."`](http://facebook.github.io/react/docs/component-specs.html#displayname) | Automatically filled by JSX |
|
|
||||||
{:.greycode.no-head}
|
|
||||||
|
|
||||||
## Lifecycle
|
```jsx
|
||||||
|
this.forceUpdate()
|
||||||
|
```
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
this.setState({ ... })
|
||||||
|
```
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
this.state
|
||||||
|
this.props
|
||||||
|
```
|
||||||
|
|
||||||
|
These methods and properies are available for `Component` instances. See: [Component API](http://facebook.github.io/react/docs/component-api.html)
|
||||||
|
|
||||||
|
Lifecycle
|
||||||
|
---------
|
||||||
|
{: .-two-column}
|
||||||
|
|
||||||
### Mounting
|
### Mounting
|
||||||
Before initial rendering occurs. Add your DOM stuff on didMount (events, timers, etc). See [reference](http://facebook.github.io/react/docs/component-specs.html#mounting-componentwillmount).
|
|
||||||
|
|
||||||
| `componentWillMount()` | Before rendering (no DOM yet) |
|
| Method | Description |
|
||||||
| `componentDidMount()` | After rendering |
|
| --- | --- |
|
||||||
{:.greycode.no-head.lc}
|
| `constructor` _(props)_ | Before rendering [#](https://facebook.github.io/react/docs/react-component.html#constructor) |
|
||||||
|
| `componentWillMount()` | _Don't use this_ [#](https://facebook.github.io/react/docs/react-component.html#componentwillmount) |
|
||||||
|
| `render()` | Render [#](https://facebook.github.io/react/docs/react-component.html#render) |
|
||||||
|
| `componentDidMount()` | After rendering (DOM available) [#](https://facebook.github.io/react/docs/react-component.html#componentdidmount) |
|
||||||
|
| --- | --- |
|
||||||
|
| `componentWillUnmount()` | Before DOM removal [#](https://facebook.github.io/react/docs/react-component.html#componentwillunmount) |
|
||||||
|
|
||||||
<br>
|
Set initial the state on `constructor()`.
|
||||||
|
Add DOM event handlers, timers (etc) on `componentDidMount()`, then remove them on `componentWillUnmount()`.
|
||||||
|
|
||||||
### Updating
|
### Updating
|
||||||
Called when parents change properties and `.setState()`. These are not called for initial renders. See [reference](http://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops).
|
|
||||||
|
|
||||||
| `componentWillReceiveProps`*(newProps={})* | Use `setState()` here |
|
| Method | Description |
|
||||||
| `shouldComponentUpdate`*(newProps={}, newState={})* | Skips `render()` if returns false |
|
| --- | --- |
|
||||||
| `componentWillUpdate`*(newProps={}, newState={})* | Can't use `setState()` here |
|
| `componentWillReceiveProps` *(newProps)* | Use `setState()` here |
|
||||||
| `componentDidUpdate`*(prevProps={}, prevState={})* | Operate on the DOM here |
|
| `shouldComponentUpdate` *(newProps, newState)* | Skips `render()` if returns false |
|
||||||
{:.greycode.no-head.lc}
|
| `componentWillUpdate` *(newProps, newState)* | Can't use `setState()` here |
|
||||||
|
| `render()` | Render |
|
||||||
|
| `componentDidUpdate` *(prevProps, prevState)* | Operate on the DOM here |
|
||||||
|
|
||||||
<br>
|
Called when parents change properties and `.setState()`. These are not called for initial renders. See: [Reference](http://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops).
|
||||||
|
|
||||||
### Unmounting
|
DOM nodes
|
||||||
Clear your DOM stuff here (probably done on didMount). See [reference](http://facebook.github.io/react/docs/component-specs.html#unmounting-componentwillunmount).
|
---------
|
||||||
|
{: .-two-column}
|
||||||
| `componentWillUnmount()` | Invoked before DOM removal |
|
|
||||||
{:.greycode.no-head.lc}
|
|
||||||
|
|
||||||
<style>
|
|
||||||
table.lc { table-layout: fixed; }
|
|
||||||
table.lc tr>:nth-child(1) { width: 50%; }
|
|
||||||
table.lc tr>:nth-child(2) { text-align: right; }
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
### Example: loading data
|
|
||||||
See [initial AJAX data](http://facebook.github.io/react/tips/initial-ajax.html).
|
|
||||||
|
|
||||||
```js
|
|
||||||
React.createClass({
|
|
||||||
componentDidMount: function () {
|
|
||||||
$.get(this.props.url, function (data) {
|
|
||||||
this.setState(data);
|
|
||||||
}.bind(this));
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function () {
|
|
||||||
return <CommentList data={this.state.data} />
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## DOM nodes
|
|
||||||
|
|
||||||
### References
|
### References
|
||||||
Allows access to DOM nodes. See [References](http://facebook.github.io/react/docs/more-about-refs.html).
|
|
||||||
|
|
||||||
```html
|
```jsx
|
||||||
<input ref="myInput">
|
class MyComponent extends React.Component {
|
||||||
```
|
render () {
|
||||||
{:.light}
|
return <div>
|
||||||
|
<input ref={el => this.input = el} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
```js
|
componentDidMount () {
|
||||||
this.refs.myInput
|
this.input.focus()
|
||||||
ReactDOM.findDOMNode(this.refs.myInput).focus()
|
}
|
||||||
ReactDOM.findDOMNode(this.refs.myInput).value
|
|
||||||
```
|
|
||||||
|
|
||||||
### DOM Events
|
|
||||||
Add attributes like `onChange`. See [events](https://facebook.github.io/react/docs/events.html).
|
|
||||||
|
|
||||||
```html
|
|
||||||
<input type="text"
|
|
||||||
value={this.state.value}
|
|
||||||
onChange={this.handleChange} />
|
|
||||||
```
|
|
||||||
{:.light}
|
|
||||||
|
|
||||||
```js
|
|
||||||
handleChange: function(event) {
|
|
||||||
this.setState({ value: event.target.value });
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
{: data-line="4,9"}
|
||||||
|
|
||||||
### Two-way binding
|
Allows access to DOM nodes. See: [Refs and the DOM](https://facebook.github.io/react/docs/refs-and-the-dom.html)
|
||||||
Use [LinkedStateMixin](http://facebook.github.io/react/docs/two-way-binding-helpers.html) for easier two-way binding.
|
|
||||||
|
### DOM Events
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class MyComponent extends React.Component {
|
||||||
|
render () {
|
||||||
|
<input type="text"
|
||||||
|
value={this.state.value}
|
||||||
|
onChange={event => this.onChange(event)} />
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange (event) {
|
||||||
|
this.setState({ value: event.target.vlaue })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
{: data-line="5,9"}
|
||||||
|
|
||||||
|
Pass functions to attributes like `onChange`. See: [Events](https://facebook.github.io/react/docs/events.html)
|
||||||
|
|
||||||
|
## Other features
|
||||||
|
|
||||||
|
### Transfering props
|
||||||
|
|
||||||
```html
|
```html
|
||||||
Email: <input type="text" valueLink={this.linkState('email')} />
|
<VideoPlayer src="video.mp4" />
|
||||||
```
|
```
|
||||||
{:.light}
|
{: .-setup}
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class VideoPlayer extends React.Component {
|
||||||
|
render () {
|
||||||
|
return <VideoEmbed {...this.props} />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
{: data-line="3"}
|
||||||
|
|
||||||
|
Propagates `src="..."` down to the sub-component.
|
||||||
|
See [Transferring props](http://facebook.github.io/react/docs/transferring-props.html).
|
||||||
|
|
||||||
|
### Top-level API
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
React.createClass({ ... })
|
||||||
|
React.isValidElement(c)
|
||||||
|
```
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(<Component />, domnode, [callback])
|
||||||
|
ReactDOM.unmountComponentAtNode(domnode)
|
||||||
|
```
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOMServer.renderToString(<Component />)
|
||||||
|
ReactDOMServer.renderToStaticMarkup(<Component />)
|
||||||
|
```
|
||||||
|
|
||||||
|
JSX patterns
|
||||||
|
------------
|
||||||
|
{: .-two-column}
|
||||||
|
|
||||||
|
### Style shorthand
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
var style = { height: 10 }
|
||||||
|
return <div style={style}></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
return <div style={{ margin: 0, padding: 0 }}></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [Inline styles](https://facebook.github.io/react/tips/inline-styles.html)
|
||||||
|
|
||||||
|
### Inner HTML
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
function markdownify() { return "<p>...</p>"; }
|
||||||
|
<div dangerouslySetInnerHTML={{__html: markdownify()}} />
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [Dangerously set innerHTML](https://facebook.github.io/react/tips/dangerously-set-inner-html.html)
|
||||||
|
|
||||||
|
### Lists
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class TodoList extends React.Component {
|
||||||
|
render () {
|
||||||
|
const { items } = this.props
|
||||||
|
|
||||||
|
return <ul>
|
||||||
|
{items.map(item =>
|
||||||
|
<TodoItem item={item} key={item.key} />)}
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
{: data-line="6,7"}
|
||||||
|
|
||||||
|
Always supply a `key` property.
|
||||||
|
|
||||||
|
### Conditionals
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
<div>
|
||||||
|
{showPopup
|
||||||
|
? <Popup />
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
Property validation
|
||||||
|
-------------------
|
||||||
|
{: .-three-column}
|
||||||
|
|
||||||
|
### PropTypes
|
||||||
|
|
||||||
```js
|
```js
|
||||||
React.createClass({
|
import PropTypes from 'prop-types'
|
||||||
mixins: [React.addons.LinkedStateMixin]
|
|
||||||
});
|
|
||||||
```
|
```
|
||||||
|
{: .-setup}
|
||||||
|
|
||||||
```js
|
See: [Typechecking with PropTypes](https://facebook.github.io/react/docs/typechecking-with-proptypes.html)
|
||||||
this.state.email
|
|
||||||
```
|
|
||||||
|
|
||||||
## Property validation
|
| PropType | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `any` | Anything |
|
||||||
|
| --- | --- |
|
||||||
|
| `string` | |
|
||||||
|
| `number` | |
|
||||||
|
| `func` | Function |
|
||||||
|
| `bool` | True or false |
|
||||||
|
| --- | --- |
|
||||||
|
| `oneOf`_(any)_ | Enum types |
|
||||||
|
| `oneOfType`_(type array)_ | Union |
|
||||||
|
| --- | --- |
|
||||||
|
| `array` | |
|
||||||
|
| `arrayOf`_(...)_ | |
|
||||||
|
| --- | --- |
|
||||||
|
| `object` | |
|
||||||
|
| `objectOf`_(...)_ | Object with values of a certain type |
|
||||||
|
| `instanceOf`_(...)_ | Instance of a class |
|
||||||
|
| `shape`_(...)_ | |
|
||||||
|
| --- | --- |
|
||||||
|
| `element` | React element |
|
||||||
|
| `node` | DOM node |
|
||||||
|
| --- | --- |
|
||||||
|
| `.isRequired` | Required |
|
||||||
|
|
||||||
### Basic types
|
### Basic types
|
||||||
Primitive types: `.string`, `.number`, `.func`, and `.bool`. See [propTypes](http://facebook.github.io/react/docs/reusable-components.html#prop-validation).
|
|
||||||
|
|
||||||
```js
|
```jsx
|
||||||
React.createClass({
|
MyComponent.propTypes = {
|
||||||
propTypes: {
|
email: PropTypes.string,
|
||||||
email: React.PropTypes.string,
|
seats: PropTypes.number,
|
||||||
seats: React.PropTypes.number,
|
callback: PropTypes.func,
|
||||||
settings: React.PropTypes.object,
|
isClosed: PropTypes.bool,
|
||||||
callback: React.PropTypes.func,
|
any: PropTypes.any
|
||||||
isClosed: React.PropTypes.bool,
|
}
|
||||||
any: React.PropTypes.any,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Required types
|
### Required types
|
||||||
Add `.isRequired`.
|
|
||||||
|
|
||||||
```js
|
```jsx
|
||||||
propTypes: {
|
MyCo.propTypes = {
|
||||||
requiredFunc: React.PropTypes.func.isRequired,
|
name: PropTypes.string.isRequired
|
||||||
requiredAny: React.PropTypes.any.isRequired,
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### React elements
|
### Elements
|
||||||
Use `.element`, `.node`.
|
|
||||||
|
|
||||||
```js
|
```jsx
|
||||||
propTypes: {
|
MyCo.propTypes = {
|
||||||
element: React.PropTypes.element, // react element
|
// React element
|
||||||
node: React.PropTypes.node, // num, string, element
|
element: PropTypes.element,
|
||||||
// ...or array of those
|
|
||||||
|
// num, string, element, or an array of those
|
||||||
|
node: PropTypes.node
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Enumerables
|
### Enumerables (oneOf)
|
||||||
Use `.oneOf`, `.oneOfType`.
|
|
||||||
|
|
||||||
```
|
```jsx
|
||||||
propTypes: {
|
MyCo.propTypes = {
|
||||||
enum: React.PropTypes.oneOf(['M','F']), // enum
|
direction: PropTypes.oneOf([
|
||||||
union: React.PropTypes.oneOfType([ // any
|
'left', 'right'
|
||||||
React.PropTypes.string,
|
])
|
||||||
React.PropTypes.number ]),
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Arrays and objects
|
### Arrays and objects
|
||||||
Use `.array[Of]`, `.object[Of]`, `.instanceOf`, `.shape`.
|
|
||||||
|
|
||||||
```js
|
```jsx
|
||||||
propTypes: {
|
MyCo.propTypes = {
|
||||||
array: React.PropTypes.array,
|
list: PropTypes.array,
|
||||||
arrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
|
ages: PropTypes.arrayOf(PropTypes.number),
|
||||||
object: React.PropTypes.object,
|
user: PropTypes.object,
|
||||||
objectOf: React.PropTypes.objectOf(React.PropTypes.number),
|
user: PropTypes.objectOf(PropTypes.number),
|
||||||
|
message: PropTypes.instanceOf(Message)
|
||||||
message: React.PropTypes.instanceOf(Message),
|
}
|
||||||
|
|
||||||
object2: React.PropTypes.shape({
|
|
||||||
color: React.PropTypes.string,
|
|
||||||
size: React.PropTypes.number
|
|
||||||
}),
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Custom validation
|
```jsx
|
||||||
Supply your own function.
|
MyCo.propTypes = {
|
||||||
|
user: PropTypes.shape({
|
||||||
|
name: PropTypes.string,
|
||||||
|
age: PropTypes.number
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
```js
|
Use `.array[Of]`, `.object[Of]`, `.instanceOf`, `.shape`.
|
||||||
propTypes: {
|
|
||||||
customProp: function(props, propName, componentName) {
|
### Custom validation
|
||||||
if (!/matchme/.test(props[propName])) {
|
|
||||||
return new Error('Validation failed!');
|
```jsx
|
||||||
|
MyCo.propTypes = {
|
||||||
|
customProp: (props, key, componentName) => {
|
||||||
|
if (!/matchme/.test(props[key])) {
|
||||||
|
return new Error('Validation failed!')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Other features
|
Examples
|
||||||
|
--------
|
||||||
|
{: .-left-reference}
|
||||||
|
|
||||||
### Class set
|
### Basic example
|
||||||
Manipulate DOM classes with [classnames](https://www.npmjs.org/package/classnames), previously known as `React.addons.classSet`. See [Class set](http://facebook.github.io/react/docs/class-name-manipulation.html).
|
|
||||||
|
|
||||||
```js
|
```jsx
|
||||||
var cx = require('classnames');
|
import React from 'react'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
render: function() {
|
|
||||||
var classes = cx({
|
|
||||||
'message': true,
|
|
||||||
'message-important': this.props.isImportant,
|
|
||||||
'message-read': this.props.isRead
|
|
||||||
});
|
|
||||||
|
|
||||||
return <div className={classes}>Great Scott!</div>;
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Propagating properties
|
```jsx
|
||||||
See [Transferring props](http://facebook.github.io/react/docs/transferring-props.html).
|
class Hello extends React.Component {
|
||||||
|
render () {
|
||||||
```html
|
return <div className='message-box'>
|
||||||
<VideoPlayer src="video.mp4" />
|
Hello {this.props.name}
|
||||||
```
|
</div>
|
||||||
{:.light}
|
|
||||||
|
|
||||||
```js
|
|
||||||
var VideoPlayer = React.createClass({
|
|
||||||
render: function() {
|
|
||||||
/* propagates src="..." down to this sub component */
|
|
||||||
return <VideoEmbed {...this.props} controls='false' />;
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Mixins
|
|
||||||
See [addons](https://facebook.github.io/react/docs/addons.html) for some built-in mixins.
|
|
||||||
|
|
||||||
```js
|
|
||||||
var SetIntervalMixin = {
|
|
||||||
componentWillMount: function() { .. }
|
|
||||||
}
|
|
||||||
```
|
|
||||||
{:.light}
|
|
||||||
|
|
||||||
```js
|
|
||||||
var TickTock = React.createClass({
|
|
||||||
mixins: [SetIntervalMixin]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## [Top level API](https://facebook.github.io/react/docs/top-level-api.html)
|
```jsx
|
||||||
|
const el = document.body
|
||||||
```js
|
ReactDOM.render(<Hello name='John' />, el)
|
||||||
React.createClass({ ... })
|
|
||||||
|
|
||||||
React.isValidElement(c)
|
|
||||||
|
|
||||||
ReactDOM.findDOMNode(c) // 0.14+
|
|
||||||
ReactDOM.render(<Component />, domnode, [callback]) // 0.14+
|
|
||||||
ReactDOM.unmountComponentAtNode(domnode) // 0.14+
|
|
||||||
|
|
||||||
ReactDOMServer.renderToString(<Component />) // 0.14+
|
|
||||||
ReactDOMServer.renderToStaticMarkup(<Component />) // 0.14+
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## JSX patterns
|
Use the [React.js jsfiddle](http://jsfiddle.net/reactjs/69z2wepo/) to start hacking. (or the unofficial [jsbin](http://jsbin.com/yafixat/edit?js,output)).
|
||||||
|
|
||||||
### Style shorthand
|
### Try it
|
||||||
See [inline styles](https://facebook.github.io/react/tips/inline-styles.html).
|
|
||||||
|
|
||||||
```js
|
<iframe src="http://jsbin.com/yafixat/edit?js,output" height="400"></iframe>
|
||||||
var style = { backgroundImage: 'url(x.jpg)', height: 10 };
|
|
||||||
return <div style={style}></div>;
|
|
||||||
```
|
|
||||||
|
|
||||||
### InnerHTML
|
[Open in jsbin](http://jsbin.com/yafixat/edit?js,output)
|
||||||
See [dangerously set innerHTML](https://facebook.github.io/react/tips/dangerously-set-inner-html.html).
|
{: target="_blank"}
|
||||||
|
|
||||||
```js
|
Also see
|
||||||
function markdownify() { return "<p>...</p>"; }
|
--------
|
||||||
<div dangerouslySetInnerHTML={{__html: markdownify()}} />
|
{: .-one-column}
|
||||||
```
|
|
||||||
|
|
||||||
### Lists
|
* This reference was made for React v15.
|
||||||
|
* [React v0.14 cheatsheet](react@0.14.html) _Legacy version_
|
||||||
|
* [React website](http://facebook.github.io/react) _facebook.github.io_
|
||||||
|
{:.-also-see}
|
||||||
|
|
||||||
```js
|
|
||||||
var TodoList = React.createClass({
|
|
||||||
render: function() {
|
|
||||||
function item(itemText) {
|
|
||||||
return <li>{itemText}</li>;
|
|
||||||
};
|
|
||||||
return <ul>{this.props.items.map(item)}</ul>;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## See also
|
|
||||||
|
|
||||||
* [Animations](http://facebook.github.io/react/docs/animation.html)
|
|
||||||
{%endraw%}
|
{%endraw%}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,416 @@
|
||||||
|
---
|
||||||
|
title: React.js
|
||||||
|
category: React
|
||||||
|
layout: default-ad
|
||||||
|
---
|
||||||
|
|
||||||
|
{%raw%}
|
||||||
|
|
||||||
|
Use the [React.js jsfiddle](http://jsfiddle.net/reactjs/69z2wepo/) to start hacking. (or the unofficial [jsbin](http://jsbin.com/yafixat/edit?js,output))
|
||||||
|
{:.brief-intro.center}
|
||||||
|
|
||||||
|
```js
|
||||||
|
var Component = React.createClass({
|
||||||
|
render: function () {
|
||||||
|
return <div>Hello {this.props.name}</div>;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
ReactDOM.render(<Component name="John" />, document.body);
|
||||||
|
```
|
||||||
|
{:.light}
|
||||||
|
|
||||||
|
## Nesting
|
||||||
|
Nest components to separate concerns. See [multiple components](http://facebook.github.io/react/docs/multiple-components.html).
|
||||||
|
{:.center}
|
||||||
|
|
||||||
|
```js
|
||||||
|
var UserAvatar = React.createClass({...});
|
||||||
|
var UserProfile = React.createClass({...});
|
||||||
|
```
|
||||||
|
{:.light}
|
||||||
|
|
||||||
|
```js
|
||||||
|
var Info = React.createClass({
|
||||||
|
render() {
|
||||||
|
return <div>
|
||||||
|
<UserAvatar src={this.props.avatar} />
|
||||||
|
<UserProfile username={this.props.username} />
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## States & Properties
|
||||||
|
Use [props](https://facebook.github.io/react/docs/tutorial.html#using-props) (`this.props`) to access parameters passed from the parent.
|
||||||
|
Use [states](https://facebook.github.io/react/docs/tutorial.html#reactive-state) (`this.state`) to manage dynamic data.
|
||||||
|
{:.center}
|
||||||
|
|
||||||
|
```html
|
||||||
|
<MyComponent fullscreen={true} />
|
||||||
|
```
|
||||||
|
{:.light}
|
||||||
|
|
||||||
|
```js
|
||||||
|
// props
|
||||||
|
this.props.fullscreen //=> true
|
||||||
|
|
||||||
|
// state
|
||||||
|
this.setState({ username: 'rstacruz' });
|
||||||
|
this.replaceState({ ... });
|
||||||
|
this.state.username //=> 'rstacruz'
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
render: function () {
|
||||||
|
return <div className={this.props.fullscreen ? 'full' : ''}>
|
||||||
|
Welcome, {this.state.username}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Setting defaults
|
||||||
|
Pre-populates `this.state.comments` and `this.props.name`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
React.createClass({
|
||||||
|
getInitialState: function () {
|
||||||
|
return { comments: [] };
|
||||||
|
},
|
||||||
|
|
||||||
|
getDefaultProps: function () {
|
||||||
|
return { name: "Hello" };
|
||||||
|
}
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Component API
|
||||||
|
|
||||||
|
These are methods available for `Component` instances. See [Component API](http://facebook.github.io/react/docs/component-api.html).
|
||||||
|
{:.center}
|
||||||
|
|
||||||
|
```js
|
||||||
|
ReactDOM.findDOMNode(c) // 0.14+
|
||||||
|
React.findDOMNode(c) // 0.13
|
||||||
|
c.getDOMNode() // 0.12 below
|
||||||
|
```
|
||||||
|
{:.light}
|
||||||
|
|
||||||
|
```js
|
||||||
|
c.forceUpdate()
|
||||||
|
c.isMounted()
|
||||||
|
|
||||||
|
c.state
|
||||||
|
c.props
|
||||||
|
|
||||||
|
c.setState({ ... })
|
||||||
|
c.replaceState({ ... })
|
||||||
|
|
||||||
|
c.setProps({ ... }) // for deprecation
|
||||||
|
c.replaceProps({ ... }) // for deprecation
|
||||||
|
|
||||||
|
c.refs
|
||||||
|
```
|
||||||
|
|
||||||
|
### Component specs
|
||||||
|
Methods and properties you can override. See [component specs](http://facebook.github.io/react/docs/component-specs.html).
|
||||||
|
|
||||||
|
| Method | What |
|
||||||
|
| ---- | ---- |
|
||||||
|
| [`render()`](http://facebook.github.io/react/docs/component-specs.html#render) | |
|
||||||
|
| ---- | ---- |
|
||||||
|
| [`getInitialState()`](http://facebook.github.io/react/docs/component-specs.html#getinitialstate) | |
|
||||||
|
| [`getDefaultProps()`](http://facebook.github.io/react/docs/component-specs.html#getdefaultprops) | |
|
||||||
|
| ---- | ---- |
|
||||||
|
| [`mixins: [ ... ]`](http://facebook.github.io/react/docs/component-specs.html#mixins) | Mixins ... [more](#mixins) |
|
||||||
|
| [`propTypes: { ... }`](http://facebook.github.io/react/docs/component-specs.html#proptypes) | Validation ... [more](#property-validation) |
|
||||||
|
| [`statics: { ... }`](http://facebook.github.io/react/docs/component-specs.html#statics) | Static methods |
|
||||||
|
| [`displayName: "..."`](http://facebook.github.io/react/docs/component-specs.html#displayname) | Automatically filled by JSX |
|
||||||
|
{:.greycode.no-head}
|
||||||
|
|
||||||
|
## Lifecycle
|
||||||
|
|
||||||
|
### Mounting
|
||||||
|
Before initial rendering occurs. Add your DOM stuff on didMount (events, timers, etc). See [reference](http://facebook.github.io/react/docs/component-specs.html#mounting-componentwillmount).
|
||||||
|
|
||||||
|
| `componentWillMount()` | Before rendering (no DOM yet) |
|
||||||
|
| `componentDidMount()` | After rendering |
|
||||||
|
{:.greycode.no-head.lc}
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### Updating
|
||||||
|
Called when parents change properties and `.setState()`. These are not called for initial renders. See [reference](http://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops).
|
||||||
|
|
||||||
|
| `componentWillReceiveProps`*(newProps={})* | Use `setState()` here |
|
||||||
|
| `shouldComponentUpdate`*(newProps={}, newState={})* | Skips `render()` if returns false |
|
||||||
|
| `componentWillUpdate`*(newProps={}, newState={})* | Can't use `setState()` here |
|
||||||
|
| `componentDidUpdate`*(prevProps={}, prevState={})* | Operate on the DOM here |
|
||||||
|
{:.greycode.no-head.lc}
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### Unmounting
|
||||||
|
Clear your DOM stuff here (probably done on didMount). See [reference](http://facebook.github.io/react/docs/component-specs.html#unmounting-componentwillunmount).
|
||||||
|
|
||||||
|
| `componentWillUnmount()` | Invoked before DOM removal |
|
||||||
|
{:.greycode.no-head.lc}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
table.lc { table-layout: fixed; }
|
||||||
|
table.lc tr>:nth-child(1) { width: 50%; }
|
||||||
|
table.lc tr>:nth-child(2) { text-align: right; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### Example: loading data
|
||||||
|
See [initial AJAX data](http://facebook.github.io/react/tips/initial-ajax.html).
|
||||||
|
|
||||||
|
```js
|
||||||
|
React.createClass({
|
||||||
|
componentDidMount: function () {
|
||||||
|
$.get(this.props.url, function (data) {
|
||||||
|
this.setState(data);
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function () {
|
||||||
|
return <CommentList data={this.state.data} />
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## DOM nodes
|
||||||
|
|
||||||
|
### References
|
||||||
|
Allows access to DOM nodes. See [References](http://facebook.github.io/react/docs/more-about-refs.html).
|
||||||
|
|
||||||
|
```html
|
||||||
|
<input ref="myInput">
|
||||||
|
```
|
||||||
|
{:.light}
|
||||||
|
|
||||||
|
```js
|
||||||
|
this.refs.myInput
|
||||||
|
ReactDOM.findDOMNode(this.refs.myInput).focus()
|
||||||
|
ReactDOM.findDOMNode(this.refs.myInput).value
|
||||||
|
```
|
||||||
|
|
||||||
|
### DOM Events
|
||||||
|
Add attributes like `onChange`. See [events](https://facebook.github.io/react/docs/events.html).
|
||||||
|
|
||||||
|
```html
|
||||||
|
<input type="text"
|
||||||
|
value={this.state.value}
|
||||||
|
onChange={this.handleChange} />
|
||||||
|
```
|
||||||
|
{:.light}
|
||||||
|
|
||||||
|
```js
|
||||||
|
handleChange: function(event) {
|
||||||
|
this.setState({ value: event.target.value });
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Two-way binding
|
||||||
|
Use [LinkedStateMixin](http://facebook.github.io/react/docs/two-way-binding-helpers.html) for easier two-way binding.
|
||||||
|
|
||||||
|
```html
|
||||||
|
Email: <input type="text" valueLink={this.linkState('email')} />
|
||||||
|
```
|
||||||
|
{:.light}
|
||||||
|
|
||||||
|
```js
|
||||||
|
React.createClass({
|
||||||
|
mixins: [React.addons.LinkedStateMixin]
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
this.state.email
|
||||||
|
```
|
||||||
|
|
||||||
|
## Property validation
|
||||||
|
|
||||||
|
### Basic types
|
||||||
|
Primitive types: `.string`, `.number`, `.func`, and `.bool`. See [propTypes](http://facebook.github.io/react/docs/reusable-components.html#prop-validation).
|
||||||
|
|
||||||
|
```js
|
||||||
|
React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
email: React.PropTypes.string,
|
||||||
|
seats: React.PropTypes.number,
|
||||||
|
settings: React.PropTypes.object,
|
||||||
|
callback: React.PropTypes.func,
|
||||||
|
isClosed: React.PropTypes.bool,
|
||||||
|
any: React.PropTypes.any,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Required types
|
||||||
|
Add `.isRequired`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
propTypes: {
|
||||||
|
requiredFunc: React.PropTypes.func.isRequired,
|
||||||
|
requiredAny: React.PropTypes.any.isRequired,
|
||||||
|
```
|
||||||
|
|
||||||
|
### React elements
|
||||||
|
Use `.element`, `.node`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
propTypes: {
|
||||||
|
element: React.PropTypes.element, // react element
|
||||||
|
node: React.PropTypes.node, // num, string, element
|
||||||
|
// ...or array of those
|
||||||
|
```
|
||||||
|
|
||||||
|
### Enumerables
|
||||||
|
Use `.oneOf`, `.oneOfType`.
|
||||||
|
|
||||||
|
```
|
||||||
|
propTypes: {
|
||||||
|
enum: React.PropTypes.oneOf(['M','F']), // enum
|
||||||
|
union: React.PropTypes.oneOfType([ // any
|
||||||
|
React.PropTypes.string,
|
||||||
|
React.PropTypes.number ]),
|
||||||
|
```
|
||||||
|
|
||||||
|
### Arrays and objects
|
||||||
|
Use `.array[Of]`, `.object[Of]`, `.instanceOf`, `.shape`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
propTypes: {
|
||||||
|
array: React.PropTypes.array,
|
||||||
|
arrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
|
||||||
|
object: React.PropTypes.object,
|
||||||
|
objectOf: React.PropTypes.objectOf(React.PropTypes.number),
|
||||||
|
|
||||||
|
message: React.PropTypes.instanceOf(Message),
|
||||||
|
|
||||||
|
object2: React.PropTypes.shape({
|
||||||
|
color: React.PropTypes.string,
|
||||||
|
size: React.PropTypes.number
|
||||||
|
}),
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom validation
|
||||||
|
Supply your own function.
|
||||||
|
|
||||||
|
```js
|
||||||
|
propTypes: {
|
||||||
|
customProp: function(props, propName, componentName) {
|
||||||
|
if (!/matchme/.test(props[propName])) {
|
||||||
|
return new Error('Validation failed!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Other features
|
||||||
|
|
||||||
|
### Class set
|
||||||
|
Manipulate DOM classes with [classnames](https://www.npmjs.org/package/classnames), previously known as `React.addons.classSet`. See [Class set](http://facebook.github.io/react/docs/class-name-manipulation.html).
|
||||||
|
|
||||||
|
```js
|
||||||
|
var cx = require('classnames');
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
var classes = cx({
|
||||||
|
'message': true,
|
||||||
|
'message-important': this.props.isImportant,
|
||||||
|
'message-read': this.props.isRead
|
||||||
|
});
|
||||||
|
|
||||||
|
return <div className={classes}>Great Scott!</div>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Propagating properties
|
||||||
|
See [Transferring props](http://facebook.github.io/react/docs/transferring-props.html).
|
||||||
|
|
||||||
|
```html
|
||||||
|
<VideoPlayer src="video.mp4" />
|
||||||
|
```
|
||||||
|
{:.light}
|
||||||
|
|
||||||
|
```js
|
||||||
|
var VideoPlayer = React.createClass({
|
||||||
|
render: function() {
|
||||||
|
/* propagates src="..." down to this sub component */
|
||||||
|
return <VideoEmbed {...this.props} controls='false' />;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mixins
|
||||||
|
See [addons](https://facebook.github.io/react/docs/addons.html) for some built-in mixins.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var SetIntervalMixin = {
|
||||||
|
componentWillMount: function() { .. }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
{:.light}
|
||||||
|
|
||||||
|
```js
|
||||||
|
var TickTock = React.createClass({
|
||||||
|
mixins: [SetIntervalMixin]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## [Top level API](https://facebook.github.io/react/docs/top-level-api.html)
|
||||||
|
|
||||||
|
```js
|
||||||
|
React.createClass({ ... })
|
||||||
|
|
||||||
|
React.isValidElement(c)
|
||||||
|
|
||||||
|
ReactDOM.findDOMNode(c) // 0.14+
|
||||||
|
ReactDOM.render(<Component />, domnode, [callback]) // 0.14+
|
||||||
|
ReactDOM.unmountComponentAtNode(domnode) // 0.14+
|
||||||
|
|
||||||
|
ReactDOMServer.renderToString(<Component />) // 0.14+
|
||||||
|
ReactDOMServer.renderToStaticMarkup(<Component />) // 0.14+
|
||||||
|
```
|
||||||
|
|
||||||
|
## JSX patterns
|
||||||
|
|
||||||
|
### Style shorthand
|
||||||
|
See [inline styles](https://facebook.github.io/react/tips/inline-styles.html).
|
||||||
|
|
||||||
|
```js
|
||||||
|
var style = { backgroundImage: 'url(x.jpg)', height: 10 };
|
||||||
|
return <div style={style}></div>;
|
||||||
|
```
|
||||||
|
|
||||||
|
### InnerHTML
|
||||||
|
See [dangerously set innerHTML](https://facebook.github.io/react/tips/dangerously-set-inner-html.html).
|
||||||
|
|
||||||
|
```js
|
||||||
|
function markdownify() { return "<p>...</p>"; }
|
||||||
|
<div dangerouslySetInnerHTML={{__html: markdownify()}} />
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lists
|
||||||
|
|
||||||
|
```js
|
||||||
|
var TodoList = React.createClass({
|
||||||
|
render: function() {
|
||||||
|
function item(itemText) {
|
||||||
|
return <li>{itemText}</li>;
|
||||||
|
};
|
||||||
|
return <ul>{this.props.items.map(item)}</ul>;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## See also
|
||||||
|
|
||||||
|
* [Animations](http://facebook.github.io/react/docs/animation.html)
|
||||||
|
{%endraw%}
|
||||||
183
sass.md
183
sass.md
|
|
@ -1,10 +1,100 @@
|
||||||
---
|
---
|
||||||
title: Sass
|
title: Sass
|
||||||
category: CSS
|
category: CSS
|
||||||
|
layout: 2017/sheet
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Basics
|
||||||
|
{: .-three-column}
|
||||||
|
|
||||||
|
### Variables
|
||||||
|
|
||||||
|
```scss
|
||||||
|
$red: #833;
|
||||||
|
```
|
||||||
|
|
||||||
|
```scss
|
||||||
|
body {
|
||||||
|
color: $red;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Nesting
|
||||||
|
|
||||||
|
```scss
|
||||||
|
.markdown-body {
|
||||||
|
p {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Comments
|
||||||
|
|
||||||
|
```scss
|
||||||
|
/* Block comments */
|
||||||
|
// Line comments
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mixins
|
||||||
|
|
||||||
|
```scss
|
||||||
|
@mixin heading-font {
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```scss
|
||||||
|
h1 {
|
||||||
|
@include heading-font;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mixin properties
|
||||||
|
|
||||||
|
```scss
|
||||||
|
@mixin font-size($n) {
|
||||||
|
font-size: $n * 1.2em;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```scss
|
||||||
|
body {
|
||||||
|
@include font-size(2);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Extend
|
||||||
|
|
||||||
|
```scss
|
||||||
|
.button {
|
||||||
|
···
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```scss
|
||||||
|
.push-button {
|
||||||
|
@extend .button;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Composing
|
||||||
|
|
||||||
|
```scss
|
||||||
|
@import './other_sass_file`;
|
||||||
|
```
|
||||||
|
|
||||||
|
The `.scss` or `.sass` extension is optional.
|
||||||
|
|
||||||
## Color functions
|
## Color functions
|
||||||
|
|
||||||
|
### rgba
|
||||||
|
|
||||||
```scss
|
```scss
|
||||||
rgb(100, 120, 140)
|
rgb(100, 120, 140)
|
||||||
rgba(100, 120, 140, .5)
|
rgba(100, 120, 140, .5)
|
||||||
|
|
@ -14,7 +104,7 @@ rgba($color, .5)
|
||||||
### Mixing
|
### Mixing
|
||||||
|
|
||||||
```scss
|
```scss
|
||||||
mix($a, $b, 10%) /* 10% a, 90% b */
|
mix($a, $b, 10%) // 10% a, 90% b
|
||||||
```
|
```
|
||||||
|
|
||||||
### Modifying HSLA
|
### Modifying HSLA
|
||||||
|
|
@ -22,18 +112,24 @@ mix($a, $b, 10%) /* 10% a, 90% b */
|
||||||
```scss
|
```scss
|
||||||
darken($color, 5%)
|
darken($color, 5%)
|
||||||
lighten($color, 5%)
|
lighten($color, 5%)
|
||||||
|
```
|
||||||
|
|
||||||
|
```scss
|
||||||
saturate($color, 5%)
|
saturate($color, 5%)
|
||||||
desaturate($color, 5%)
|
desaturate($color, 5%)
|
||||||
grayscale($color)
|
grayscale($color)
|
||||||
|
```
|
||||||
|
|
||||||
|
```scss
|
||||||
adjust-hue($color, 15deg)
|
adjust-hue($color, 15deg)
|
||||||
compliment($color) /* like adjust-hue(_, 180deg) */
|
compliment($color) // like adjust-hue(_, 180deg)
|
||||||
invert($color)
|
invert($color)
|
||||||
|
```
|
||||||
|
|
||||||
fade-in($color, .5) /* aka opacify() */
|
```scss
|
||||||
fade-out($color, .5) /* aka transparentize() - halves the opacity */
|
fade-in($color, .5) // aka opacify()
|
||||||
rgba($color, .5) /* sets alpha to .5 */
|
fade-out($color, .5) // aka transparentize() - halves the opacity
|
||||||
|
rgba($color, .5) // sets alpha to .5
|
||||||
```
|
```
|
||||||
|
|
||||||
### Getting HSL values
|
### Getting HSL values
|
||||||
|
|
@ -42,28 +138,32 @@ rgba($color, .5) /* sets alpha to .5 */
|
||||||
hue($color)
|
hue($color)
|
||||||
saturation($color)
|
saturation($color)
|
||||||
lightness($color)
|
lightness($color)
|
||||||
alpha($color) /* aka opacity() */
|
alpha($color) // aka opacity()
|
||||||
```
|
```
|
||||||
|
|
||||||
### Full adjustments
|
### Adjustments
|
||||||
|
|
||||||
```scss
|
```scss
|
||||||
/* Changes by fixed amounts */
|
// Changes by fixed amounts
|
||||||
adjust-color($color, $blue: 5)
|
adjust-color($color, $blue: 5)
|
||||||
adjust-color($color, $lightness: -30%) /* like darken(_, 30%) */
|
adjust-color($color, $lightness: -30%) // like darken(_, 30%)
|
||||||
adjust-color($color, $alpha: -0.4) /* like fade-out(_, .4) */
|
adjust-color($color, $alpha: -0.4) // like fade-out(_, .4)
|
||||||
adjust-color($color, $hue: 30deg) /* like adjust-hue(_, 15deg) */
|
adjust-color($color, $hue: 30deg) // like adjust-hue(_, 15deg)
|
||||||
|
```
|
||||||
|
|
||||||
/* Changes via percentage */
|
```scss
|
||||||
|
// Changes via percentage
|
||||||
scale-color($color, $lightness: 50%)
|
scale-color($color, $lightness: 50%)
|
||||||
|
```
|
||||||
|
|
||||||
/* Changes one property completely */
|
```scss
|
||||||
|
// Changes one property completely
|
||||||
change-color($color, $hue: 180deg)
|
change-color($color, $hue: 180deg)
|
||||||
change-color($color, $blue: 250)
|
change-color($color, $blue: 250)
|
||||||
|
|
||||||
/* Supported: $red $green $blue $hue $saturation $lightness $alpha */
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Supported: `$red` `$green` `$blue` `$hue` `$saturation` `$lightness` `$alpha`
|
||||||
|
|
||||||
## Other functions
|
## Other functions
|
||||||
|
|
||||||
### Strings
|
### Strings
|
||||||
|
|
@ -71,20 +171,24 @@ change-color($color, $blue: 250)
|
||||||
```scss
|
```scss
|
||||||
unquote('hello')
|
unquote('hello')
|
||||||
quote(hello)
|
quote(hello)
|
||||||
|
```
|
||||||
|
|
||||||
|
```scss
|
||||||
to-upper-case(hello)
|
to-upper-case(hello)
|
||||||
to-lower-case(hello)
|
to-lower-case(hello)
|
||||||
|
```
|
||||||
|
|
||||||
|
```scss
|
||||||
str-length(hello world)
|
str-length(hello world)
|
||||||
str-slice(hello, 2, 5) /* "ello" - it's 1-based, not 0-based */
|
str-slice(hello, 2, 5) // "ello" - it's 1-based, not 0-based
|
||||||
str-insert("abcd", "X", 1) /* "Xabcd" */
|
str-insert("abcd", "X", 1) // "Xabcd"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Units
|
### Units
|
||||||
|
|
||||||
```scss
|
```scss
|
||||||
unit(3em) /* 'em' */
|
unit(3em) // 'em'
|
||||||
unitless(100px) /* false */
|
unitless(100px) // false
|
||||||
```
|
```
|
||||||
|
|
||||||
### Numbers
|
### Numbers
|
||||||
|
|
@ -94,27 +198,33 @@ floor(3.5)
|
||||||
ceil(3.5)
|
ceil(3.5)
|
||||||
round(3.5)
|
round(3.5)
|
||||||
abs(3.5)
|
abs(3.5)
|
||||||
|
```
|
||||||
|
|
||||||
|
```scss
|
||||||
min(1, 2, 3)
|
min(1, 2, 3)
|
||||||
max(1, 2, 3)
|
max(1, 2, 3)
|
||||||
|
```
|
||||||
|
|
||||||
percentage(.5) /* 50% */
|
```scss
|
||||||
random(3) /* 0..3 */
|
percentage(.5) // 50%
|
||||||
|
random(3) // 0..3
|
||||||
```
|
```
|
||||||
|
|
||||||
### Misc
|
### Misc
|
||||||
|
|
||||||
```scss
|
```scss
|
||||||
variable-exists(red) /* checks for $red */
|
variable-exists(red) // checks for $red
|
||||||
mixin-exists(red-text) /* checks for @mixin red-text */
|
mixin-exists(red-text) // checks for @mixin red-text
|
||||||
function-exists(redify)
|
function-exists(redify)
|
||||||
|
```
|
||||||
|
|
||||||
|
```scss
|
||||||
global-variable-exists(red)
|
global-variable-exists(red)
|
||||||
```
|
```
|
||||||
|
|
||||||
```scss
|
```scss
|
||||||
selector-append('.menu', 'li', 'a') /* .menu li a */
|
selector-append('.menu', 'li', 'a') // .menu li a
|
||||||
selector-nest('.menu', '&:hover li') /* .menu:hover li */
|
selector-nest('.menu', '&:hover li') // .menu:hover li
|
||||||
selector-extend(...)
|
selector-extend(...)
|
||||||
selector-parse(...)
|
selector-parse(...)
|
||||||
selector-replace(...)
|
selector-replace(...)
|
||||||
|
|
@ -123,10 +233,14 @@ selector-unify(...)
|
||||||
|
|
||||||
## Feature checks
|
## Feature checks
|
||||||
|
|
||||||
|
### Feature check
|
||||||
|
|
||||||
```scss
|
```scss
|
||||||
feature-exists(global-variable-shadowing)
|
feature-exists(global-variable-shadowing)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
* global-variable-shadowing
|
* global-variable-shadowing
|
||||||
* extend-selector-pseudoclass
|
* extend-selector-pseudoclass
|
||||||
* units-level-3
|
* units-level-3
|
||||||
|
|
@ -175,7 +289,9 @@ $i: 6;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Conditionals
|
## Other features
|
||||||
|
|
||||||
|
### Conditionals
|
||||||
|
|
||||||
```scss
|
```scss
|
||||||
@if $position == 'left' {
|
@if $position == 'left' {
|
||||||
|
|
@ -187,29 +303,29 @@ $i: 6;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Interpolation
|
### Interpolation
|
||||||
|
|
||||||
```scss
|
```scss
|
||||||
.#{$klass} { ... } /* Class */
|
.#{$klass} { ... } // Class
|
||||||
call($function-name) /* Functions */
|
call($function-name) // Functions
|
||||||
|
|
||||||
@media #{$tablet}
|
@media #{$tablet}
|
||||||
font: #{$size}/#{$line-height}
|
font: #{$size}/#{$line-height}
|
||||||
url("#{$background}.jpg")
|
url("#{$background}.jpg")
|
||||||
```
|
```
|
||||||
|
|
||||||
## Lists
|
### Lists
|
||||||
|
|
||||||
```scss
|
```scss
|
||||||
$list: (a b c);
|
$list: (a b c);
|
||||||
|
|
||||||
nth($list, 1) /* starts with 1 */
|
nth($list, 1) // starts with 1
|
||||||
length($list)
|
length($list)
|
||||||
|
|
||||||
@each $item in $list { ... }
|
@each $item in $list { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
## Maps
|
### Maps
|
||||||
|
|
||||||
```scss
|
```scss
|
||||||
$map: (key1: value1, key2: value2, key3: value3);
|
$map: (key1: value1, key2: value2, key3: value3);
|
||||||
|
|
@ -217,7 +333,8 @@ $map: (key1: value1, key2: value2, key3: value3);
|
||||||
map-get($map, key1)
|
map-get($map, key1)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Reference
|
## See also
|
||||||
|
{: .-one-column}
|
||||||
|
|
||||||
- <http://sass-lang.com/documentation/Sass/Script/Functions.html>
|
- <http://sass-lang.com/documentation/Sass/Script/Functions.html>
|
||||||
- <http://sass-lang.com/documentation/file.SASS_REFERENCE.html#sassscript>
|
- <http://sass-lang.com/documentation/file.SASS_REFERENCE.html#sassscript>
|
||||||
|
|
|
||||||
628
sh.md
628
sh.md
|
|
@ -1,261 +1,575 @@
|
||||||
---
|
---
|
||||||
title: Bash scripting
|
title: Bash scripting
|
||||||
category: CLI
|
category: CLI
|
||||||
|
layout: 2017/sheet
|
||||||
|
ads: true
|
||||||
---
|
---
|
||||||
|
|
||||||
### Pattern substitution
|
Getting started
|
||||||
|
---------------
|
||||||
|
{: .-three-column}
|
||||||
|
|
||||||
STR=/path/to/foo.c
|
### Example
|
||||||
|
|
||||||
echo ${STR%.c} #=> "/path/to/foo"
|
```bash
|
||||||
echo ${STR%.c}.o #=> "/path/to/foo.o"
|
#!/usr/bin/env bash
|
||||||
echo ${STR##*.} #=> "c" (extension)
|
|
||||||
|
|
||||||
BASE=${STR##*/} #=> "foo.c" (basepath)
|
NAME="John"
|
||||||
DIR=${SRC%$BASE} #=> "/path/to"
|
echo "Hello $NAME!"
|
||||||
|
```
|
||||||
|
|
||||||
### Substitutions by regex
|
### Variables
|
||||||
|
|
||||||
echo ${STR/hi/hello} # Replace first match
|
```bash
|
||||||
echo ${STR//hi/hello} # Replace all matches
|
NAME="John"
|
||||||
echo ${STR/#hi/hello} # ^hi
|
echo $NAME
|
||||||
echo ${STR/%hi/hello} # hi$
|
echo "$NAME"
|
||||||
|
echo "${NAME}!"
|
||||||
|
```
|
||||||
|
|
||||||
echo "${STR:0:3}" # .substr(0, 3) -- position, length
|
### String quotes
|
||||||
echo "${STR:-3:3}" # Negative position = from the right
|
|
||||||
|
|
||||||
echo ${#line} # Length of $line
|
```bash
|
||||||
|
NAME="John"
|
||||||
|
echo "Hi $NAME" #=> Hi John
|
||||||
|
echo 'Hi $NAME' #=> Hi $NAME
|
||||||
|
```
|
||||||
|
|
||||||
[ -z "$CC" ] && CC=gcc # CC ||= "gcc" assignment
|
### Shell execution
|
||||||
${CC:=gcc} # $CC || "gcc"
|
|
||||||
${CC:-gcc} # same as above
|
|
||||||
|
|
||||||
### Reading input
|
```bash
|
||||||
|
echo "I'm in $(pwd)"
|
||||||
|
echo "I'm in `pwd`"
|
||||||
|
# Same
|
||||||
|
```
|
||||||
|
|
||||||
echo -n "Proceed? [y/n]: "
|
See [Command substitution](http://wiki.bash-hackers.org/syntax/expansion/cmdsubst)
|
||||||
read ans
|
|
||||||
echo $ans
|
|
||||||
|
|
||||||
read -n 1 ans # Just one character
|
### Conditional execution
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git commit && git push
|
||||||
|
git commit || echo "Commit failed"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Functions
|
||||||
|
{: id='functions-example'}
|
||||||
|
|
||||||
|
```bash
|
||||||
|
get_name() {
|
||||||
|
echo "John"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "You are $(get_name)"
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [Functions](#functions)
|
||||||
|
|
||||||
|
### Conditionals
|
||||||
|
{: id='conditionals-example'}
|
||||||
|
|
||||||
|
```bash
|
||||||
|
if [ -z "$string" ]; then
|
||||||
|
echo "String is empty"
|
||||||
|
elsif [ -n "$string" ]; then
|
||||||
|
echo "String is not empty"
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [Conditionals](#conditionals)
|
||||||
|
|
||||||
|
### Strict mode
|
||||||
|
|
||||||
|
```bash
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [Unofficial bash strict mode](http://redsymbol.net/articles/unofficial-bash-strict-mode/)
|
||||||
|
|
||||||
|
### Brace expansion
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo {A,B}.js
|
||||||
|
```
|
||||||
|
|
||||||
|
| `{A,B}` | Same as `A B` |
|
||||||
|
| `{A,B}.js` | Same as `A.js B.js` |
|
||||||
|
| `{1..5}` | Same as `1 2 3 4 5` |
|
||||||
|
|
||||||
|
See: [Brace expansion](http://wiki.bash-hackers.org/syntax/expansion/brace)
|
||||||
|
|
||||||
|
|
||||||
|
Parameter expansions
|
||||||
|
--------------------
|
||||||
|
{: .-three-column}
|
||||||
|
|
||||||
|
### Basics
|
||||||
|
|
||||||
|
```bash
|
||||||
|
name="John"
|
||||||
|
echo ${name}
|
||||||
|
echo ${name/J/j} #=> "john" (substitution)
|
||||||
|
echo ${name:0:2} #=> "jo" (slicing)
|
||||||
|
echo ${food:-Cake} #=> $food or "Cake"
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
length=2
|
||||||
|
echo ${name:0:length} #=> "jo"
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [Parameter expansion](http://wiki.bash-hackers.org/syntax/pe)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
STR="/path/to/foo.cpp"
|
||||||
|
echo ${STR%.cpp} # /path/to/foo
|
||||||
|
echo ${STR%.cpp}.o # /path/to/foo.o
|
||||||
|
|
||||||
|
echo ${STR##*.} # cpp (extension)
|
||||||
|
echo ${STR##*/} # foo.cpp (basepath)
|
||||||
|
|
||||||
|
echo ${STR#*/} # path/to/foo.cpp
|
||||||
|
echo ${STR##*/} # foo.cpp
|
||||||
|
|
||||||
|
echo ${STR/foo/bar} # /path/to/bar.cpp
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
STR="Hello world"
|
||||||
|
echo ${STR:6:5} # "world"
|
||||||
|
echo ${STR:-5:5} # "world"
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
SRC="/path/to/foo.cpp"
|
||||||
|
BASE=${STR##*/} #=> "foo.cpp" (basepath)
|
||||||
|
DIR=${SRC%$BASE} #=> "/path/to" (dirpath)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Substitution
|
||||||
|
|
||||||
|
| Code | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `${FOO%suffix}` | Remove suffix |
|
||||||
|
| `${FOO#prefix}` | Remove prefix |
|
||||||
|
| --- | --- |
|
||||||
|
| `${FOO%%suffix}` | Remove long suffix |
|
||||||
|
| `${FOO##prefix}` | Remove long prefix |
|
||||||
|
| --- | --- |
|
||||||
|
| `${FOO/from/to}` | Replace first match |
|
||||||
|
| `${FOO//from/to}` | Replace all |
|
||||||
|
| --- | --- |
|
||||||
|
| `${FOO/%from/to}` | Replace suffix |
|
||||||
|
| `${FOO/#from/to}` | Replace prefix |
|
||||||
|
|
||||||
|
### Substrings
|
||||||
|
|
||||||
|
| `${FOO:0:3}` | Substring _(position, length)_ |
|
||||||
|
| `${FOO:-3:3}` | Substring from the right |
|
||||||
|
|
||||||
|
### Length
|
||||||
|
|
||||||
|
| `${#FOO}` | Length of `$FOO` |
|
||||||
|
|
||||||
|
### Default values
|
||||||
|
|
||||||
|
| `${FOO:-val}` | `$FOO`, or `val` if not set |
|
||||||
|
| `${FOO:=val}` | Set `$FOO` to `val` if not set |
|
||||||
|
| `${FOO:+val}` | `val` if `$FOO` is set |
|
||||||
|
| `${FOO:?message}` | Show error message ande xit if `$FOO` is not set |
|
||||||
|
|
||||||
|
The `:` is optional (eg, `${FOO=word}` works)
|
||||||
|
|
||||||
Loops
|
Loops
|
||||||
-----
|
-----
|
||||||
|
{: .-three-column}
|
||||||
|
|
||||||
### Basic for loop
|
### Basic for loop
|
||||||
|
|
||||||
for i in /etc/rc.*; do
|
```bash
|
||||||
echo $i
|
for i in /etc/rc.*; do
|
||||||
done
|
echo $i
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
### Ranges
|
### Ranges
|
||||||
|
|
||||||
for i in {1..5}; do
|
```bash
|
||||||
echo "Welcome $i"
|
for i in {1..5}; do
|
||||||
done
|
echo "Welcome $i"
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
### Reading lines
|
### Reading lines
|
||||||
|
|
||||||
cat file.txt | while read line; do
|
```bash
|
||||||
echo $line
|
cat file.txt | while read line; do
|
||||||
done
|
echo $line
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
### Forever
|
||||||
|
|
||||||
|
```bash
|
||||||
|
while true; do
|
||||||
|
···
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
Functions
|
Functions
|
||||||
---------
|
---------
|
||||||
|
{: .-three-column}
|
||||||
|
|
||||||
### Defining functions
|
### Defining functions
|
||||||
|
|
||||||
myfunc() { ... }
|
```bash
|
||||||
fuction myfunc { ... }
|
myfunc() {
|
||||||
fuction myfunc() { ... }
|
echo "hello $1"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Returning strings
|
```bash
|
||||||
|
# Same as above (alternate syntax)
|
||||||
|
function myfunc() {
|
||||||
|
echo "hello $1"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
myfunc() {
|
```bash
|
||||||
local myresult='some value'
|
myfunc "John"
|
||||||
echo $myresult
|
```
|
||||||
}
|
|
||||||
|
|
||||||
result=$(myfunc)
|
### Returning values
|
||||||
|
|
||||||
### Errors
|
```bash
|
||||||
|
myfunc() {
|
||||||
|
local myresult='some value'
|
||||||
|
echo $myresult
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
myfunc() { return 1; }
|
```bash
|
||||||
|
result=$(myfunc)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Raising errors
|
||||||
|
|
||||||
|
```bash
|
||||||
|
myfunc() {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
if myfunc; then
|
||||||
|
echo "success"
|
||||||
|
else
|
||||||
|
echo "failure"
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
### Arguments
|
### Arguments
|
||||||
|
|
||||||
$# # Number of arguments
|
| Expression | Description |
|
||||||
$* # All args
|
| --- | --- |
|
||||||
$1 # First argument
|
| `$#` | Number of arguments |
|
||||||
|
| `$*` | All arguments |
|
||||||
|
| `$@` | All arguments, starting from first |
|
||||||
|
| `$1` | First argument |
|
||||||
|
|
||||||
Ifs - files
|
See [Special parameters](http://wiki.bash-hackers.org/syntax/shellvars#special_parameters_and_shell_variables).
|
||||||
-----------
|
|
||||||
|
|
||||||
# File conditions
|
Conditionals
|
||||||
if [ -a FILE ]; then # -e exists -d directory -f file
|
------------
|
||||||
fi # -r readable -w writeable -x executable
|
{: .-three-column}
|
||||||
# -h symlink -s size > 0
|
|
||||||
|
|
||||||
# File comparisons
|
### Conditions
|
||||||
if [ FILE1 -nt FILE2 ] # -nt 1 more recent than 2
|
|
||||||
# -ot 2 more recent than 1
|
|
||||||
# -ef same files
|
|
||||||
|
|
||||||
Ifs
|
| Condition | Description |
|
||||||
---
|
| --- | --- |
|
||||||
|
| `[ -z STRING ]` | Empty string |
|
||||||
|
| `[ -n STRING ]` | Not empty string |
|
||||||
|
| --- | --- |
|
||||||
|
| `[ NUM -eq NUM ]` | Equal |
|
||||||
|
| `[ NUM -ne NUM ]` | Not equal |
|
||||||
|
| `[ NUM -lt NUM ]` | Less than |
|
||||||
|
| `[ NUM -le NUM ]` | Less than or equal |
|
||||||
|
| `[ NUM -gt NUM ]` | Greater than |
|
||||||
|
| `[ NUM -ge NUM ]` | Greater than or equal |
|
||||||
|
| --- | --- |
|
||||||
|
| `[[ STRING =~ STRING ]]` | Regexp |
|
||||||
|
| --- | --- |
|
||||||
|
| `(( NUM < NUM ))` | Numeric conditions |
|
||||||
|
|
||||||
# String
|
| Condition | Description |
|
||||||
if [ -z STRING ] # empty?
|
| --- | --- |
|
||||||
if [ -n STRING ] # not empty?
|
| `[ -o noclobber ]` | If OPTIONNAME is enabled |
|
||||||
|
| --- | --- |
|
||||||
|
| `[ ! EXPR ]` | Not |
|
||||||
|
| `[ X ] && [ Y ]` | And |
|
||||||
|
| `[ X ] || [ Y ]` | Or |
|
||||||
|
|
||||||
# Numeric
|
### File conditions
|
||||||
if [ $? -eq 0 ] # -eq -ne -lt -le -gt -ge
|
|
||||||
# $? is exit status by the way
|
|
||||||
|
|
||||||
# Etc
|
| Condition | Description |
|
||||||
if [ -o noclobber ] # if OPTIONNAME is enabled
|
| --- | --- |
|
||||||
if [ ! EXPR ] # not
|
| `[ -e FILE ]` | Exists |
|
||||||
if [ ONE -a TWO ] # and
|
| `[ -r FILE ]` | Readable |
|
||||||
if [ ONE -o TWO ] # or
|
| `[ -h FILE ]` | Symlink |
|
||||||
|
| `[ -d FILE ]` | Directory |
|
||||||
|
| `[ -w FILE ]` | Writable |
|
||||||
|
| `[ -s FILE ]` | Size is > 0 bytes |
|
||||||
|
| `[ -f FILE ]` | File |
|
||||||
|
| `[ -x FILE ]` | Executable |
|
||||||
|
| --- | --- |
|
||||||
|
| `[ FILE1 -nt FILE2 ]` | 1 is more recent than 2 |
|
||||||
|
| `[ FILE1 -ot FILE2 ]` | 2 is more recent than 1 |
|
||||||
|
| `[ FILE1 -ef FILE2 ]` | Same files |
|
||||||
|
|
||||||
# Regex
|
### Example
|
||||||
if [[ "A" =~ "." ]]
|
|
||||||
|
|
||||||
### Numeric comparisons
|
```bash
|
||||||
|
# String
|
||||||
|
if [ -z "$string" ]; then
|
||||||
|
echo "String is empty"
|
||||||
|
elsif [ -n "$string" ]; then
|
||||||
|
echo "String is not empty"
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
if (( $a < $b ))
|
```bash
|
||||||
|
# Combinations
|
||||||
|
if [ X ] && [ Y ]; then
|
||||||
|
...
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
### Unset variables
|
```bash
|
||||||
|
# Regex
|
||||||
|
if [[ "A" =~ "." ]]
|
||||||
|
```
|
||||||
|
|
||||||
Assume `$FOO` is not set. Doing *this* will result in *that*:
|
```bash
|
||||||
|
if (( $a < $b ))
|
||||||
|
```
|
||||||
|
|
||||||
${FOO:-word} # Returns word
|
```bash
|
||||||
${FOO:+word} # Returns empty, or word if set
|
if [ -e "file.txt" ]; then
|
||||||
${FOO:=word} # Sets parameter to word, returns word
|
echo "file exists"
|
||||||
${FOO:?message} # Echoes message and exits
|
fi
|
||||||
|
```
|
||||||
${FOO=word} # : is optional in all of the above
|
|
||||||
|
|
||||||
Numeric calculations
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
$((RANDOM%=200)) # Random number 0..200
|
|
||||||
$((a + 200)) # $ is optional
|
|
||||||
|
|
||||||
Arrays
|
Arrays
|
||||||
------
|
------
|
||||||
|
|
||||||
# Declaring using declare -a
|
### Defining arrays
|
||||||
declare -a Fruits=('Apple' 'Banana' 'Orange')
|
|
||||||
|
|
||||||
Fruits[0]="Apple"
|
```bash
|
||||||
Fruits[1]="Banana"
|
Fruits=('Apple' 'Banana' 'Orange')
|
||||||
Fruits[2]="Orange"
|
```
|
||||||
|
|
||||||
echo ${Fruits[0]} # Element #0
|
```bash
|
||||||
echo ${Fruits[@]} # All elements, space-separated
|
Fruits[0]="Apple"
|
||||||
echo ${#Fruits[@]} # Number of elements
|
Fruits[1]="Banana"
|
||||||
echo ${#Fruits} # String length of the 1st element
|
Fruits[2]="Orange"
|
||||||
echo ${#Fruits[3]} # String length of the Nth element
|
```
|
||||||
echo ${Fruits[@]:3:2} # Range (from position 3, length 2)
|
|
||||||
|
### Working with arrays
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo ${Fruits[0]} # Element #0
|
||||||
|
echo ${Fruits[@]} # All elements, space-separated
|
||||||
|
echo ${#Fruits[@]} # Number of elements
|
||||||
|
echo ${#Fruits} # String length of the 1st element
|
||||||
|
echo ${#Fruits[3]} # String length of the Nth element
|
||||||
|
echo ${Fruits[@]:3:2} # Range (from position 3, length 2)
|
||||||
|
```
|
||||||
|
|
||||||
### Operations
|
### Operations
|
||||||
|
|
||||||
Fruits=("${Fruits[@]}" "Watermelon") # Push
|
```bash
|
||||||
Fruits=( ${Fruits[@]/Ap*/} ) # Remove by regex match
|
Fruits=("${Fruits[@]}" "Watermelon") # Push
|
||||||
unset Fruits[2] # Remove one item
|
Fruits=( ${Fruits[@]/Ap*/} ) # Remove by regex match
|
||||||
Fruits=("${Fruits[@]}") # Duplicate
|
unset Fruits[2] # Remove one item
|
||||||
Fruits=("${Fruits[@]}" "${Veggies[@]}") # Concatenate
|
Fruits=("${Fruits[@]}") # Duplicate
|
||||||
lines=(`cat "logfile"`) # Read from file
|
Fruits=("${Fruits[@]}" "${Veggies[@]}") # Concatenate
|
||||||
|
lines=(`cat "logfile"`) # Read from file
|
||||||
|
```
|
||||||
|
|
||||||
### Iteration
|
### Iteration
|
||||||
|
|
||||||
for i in "${arrayName[@]}"; do
|
```bash
|
||||||
echo $i
|
for i in "${arrayName[@]}"; do
|
||||||
done
|
echo $i
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
Misc crap
|
Options
|
||||||
---------
|
-------
|
||||||
|
|
||||||
command -V cd #=> "cd is a function/alias/whatever"
|
|
||||||
|
|
||||||
### Options
|
### Options
|
||||||
|
|
||||||
set -o noclobber # Avoid overlay files (echo "hi" > foo)
|
```bash
|
||||||
set -o errexit # Used to exit upon error, avoiding cascading errors
|
set -o noclobber # Avoid overlay files (echo "hi" > foo)
|
||||||
set -o pipefail # Unveils hidden failures
|
set -o errexit # Used to exit upon error, avoiding cascading errors
|
||||||
set -o nounset # Exposes unset variables
|
set -o pipefail # Unveils hidden failures
|
||||||
|
set -o nounset # Exposes unset variables
|
||||||
|
```
|
||||||
|
|
||||||
### Glob options
|
### Glob options
|
||||||
|
|
||||||
set -o nullglob # Non-matching globs are removed ('*.foo' => '')
|
```bash
|
||||||
set -o failglob # Non-matching globs throw errors
|
set -o nullglob # Non-matching globs are removed ('*.foo' => '')
|
||||||
set -o nocaseglob # Case insensitive globs
|
set -o failglob # Non-matching globs throw errors
|
||||||
set -o globdots # Wildcards match dotfiles ("*.sh" => ".foo.sh")
|
set -o nocaseglob # Case insensitive globs
|
||||||
set -o globstar # Allow ** for recursive matches ('lib/**/*.rb' => 'lib/a/b/c.rb')
|
set -o globdots # Wildcards match dotfiles ("*.sh" => ".foo.sh")
|
||||||
|
set -o globstar # Allow ** for recursive matches ('lib/**/*.rb' => 'lib/a/b/c.rb')
|
||||||
|
```
|
||||||
|
|
||||||
set GLOBIGNORE as a colon-separated list of patterns to be removed from glob
|
Set `GLOBIGNORE` as a colon-separated list of patterns to be removed from glob
|
||||||
matches.
|
matches.
|
||||||
|
|
||||||
|
Miscellaneous
|
||||||
|
-------------
|
||||||
|
|
||||||
|
### Numeric calculations
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$((a + 200)) # Add 200 to $a
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$((RANDOM%=200)) # Random number 0..200
|
||||||
|
```
|
||||||
|
|
||||||
|
### Subshells
|
||||||
|
|
||||||
|
```bash
|
||||||
|
(cd somedir; echo "I'm now in $PWD")
|
||||||
|
pwd # still in first directory
|
||||||
|
```
|
||||||
|
|
||||||
|
### Redirection
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python hello.py > output.txt # stdout to (file)
|
||||||
|
python hello.py >> output.txt # stdout to (file), append
|
||||||
|
python hello.py 2> error.log # stderr to (file)
|
||||||
|
python hello.py 2>&1 # stderr to stdout
|
||||||
|
python hello.py 2>/dev/null # stderr to (null)
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python hello.py < foo.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Inspecting commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
command -V cd
|
||||||
|
#=> "cd is a function/alias/whatever"
|
||||||
|
```
|
||||||
|
|
||||||
### Trap errors
|
### Trap errors
|
||||||
|
|
||||||
trap 'echo Error at about $LINENO' ERR
|
```bash
|
||||||
|
trap 'echo Error at about $LINENO' ERR
|
||||||
|
```
|
||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
traperr() {
|
```bash
|
||||||
echo "ERROR: ${BASH_SOURCE[1]} at about ${BASH_LINENO[0]}"
|
traperr() {
|
||||||
}
|
echo "ERROR: ${BASH_SOURCE[1]} at about ${BASH_LINENO[0]}"
|
||||||
|
}
|
||||||
|
|
||||||
set -o errtrace
|
set -o errtrace
|
||||||
trap traperr ERR
|
trap traperr ERR
|
||||||
|
```
|
||||||
|
|
||||||
### Case/switch
|
### Case/switch
|
||||||
|
|
||||||
case $1 in
|
```bash
|
||||||
start | up)
|
case "$1" in
|
||||||
vagrant up
|
start | up)
|
||||||
;;
|
vagrant up
|
||||||
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
echo "Usage: $0 {start|stop|ssh}"
|
echo "Usage: $0 {start|stop|ssh}"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
```
|
||||||
|
|
||||||
### Source relative
|
### Source relative
|
||||||
|
|
||||||
source "${0%/*}/../share/foo.sh"
|
```bash
|
||||||
|
source "${0%/*}/../share/foo.sh"
|
||||||
|
```
|
||||||
|
|
||||||
### printf
|
### printf
|
||||||
|
|
||||||
printf "Hello %s, I'm %s" Sven Olga
|
```bash
|
||||||
|
printf "Hello %s, I'm %s" Sven Olga
|
||||||
|
#=> "Hello Sven, I'm Olga
|
||||||
|
```
|
||||||
|
|
||||||
### Directory of script
|
### Directory of script
|
||||||
|
|
||||||
DIR="${0%/*}"
|
```bash
|
||||||
|
DIR="${0%/*}"
|
||||||
|
```
|
||||||
|
|
||||||
### Getting options
|
### Getting options
|
||||||
|
|
||||||
while [[ "$1" =~ ^- && ! "$1" == "--" ]]; do case $1 in
|
```bash
|
||||||
-V | --version )
|
while [[ "$1" =~ ^- && ! "$1" == "--" ]]; do case $1 in
|
||||||
echo $version
|
-V | --version )
|
||||||
exit
|
echo $version
|
||||||
;;
|
exit
|
||||||
-s | --string )
|
;;
|
||||||
shift; string=$1
|
-s | --string )
|
||||||
;;
|
shift; string=$1
|
||||||
-f | --flag )
|
;;
|
||||||
flag=1
|
-f | --flag )
|
||||||
;;
|
flag=1
|
||||||
esac; shift; done
|
;;
|
||||||
if [[ "$1" == '--' ]]; then shift; fi
|
esac; shift; done
|
||||||
|
if [[ "$1" == '--' ]]; then shift; fi
|
||||||
|
```
|
||||||
|
|
||||||
### Heredoc
|
### Heredoc
|
||||||
|
|
||||||
cat <<END
|
```sh
|
||||||
hello world
|
cat <<END
|
||||||
END
|
hello world
|
||||||
|
END
|
||||||
|
```
|
||||||
|
|
||||||
## Reference
|
### Reading input
|
||||||
|
|
||||||
* [Bash-hackers wiki](http://wiki.bash-hackers.org/) (back-hackers.org)
|
```bash
|
||||||
* [Shell vars](http://wiki.bash-hackers.org/syntax/shellvars) (back-hackers.org)
|
echo -n "Proceed? [y/n]: "
|
||||||
|
read ans
|
||||||
|
echo $ans
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
read -n 1 ans # Just one character
|
||||||
|
```
|
||||||
|
|
||||||
|
### Process IDs
|
||||||
|
|
||||||
|
| `$?` | PID of last foreground task |
|
||||||
|
| `$!` | PID of last background task |
|
||||||
|
| `$$` | PID of shell |
|
||||||
|
|
||||||
|
See [Special parameters](http://wiki.bash-hackers.org/syntax/shellvars#special_parameters_and_shell_variables).
|
||||||
|
|
||||||
|
## Also see
|
||||||
|
{: .-one-column}
|
||||||
|
|
||||||
|
* [Bash-hackers wiki](http://wiki.bash-hackers.org/) _(bash-hackers.org)_
|
||||||
|
* [Shell vars](http://wiki.bash-hackers.org/syntax/shellvars) _(bash-hackers.org)_
|
||||||
|
* [Learn bash in y minutes](https://learnxinyminutes.com/docs/bash/) _(learnxinyminutes.com)_
|
||||||
|
|
|
||||||
83
sketch.md
83
sketch.md
|
|
@ -1,68 +1,73 @@
|
||||||
---
|
---
|
||||||
title: Sketch
|
title: Sketch
|
||||||
category: Apps
|
category: Apps
|
||||||
|
layout: 2017/sheet
|
||||||
---
|
---
|
||||||
|
|
||||||
|
Shortcuts
|
||||||
|
---------
|
||||||
|
{: .-three-column}
|
||||||
|
|
||||||
### Insert
|
### Insert
|
||||||
|
|
||||||
| `V` | vector |
|
| `V` | Vector |
|
||||||
| `P` | pencil |
|
| `P` | Pencil |
|
||||||
| `T` | text |
|
| `T` | Text |
|
||||||
| `L` | line |
|
| `L` | Line |
|
||||||
| `R` | rect |
|
| `R` | Rectangle |
|
||||||
| `O` | oval |
|
| `O` | Oval |
|
||||||
| `U` | rounded |
|
| `U` | Rounded |
|
||||||
{:.shortcuts}
|
{: .-shortcuts}
|
||||||
|
|
||||||
### Show
|
### Show
|
||||||
|
|
||||||
| `^G` | grid |
|
| `^G` | Show grid |
|
||||||
| `^L` | layout |
|
| `^L` | Show layout |
|
||||||
| `^P` | pixels |
|
| `^P` | Show pixels |
|
||||||
| `^H` | selection handles |
|
| `^H` | Show selection handles |
|
||||||
| `^R` | rulers |
|
| `^R` | Show rulers |
|
||||||
{:.shortcuts}
|
{: .-shortcuts}
|
||||||
|
|
||||||
### Sidebars
|
### Sidebars
|
||||||
|
|
||||||
| `⌘⌥1` | toggle left (layers) |
|
| `⌘⌥1` | Toggle left (layers) |
|
||||||
| `⌘⌥2` | toggle right (inspector) |
|
| `⌘⌥2` | Toggle right (inspector) |
|
||||||
| `⌘⌥3` | toggle both |
|
| `⌘⌥3` | Toggle both |
|
||||||
| `⌘.` | presentation |
|
| `⌘.` | Presentation mode |
|
||||||
{:.shortcuts}
|
{: .-shortcuts}
|
||||||
|
|
||||||
### Zoom
|
### Zoom
|
||||||
|
|
||||||
| `⌘0` | 100% |
|
| `⌘0` | 100% |
|
||||||
| `⌘1` | fit to screen |
|
| `⌘1` | Fit to screen |
|
||||||
| `⌘2` | fit selection to screen |
|
| `⌘2` | Fit selection to screen |
|
||||||
| `⌘3` | center selection |
|
| `⌘3` | Center selection |
|
||||||
{:.shortcuts}
|
{: .-shortcuts}
|
||||||
|
|
||||||
### Arrange
|
### Arrange
|
||||||
|
|
||||||
| `⌘⌥ up/dn` | forward or backward |
|
| `⌘⌥↑` _/_ `↓` | Forward or backward |
|
||||||
| `^⌘⌥ up/dn` | front or back |
|
| `^⌘⌥↑` _/_ `↓` | Front or back |
|
||||||
{:.shortcuts}
|
{: .-shortcuts}
|
||||||
|
|
||||||
### Distribute
|
### Distribute
|
||||||
|
|
||||||
| `^⌘H` | horizontal |
|
| `^⌘H` | Horizontal |
|
||||||
| `^⌘V` | vertical |
|
| `^⌘V` | Vertical |
|
||||||
{:.shortcuts}
|
{: .-shortcuts}
|
||||||
|
|
||||||
### Layers
|
### Layers
|
||||||
|
|
||||||
| `⌘R` | rename |
|
| `⌘R` | Rename layer |
|
||||||
| `⌘F` | find |
|
| `⌘F` | Find layer |
|
||||||
| `⌘G` | group |
|
| `⌘G` | Group |
|
||||||
| `⌘⇧G` | ungroup |
|
| `⌘⇧G` | Ungroup |
|
||||||
{:.shortcuts}
|
{: .-shortcuts}
|
||||||
|
|
||||||
### Font
|
### Font
|
||||||
|
|
||||||
| `⌘⌥ +/-` | bigger/smaller |
|
| `⌘⌥ +` _/_ `-` | Bigger/smaller |
|
||||||
| `⌘⇧[` | left align |
|
| `⌘⇧[` | Left align |
|
||||||
| `⌘⇧\` | center align |
|
| `⌘⇧\` | Center align |
|
||||||
| `⌘⇧]` | right align |
|
| `⌘⇧]` | Right align |
|
||||||
{:.shortcuts}
|
{: .-shortcuts}
|
||||||
|
|
|
||||||
319
vim.md
319
vim.md
|
|
@ -1,137 +1,268 @@
|
||||||
---
|
---
|
||||||
title: vim
|
title: Vim
|
||||||
category: Vim
|
category: Vim
|
||||||
|
layout: 2017/sheet
|
||||||
---
|
---
|
||||||
|
|
||||||
* [Digraphs](vim-digraphs.html)
|
Getting started
|
||||||
* [Help text](vim-help.html)
|
---------------
|
||||||
* [Vimscript](vimscript.html)
|
{: .-three-column}
|
||||||
* [Vim-unite](vim-unite.html)
|
|
||||||
* [Vim-easyalign](vim-easyalign.html)
|
|
||||||
* [Vim-rails](vim-rails.html)
|
|
||||||
|
|
||||||
Command line
|
### Exiting
|
||||||
------------
|
{: .-prime}
|
||||||
|
|
||||||
<C-r><C-w> # insert current word into the command line
|
| Shortcut | Description |
|
||||||
<C-r>" # paste from " register
|
| --- | --- |
|
||||||
|
| `:qa` | Close all files |
|
||||||
|
| `:qa!` | Close all files, abandon changes |
|
||||||
|
| --- | --- |
|
||||||
|
| `:w` | Save |
|
||||||
|
| `:wq` _/_ `:x` | Save and close file |
|
||||||
|
| --- | --- |
|
||||||
|
| `:q` | Close file |
|
||||||
|
| `:q!` | Close file, abandon changes |
|
||||||
|
| --- | --- |
|
||||||
|
| `ZZ` | Save and quit |
|
||||||
|
| `ZQ` | Quit without checking changes |
|
||||||
|
{: .-shortcuts}
|
||||||
|
|
||||||
|
### Navigating
|
||||||
|
|
||||||
|
| Shortcut | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `h` `j` `k` `l` | Arrow keys |
|
||||||
|
| `^u` _/_ `^d` | Page up/page down |
|
||||||
|
| --- | --- |
|
||||||
|
| `b` _/_ `w` | Previous/next word |
|
||||||
|
| `e` _/_ `ge` | Previous/next end of word |
|
||||||
|
| --- | --- |
|
||||||
|
| `0` _(zero)_ | Start of line |
|
||||||
|
| `^` | Start of line _(after whitespace)_ |
|
||||||
|
| --- | --- |
|
||||||
|
| `$` | End of line |
|
||||||
|
| `gg` | First line |
|
||||||
|
| `G` | Last line |
|
||||||
|
| --- | --- |
|
||||||
|
| `:n` | Go to line `n` |
|
||||||
|
| `nG` | Go to line `n` |
|
||||||
|
{: .-shortcuts}
|
||||||
|
|
||||||
|
### Entering insert mode
|
||||||
|
|
||||||
|
| Shortcut | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `a` | Append |
|
||||||
|
| `i` | Insert |
|
||||||
|
| `o` | Next line |
|
||||||
|
| `O` | Previous line |
|
||||||
|
| --- | --- |
|
||||||
|
| `s` | Delete char and insert |
|
||||||
|
| `S` | Delete line and insert |
|
||||||
|
| `C` | Delete until end of line and insert |
|
||||||
|
| --- | --- |
|
||||||
|
| `R` | Replace |
|
||||||
|
{: .-shortcuts}
|
||||||
|
|
||||||
|
### Exiting insert mode
|
||||||
|
|
||||||
|
| Shortcut | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `Esc` _/_ `^[` | Exit insert mode |
|
||||||
|
| `^c` | Exit insert mode, and abort current command |
|
||||||
|
{: .-shortcuts}
|
||||||
|
|
||||||
|
### Clipboard
|
||||||
|
|
||||||
|
| Shortcut | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `x` | Delete character |
|
||||||
|
| --- | --- |
|
||||||
|
| `dd` | Delete line _(Cut)_ |
|
||||||
|
| `yy` | Yank line _(Copy)_ |
|
||||||
|
| --- | --- |
|
||||||
|
| `p` | Paste |
|
||||||
|
| `P` | Paste before |
|
||||||
|
{: .-shortcuts}
|
||||||
|
|
||||||
|
### Visual mode
|
||||||
|
|
||||||
|
| Shortcut | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `v` | Enter visual mode |
|
||||||
|
| `V` | Enter visual line mode |
|
||||||
|
| `^v` | Enter visual block mode |
|
||||||
|
| --- | --- |
|
||||||
|
| `d` _/_ `x` | Delete selection |
|
||||||
|
| `s` | Replace selection |
|
||||||
|
| `y` | Yank selection _(Copy)_ |
|
||||||
|
{: .-shortcuts}
|
||||||
|
|
||||||
Text objects
|
Text objects
|
||||||
------------
|
------------
|
||||||
|
|
||||||
vip # Select paragraph
|
### Usage
|
||||||
vipipipip # Select more
|
|
||||||
|
|
||||||
ap # a paragraph
|
| Shortcut | Description |
|
||||||
ip # inner paragraph
|
| --- | --- |
|
||||||
|
| `vip` | Select paragraph |
|
||||||
|
| `vipipipip` | Select more |
|
||||||
|
| --- | --- |
|
||||||
|
| `yip` | Yank inner paragraph |
|
||||||
|
| `yap` | Yank paragraph (including newline) |
|
||||||
|
| --- | --- |
|
||||||
|
| `dip` | Delete inner paragraph |
|
||||||
|
{: .-shortcuts}
|
||||||
|
|
||||||
ap, ip # Paragraph
|
### Text objects
|
||||||
aw, iw # Word
|
|
||||||
as, is # Sentence
|
|
||||||
|
|
||||||
ab # A block [(
|
| Shortcut | Description |
|
||||||
aB # A block in [{
|
| --- | --- |
|
||||||
at # A XML tag block
|
| `ap` | a paragraph |
|
||||||
a[ ( { < # A [], (), or {} block
|
| `ip` | inner paragraph |
|
||||||
a' " ` # A quoted string
|
| --- | --- |
|
||||||
|
| `ap` `ip` | Paragraph |
|
||||||
|
| `aw` `iw` | Word |
|
||||||
|
| `as` `is` | Sentence |
|
||||||
|
| --- | --- |
|
||||||
|
| `a[` `a(` `a{` `a<` | A [], (), or {} block |
|
||||||
|
| `a'` `a"` <code>a`</code> | A quoted string |
|
||||||
|
| --- | --- |
|
||||||
|
| `ab` | A block [( |
|
||||||
|
| `aB` | A block in [{ |
|
||||||
|
| `at` | A XML tag block |
|
||||||
|
{: .-shortcuts}
|
||||||
|
|
||||||
[( [{ [< # previous ( or { or <
|
### Navigation
|
||||||
]) # next
|
|
||||||
|
|
||||||
[m # previous method start
|
| Shortcut | Description |
|
||||||
[M # previous method end
|
| --- | --- |
|
||||||
|
| `[(` `[{` `[<` | previous `(` or `{` or `<` |
|
||||||
|
| `])` | next |
|
||||||
|
| --- | --- |
|
||||||
|
| `[m` | previous method start |
|
||||||
|
| `[M` | previous method end |
|
||||||
|
{: .-shortcuts}
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
yip # Yank inner paragraph
|
|
||||||
yap # Yank paragraph (including newline)
|
|
||||||
|
|
||||||
Folds
|
|
||||||
-----
|
|
||||||
|
|
||||||
zo # Open
|
|
||||||
zO # Open, recursive
|
|
||||||
zc # Close
|
|
||||||
zC # Close, recursive
|
|
||||||
za # Toggle
|
|
||||||
zA # Toggle, recursive
|
|
||||||
|
|
||||||
zv # Open folds for this line
|
|
||||||
|
|
||||||
zM # Close all
|
|
||||||
zR # Open all
|
|
||||||
|
|
||||||
zm # Fold more (foldlevel += 1)
|
|
||||||
zr # Fold less (foldlevel -= 1)
|
|
||||||
|
|
||||||
zx # Update
|
|
||||||
|
|
||||||
Jumping
|
|
||||||
-------
|
|
||||||
|
|
||||||
^O # Go back to previous location
|
|
||||||
^I # Go forward
|
|
||||||
|
|
||||||
gf # go to file in cursor
|
|
||||||
|
|
||||||
Misc
|
Misc
|
||||||
----
|
----
|
||||||
|
|
||||||
. # repeat last command
|
### Folds
|
||||||
]p # paste under the current indentation level
|
|
||||||
|
|
||||||
zz # Center this line
|
| Shortcut | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `zo` _/_ `zO` | Open |
|
||||||
|
| `zc` _/_ `zC` | Close |
|
||||||
|
| `za` _/_ `zA` | Toggle |
|
||||||
|
| --- | --- |
|
||||||
|
| `zv` | Open folds for this line |
|
||||||
|
| --- | --- |
|
||||||
|
| `zM` | Close all |
|
||||||
|
| `zR` | Open all |
|
||||||
|
| --- | --- |
|
||||||
|
| `zm` | Fold more _(foldlevel += 1)_ |
|
||||||
|
| `zr` | Fold less _(foldlevel -= 1)_ |
|
||||||
|
| --- | --- |
|
||||||
|
| `zx` | Update folds |
|
||||||
|
{: .-shortcuts}
|
||||||
|
|
||||||
Counters
|
Uppercase ones are recursive (eg, `zO` is open recursively).
|
||||||
--------
|
|
||||||
|
|
||||||
^A # increment number
|
### Jumping
|
||||||
^X # decrement
|
|
||||||
|
|
||||||
Windows
|
| Shortcut | Description |
|
||||||
-------
|
| --- | --- |
|
||||||
|
| `^O` | Go back to previous location |
|
||||||
|
| `^I` | Go forward |
|
||||||
|
| --- | --- |
|
||||||
|
| `gf` | go to file in cursor |
|
||||||
|
{: .-shortcuts}
|
||||||
|
|
||||||
z{height}<Cr> # Resize pane to {height} lines tall
|
### Counters
|
||||||
|
|
||||||
Tags
|
| `^A` | increment number |
|
||||||
----
|
| `^X` | decrement |
|
||||||
|
|
||||||
:tag Classname # Jump to first definition of Classname
|
### Windows
|
||||||
|
|
||||||
^] # Jump to definition
|
| `z{height}<Cr>` | Resize pane to `{height}` lines tall |
|
||||||
g] # See all definitions
|
|
||||||
C-t # Go back to last tag
|
|
||||||
^O ^I # Back/forward
|
|
||||||
|
|
||||||
:tselect Classname # Find definitions of Classname
|
### Tags
|
||||||
:tjump Classname # Find definitions of Classname (auto-select 1st)
|
|
||||||
|
|
||||||
Case
|
| Shortcut | Description |
|
||||||
----
|
| --- | --- |
|
||||||
|
| `:tag Classname` | Jump to first definition of Classname |
|
||||||
|
| --- | --- |
|
||||||
|
| `^]` | Jump to definition |
|
||||||
|
| `g]` | See all definitions |
|
||||||
|
| `^t` | Go back to last tag |
|
||||||
|
| `^o ^i` | Back/forward |
|
||||||
|
| --- | --- |
|
||||||
|
| `:tselect Classname` | Find definitions of Classname |
|
||||||
|
| `:tjump Classname` | Find definitions of Classname (auto-select 1st) |
|
||||||
|
{: .-shortcuts}
|
||||||
|
|
||||||
~ # toggle case (Case => cASE)
|
### Case
|
||||||
gU # uppercase
|
|
||||||
gu # lowercase
|
|
||||||
|
|
||||||
gUU # uppercase current line (also gUgU)
|
| Shortcut | Description |
|
||||||
guu # lowercase current line (also gugu)
|
| --- | --- |
|
||||||
|
| `~` | toggle case (Case => cASE) |
|
||||||
|
| `gU` | uppercase |
|
||||||
|
| `gu` | lowercase |
|
||||||
|
| --- | --- |
|
||||||
|
| `gUU` | uppercase current line (also `gUgU`) |
|
||||||
|
| `guu` | lowercase current line (also `gugu`) |
|
||||||
|
{: .-shortcuts}
|
||||||
|
|
||||||
Marks
|
Do these in visual mode.
|
||||||
-----
|
|
||||||
|
|
||||||
`^ # Last position of cursor in insert mode
|
### Marks
|
||||||
`. # Last change
|
|
||||||
`` # Last jump
|
|
||||||
|
|
||||||
Text alignment
|
| <code>`^</code> | Last position of cursor in insert mode |
|
||||||
--------------
|
| <code>`.</code> | Last change |
|
||||||
|
| <code>``</code> | Last jump |
|
||||||
|
|
||||||
See `:help formatting`
|
### Misc
|
||||||
|
|
||||||
|
| Shortcut | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `.` | repeat last command |
|
||||||
|
| `]p` | paste under the current indentation level |
|
||||||
|
| --- | --- |
|
||||||
|
| `zz` | Center this line |
|
||||||
|
|
||||||
|
### Command line
|
||||||
|
|
||||||
|
| Shortcut | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `<C-r><C-w>` | insert current word into the command line |
|
||||||
|
| `<C-r>"` | paste from " register |
|
||||||
|
|
||||||
|
### Text alignment
|
||||||
|
|
||||||
:center [width]
|
:center [width]
|
||||||
:right [width]
|
:right [width]
|
||||||
:left
|
:left
|
||||||
|
|
||||||
|
See `:help formatting`
|
||||||
|
|
||||||
### Calculator
|
### Calculator
|
||||||
|
|
||||||
(Insert mode) <C-r>=128/2
|
<C-r>=128/2
|
||||||
|
|
||||||
|
Do this in insert mode.
|
||||||
|
|
||||||
|
Also see
|
||||||
|
--------
|
||||||
|
{: .-one-column}
|
||||||
|
|
||||||
|
* [Digraphs](vim-digraphs.html)
|
||||||
|
* [Help text](vim-help.html)
|
||||||
|
* [Vimscript](vimscript.html)
|
||||||
|
* [Vim-unite](vim-unite.html)
|
||||||
|
* [Vim-easyalign](vim-easyalign.html)
|
||||||
|
* [Vim-rails](vim-rails.html)
|
||||||
|
{: .-also-see}
|
||||||
|
|
||||||
|
This reference was made for Vim 8.0.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue