Add blog
This commit is contained in:
parent
3c9ca5a64e
commit
9496deea93
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
recompile css
|
recompile css
|
||||||
```sh
|
```sh
|
||||||
tailwindcss -i ./content/css/main.css -o ./content/css/mini.css --minify
|
tailwindcss -i ./content/css/main.css -o ./content/css/mini.css --minify
|
||||||
```
|
```
|
||||||
|
|
||||||
build, serve and watch
|
build, serve and watch
|
||||||
```sh
|
```sh
|
||||||
cabal run site -- watch
|
cabal run site -- watch
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
.components-flex {
|
|
||||||
display: flex;
|
|
||||||
gap: 1.4em;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.components-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-column-gap: 1.4em;
|
|
||||||
grid-template-columns: auto;
|
|
||||||
grid-template-rows: auto;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-rows: auto;
|
|
||||||
display: grid;
|
|
||||||
grid-gap: 1em;
|
|
||||||
grid-template-rows: auto;
|
|
||||||
grid-template-columns: repeat(
|
|
||||||
auto-fit,
|
|
||||||
minmax(calc(var(--page-width) / 12), 1fr)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (min-width: 45em) {
|
|
||||||
.components-grid {
|
|
||||||
grid-template-columns: 3fr 9fr;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,141 +0,0 @@
|
||||||
html {
|
|
||||||
font-size: 62.5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-size: 1.6rem;
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
header {
|
|
||||||
border-bottom: 0.2rem solid #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav a {
|
|
||||||
font-size: 1.8rem;
|
|
||||||
font-weight: bold;
|
|
||||||
color: black;
|
|
||||||
text-decoration: none;
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer {
|
|
||||||
margin-top: 3rem;
|
|
||||||
padding: 1.2rem 0;
|
|
||||||
border-top: 0.2rem solid #000;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 2.4rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
article .header {
|
|
||||||
font-size: 1.4rem;
|
|
||||||
font-style: italic;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo a {
|
|
||||||
font-weight: bold;
|
|
||||||
color: #000;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 319px) {
|
|
||||||
body {
|
|
||||||
width: 90%;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0 5%;
|
|
||||||
}
|
|
||||||
header {
|
|
||||||
margin: 4.2rem 0;
|
|
||||||
}
|
|
||||||
nav {
|
|
||||||
margin: 0 auto 3rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
footer {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.logo {
|
|
||||||
text-align: center;
|
|
||||||
margin: 1rem auto 3rem;
|
|
||||||
}
|
|
||||||
.logo a {
|
|
||||||
font-size: 2.4rem;
|
|
||||||
}
|
|
||||||
nav a {
|
|
||||||
display: block;
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 320px) {
|
|
||||||
body {
|
|
||||||
width: 90%;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0 5%;
|
|
||||||
}
|
|
||||||
header {
|
|
||||||
margin: 4.2rem 0;
|
|
||||||
}
|
|
||||||
nav {
|
|
||||||
margin: 0 auto 3rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
footer {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.logo {
|
|
||||||
text-align: center;
|
|
||||||
margin: 1rem auto 3rem;
|
|
||||||
}
|
|
||||||
.logo a {
|
|
||||||
font-size: 2.4rem;
|
|
||||||
}
|
|
||||||
nav a {
|
|
||||||
display: inline;
|
|
||||||
margin: 0 0.6rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 640px) {
|
|
||||||
body {
|
|
||||||
width: 60rem;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
header {
|
|
||||||
margin: 0 0 3rem;
|
|
||||||
padding: 1.2rem 0;
|
|
||||||
}
|
|
||||||
nav {
|
|
||||||
margin: 0;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
nav a {
|
|
||||||
margin: 0 0 0 1.2rem;
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
footer {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
.logo {
|
|
||||||
margin: 0;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
.logo a {
|
|
||||||
float: left;
|
|
||||||
font-size: 1.8rem;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,3 +8,59 @@
|
||||||
src: local("jetbrains-mono"),
|
src: local("jetbrains-mono"),
|
||||||
url("/fonts/JetBrainsMono-Medium.woff2") format("woff2");
|
url("/fonts/JetBrainsMono-Medium.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
article {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
article>section> :is(p, h1, h2, h3, h4, h5, h6) {
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
article>section>h1 {
|
||||||
|
margin-top: 2rem;
|
||||||
|
font-size: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
article>section>h1::before {
|
||||||
|
content: "# ";
|
||||||
|
}
|
||||||
|
|
||||||
|
article>section>h2 {
|
||||||
|
margin-top: 2rem;
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
article>section>h2::before {
|
||||||
|
content: "## ";
|
||||||
|
}
|
||||||
|
|
||||||
|
article>section>h3::before {
|
||||||
|
content: "### ";
|
||||||
|
}
|
||||||
|
|
||||||
|
article>section>h4::before {
|
||||||
|
content: "#### ";
|
||||||
|
}
|
||||||
|
|
||||||
|
article>section {
|
||||||
|
margin-top: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
article a {
|
||||||
|
text-decoration-color: rgb(239 68 68);
|
||||||
|
text-decoration-thickness: 4px;
|
||||||
|
text-decoration-line: underline;
|
||||||
|
transition-duration: 70ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
article a:hover {
|
||||||
|
text-decoration-thickness: 8px;
|
||||||
|
text-decoration-color: rgb(185 28 28);
|
||||||
|
text-decoration-line: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
article ul {
|
||||||
|
margin-left: 2rem;
|
||||||
|
list-style-type: "❯ ";
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
|
@ -1,349 +0,0 @@
|
||||||
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
|
|
||||||
|
|
||||||
/* Document
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Correct the line height in all browsers.
|
|
||||||
* 2. Prevent adjustments of font size after orientation changes in iOS.
|
|
||||||
*/
|
|
||||||
|
|
||||||
html {
|
|
||||||
line-height: 1.15; /* 1 */
|
|
||||||
-webkit-text-size-adjust: 100%; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sections
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the margin in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render the `main` element consistently in IE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
main {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct the font size and margin on `h1` elements within `section` and
|
|
||||||
* `article` contexts in Chrome, Firefox, and Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 2em;
|
|
||||||
margin: 0.67em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Grouping content
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Add the correct box sizing in Firefox.
|
|
||||||
* 2. Show the overflow in Edge and IE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
hr {
|
|
||||||
box-sizing: content-box; /* 1 */
|
|
||||||
height: 0; /* 1 */
|
|
||||||
overflow: visible; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
|
||||||
* 2. Correct the odd `em` font sizing in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
pre {
|
|
||||||
font-family: monospace, monospace; /* 1 */
|
|
||||||
font-size: 1em; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Text-level semantics
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the gray background on active links in IE 10.
|
|
||||||
*/
|
|
||||||
|
|
||||||
a {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Remove the bottom border in Chrome 57-
|
|
||||||
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
abbr[title] {
|
|
||||||
border-bottom: none; /* 1 */
|
|
||||||
text-decoration: underline; /* 2 */
|
|
||||||
text-decoration: underline dotted; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the correct font weight in Chrome, Edge, and Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
b,
|
|
||||||
strong {
|
|
||||||
font-weight: bolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
|
||||||
* 2. Correct the odd `em` font sizing in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
code,
|
|
||||||
kbd,
|
|
||||||
samp {
|
|
||||||
font-family: monospace, monospace; /* 1 */
|
|
||||||
font-size: 1em; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the correct font size in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
small {
|
|
||||||
font-size: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prevent `sub` and `sup` elements from affecting the line height in
|
|
||||||
* all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
sub,
|
|
||||||
sup {
|
|
||||||
font-size: 75%;
|
|
||||||
line-height: 0;
|
|
||||||
position: relative;
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub {
|
|
||||||
bottom: -0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
sup {
|
|
||||||
top: -0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Embedded content
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the border on images inside links in IE 10.
|
|
||||||
*/
|
|
||||||
|
|
||||||
img {
|
|
||||||
border-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Forms
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Change the font styles in all browsers.
|
|
||||||
* 2. Remove the margin in Firefox and Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button,
|
|
||||||
input,
|
|
||||||
optgroup,
|
|
||||||
select,
|
|
||||||
textarea {
|
|
||||||
font-family: inherit; /* 1 */
|
|
||||||
font-size: 100%; /* 1 */
|
|
||||||
line-height: 1.15; /* 1 */
|
|
||||||
margin: 0; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the overflow in IE.
|
|
||||||
* 1. Show the overflow in Edge.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button,
|
|
||||||
input { /* 1 */
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
|
||||||
* 1. Remove the inheritance of text transform in Firefox.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button,
|
|
||||||
select { /* 1 */
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct the inability to style clickable types in iOS and Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button,
|
|
||||||
[type="button"],
|
|
||||||
[type="reset"],
|
|
||||||
[type="submit"] {
|
|
||||||
-webkit-appearance: button;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the inner border and padding in Firefox.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button::-moz-focus-inner,
|
|
||||||
[type="button"]::-moz-focus-inner,
|
|
||||||
[type="reset"]::-moz-focus-inner,
|
|
||||||
[type="submit"]::-moz-focus-inner {
|
|
||||||
border-style: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restore the focus styles unset by the previous rule.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button:-moz-focusring,
|
|
||||||
[type="button"]:-moz-focusring,
|
|
||||||
[type="reset"]:-moz-focusring,
|
|
||||||
[type="submit"]:-moz-focusring {
|
|
||||||
outline: 1px dotted ButtonText;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct the padding in Firefox.
|
|
||||||
*/
|
|
||||||
|
|
||||||
fieldset {
|
|
||||||
padding: 0.35em 0.75em 0.625em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Correct the text wrapping in Edge and IE.
|
|
||||||
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
|
||||||
* 3. Remove the padding so developers are not caught out when they zero out
|
|
||||||
* `fieldset` elements in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
legend {
|
|
||||||
box-sizing: border-box; /* 1 */
|
|
||||||
color: inherit; /* 2 */
|
|
||||||
display: table; /* 1 */
|
|
||||||
max-width: 100%; /* 1 */
|
|
||||||
padding: 0; /* 3 */
|
|
||||||
white-space: normal; /* 1 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
|
||||||
*/
|
|
||||||
|
|
||||||
progress {
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the default vertical scrollbar in IE 10+.
|
|
||||||
*/
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Add the correct box sizing in IE 10.
|
|
||||||
* 2. Remove the padding in IE 10.
|
|
||||||
*/
|
|
||||||
|
|
||||||
[type="checkbox"],
|
|
||||||
[type="radio"] {
|
|
||||||
box-sizing: border-box; /* 1 */
|
|
||||||
padding: 0; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct the cursor style of increment and decrement buttons in Chrome.
|
|
||||||
*/
|
|
||||||
|
|
||||||
[type="number"]::-webkit-inner-spin-button,
|
|
||||||
[type="number"]::-webkit-outer-spin-button {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Correct the odd appearance in Chrome and Safari.
|
|
||||||
* 2. Correct the outline style in Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
[type="search"] {
|
|
||||||
-webkit-appearance: textfield; /* 1 */
|
|
||||||
outline-offset: -2px; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the inner padding in Chrome and Safari on macOS.
|
|
||||||
*/
|
|
||||||
|
|
||||||
[type="search"]::-webkit-search-decoration {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Correct the inability to style clickable types in iOS and Safari.
|
|
||||||
* 2. Change font properties to `inherit` in Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
::-webkit-file-upload-button {
|
|
||||||
-webkit-appearance: button; /* 1 */
|
|
||||||
font: inherit; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Interactive
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add the correct display in Edge, IE 10+, and Firefox.
|
|
||||||
*/
|
|
||||||
|
|
||||||
details {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add the correct display in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
summary {
|
|
||||||
display: list-item;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Misc
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the correct display in IE 10+.
|
|
||||||
*/
|
|
||||||
|
|
||||||
template {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the correct display in IE 10.
|
|
||||||
*/
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
|
@ -1,994 +0,0 @@
|
||||||
:root {
|
|
||||||
--global-font-size: 20px;
|
|
||||||
--global-line-height: 1.6em;
|
|
||||||
--global-space: 12px;
|
|
||||||
--font-stack: "JetBrains Mono", Menlo, Monaco, Lucida Console, Liberation Mono,
|
|
||||||
DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace,
|
|
||||||
serif;
|
|
||||||
--mono-font-stack: Menlo, Monaco, Lucida Console, Liberation Mono,
|
|
||||||
DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace,
|
|
||||||
serif;
|
|
||||||
--background-color: #222225;
|
|
||||||
--page-width: 60em;
|
|
||||||
--font-color: #e8e9ed;
|
|
||||||
--invert-font-color: #222225;
|
|
||||||
--secondary-color: #a3abba;
|
|
||||||
--tertiary-color: #a3abba;
|
|
||||||
--primary-color: #62c4ff;
|
|
||||||
--error-color: #ff3c74;
|
|
||||||
--progress-bar-background: #3f3f44;
|
|
||||||
--progress-bar-fill: #62c4ff;
|
|
||||||
--code-bg-color: #3f3f44;
|
|
||||||
--input-style: solid;
|
|
||||||
--display-h1-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
text-rendering: geometricPrecision;
|
|
||||||
}
|
|
||||||
|
|
||||||
*::-moz-selection {
|
|
||||||
background: var(--primary-color);
|
|
||||||
color: var(--invert-font-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
*::selection {
|
|
||||||
background: var(--primary-color);
|
|
||||||
color: var(--invert-font-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-size: var(--global-font-size);
|
|
||||||
color: var(--font-color);
|
|
||||||
line-height: var(--global-line-height);
|
|
||||||
margin: 0;
|
|
||||||
font-family: var(--font-stack);
|
|
||||||
word-wrap: break-word;
|
|
||||||
background-color: var(--background-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
h1,
|
|
||||||
h2,
|
|
||||||
h3,
|
|
||||||
h4,
|
|
||||||
h5,
|
|
||||||
h6,
|
|
||||||
.logo {
|
|
||||||
line-height: var(--global-line-height);
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
cursor: pointer;
|
|
||||||
color: var(--primary-color);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
background-color: var(--primary-color);
|
|
||||||
color: var(--invert-font-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
em {
|
|
||||||
font-size: var(--global-font-size);
|
|
||||||
font-style: italic;
|
|
||||||
font-family: var(--font-stack);
|
|
||||||
color: var(--font-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote,
|
|
||||||
code,
|
|
||||||
em,
|
|
||||||
strong {
|
|
||||||
line-height: var(--global-line-height);
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote,
|
|
||||||
code,
|
|
||||||
footer,
|
|
||||||
h1,
|
|
||||||
h2,
|
|
||||||
h3,
|
|
||||||
h4,
|
|
||||||
h5,
|
|
||||||
h6,
|
|
||||||
header,
|
|
||||||
li,
|
|
||||||
ol,
|
|
||||||
p,
|
|
||||||
section,
|
|
||||||
ul,
|
|
||||||
.logo {
|
|
||||||
float: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote,
|
|
||||||
h1,
|
|
||||||
ol,
|
|
||||||
p,
|
|
||||||
ul,
|
|
||||||
.logo {
|
|
||||||
margin-top: calc(var(--global-space) * 2);
|
|
||||||
margin-bottom: calc(var(--global-space) * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
h1,
|
|
||||||
.logo {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
display: table-cell;
|
|
||||||
padding: calc(var(--global-space) * 2) 0 calc(var(--global-space) * 2);
|
|
||||||
margin: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1::after {
|
|
||||||
content: "====================================================================================================";
|
|
||||||
position: absolute;
|
|
||||||
bottom: 5px;
|
|
||||||
left: 0;
|
|
||||||
display: var(--display-h1-decoration);
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 + *,
|
|
||||||
.logo + * {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2,
|
|
||||||
h3,
|
|
||||||
h4,
|
|
||||||
h5,
|
|
||||||
h6 {
|
|
||||||
position: relative;
|
|
||||||
margin-bottom: var(--global-line-height);
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
position: relative;
|
|
||||||
padding-left: calc(var(--global-space) * 2);
|
|
||||||
padding-left: 2ch;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote::after {
|
|
||||||
content: ">\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>\A>";
|
|
||||||
white-space: pre;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
line-height: var(--global-line-height);
|
|
||||||
color: #9ca2ab;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-weight: inherit;
|
|
||||||
background-color: var(--code-bg-color);
|
|
||||||
font-family: var(--mono-font-stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
code::after,
|
|
||||||
code::before {
|
|
||||||
content: "`";
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre code::after,
|
|
||||||
pre code::before {
|
|
||||||
content: "";
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
display: block;
|
|
||||||
word-break: break-all;
|
|
||||||
word-wrap: break-word;
|
|
||||||
color: var(--secondary-color);
|
|
||||||
background-color: var(--background-color);
|
|
||||||
border: 1px solid var(--secondary-color);
|
|
||||||
padding: var(--global-space);
|
|
||||||
white-space: pre-wrap;
|
|
||||||
white-space: -moz-pre-wrap;
|
|
||||||
white-space: -pre-wrap;
|
|
||||||
white-space: -o-pre-wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre code {
|
|
||||||
overflow-x: scroll;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
display: inline-block;
|
|
||||||
min-width: 100%;
|
|
||||||
font-family: var(--mono-font-stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal blockquote,
|
|
||||||
.terminal code,
|
|
||||||
.terminal h1,
|
|
||||||
.terminal h2,
|
|
||||||
.terminal h3,
|
|
||||||
.terminal h4,
|
|
||||||
.terminal h5,
|
|
||||||
.terminal h6,
|
|
||||||
.terminal strong,
|
|
||||||
.terminal .logo {
|
|
||||||
font-size: var(--global-font-size);
|
|
||||||
font-style: normal;
|
|
||||||
font-family: var(--font-stack);
|
|
||||||
color: var(--font-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-prompt {
|
|
||||||
position: relative;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-prompt::before {
|
|
||||||
content: "> ";
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-prompt::after {
|
|
||||||
content: "";
|
|
||||||
animation: cursor 1200ms infinite;
|
|
||||||
background: var(--primary-color);
|
|
||||||
border-radius: 0;
|
|
||||||
display: inline-block;
|
|
||||||
height: 1em;
|
|
||||||
margin-left: 0.2em;
|
|
||||||
width: 3px;
|
|
||||||
bottom: -2px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
@-webkit-keyframes cursor {
|
|
||||||
0% {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
50% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes cursor {
|
|
||||||
0% {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
50% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
li,
|
|
||||||
li > ul > li {
|
|
||||||
position: relative;
|
|
||||||
display: block;
|
|
||||||
padding-left: calc(var(--global-space) * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
nav > ul > li {
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
li::after {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul > li::after {
|
|
||||||
content: "-";
|
|
||||||
}
|
|
||||||
|
|
||||||
nav ul > li::after {
|
|
||||||
content: "";
|
|
||||||
}
|
|
||||||
|
|
||||||
ol li::before {
|
|
||||||
content: counters(item, ".") ". ";
|
|
||||||
counter-increment: item;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol ol li::before {
|
|
||||||
content: counters(item, ".") " ";
|
|
||||||
counter-increment: item;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-menu li::after,
|
|
||||||
.terminal-menu li::before {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol {
|
|
||||||
counter-reset: item;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol li:nth-child(n+10)::after {
|
|
||||||
left: -7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol ol {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-menu {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-nav {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul ul {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-menu ul {
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 0 !important;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
flex-grow: 1;
|
|
||||||
font-size: var(--global-font-size);
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-menu li {
|
|
||||||
display: flex;
|
|
||||||
margin: 0 0 0.5em 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol.terminal-toc li {
|
|
||||||
border-bottom: 1px dotted var(--secondary-color);
|
|
||||||
padding: 0;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-menu li:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol.terminal-toc li a {
|
|
||||||
margin: 4px 4px 4px 0;
|
|
||||||
background: var(--background-color);
|
|
||||||
position: relative;
|
|
||||||
top: 6px;
|
|
||||||
text-align: left;
|
|
||||||
padding-right: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-menu li a:not(.btn) {
|
|
||||||
text-decoration: none;
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
border: none;
|
|
||||||
color: var(--secondary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-menu li a.active {
|
|
||||||
color: var(--font-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-menu li a:hover {
|
|
||||||
background: none;
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol.terminal-toc li::before {
|
|
||||||
content: counters(item, ".") ". ";
|
|
||||||
counter-increment: item;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
background: var(--background-color);
|
|
||||||
padding: 4px 0 4px 4px;
|
|
||||||
bottom: -8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol.terminal-toc li a:hover {
|
|
||||||
background: var(--primary-color);
|
|
||||||
color: var(--invert-font-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
margin: calc(var(--global-space) * 4) 0;
|
|
||||||
border: 0;
|
|
||||||
border-bottom: 1px dashed var(--secondary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 0 0 var(--global-line-height);
|
|
||||||
color: var(--global-font-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
max-width: var(--page-width);
|
|
||||||
}
|
|
||||||
|
|
||||||
.container,
|
|
||||||
.container-fluid {
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 0 calc(var(--global-space) * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar {
|
|
||||||
height: 8px;
|
|
||||||
background-color: var(--progress-bar-background);
|
|
||||||
margin: 12px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar.progress-bar-show-percent {
|
|
||||||
margin-top: 38px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar-filled {
|
|
||||||
background-color: var(--progress-bar-fill);
|
|
||||||
height: 100%;
|
|
||||||
transition: width 0.3s ease;
|
|
||||||
position: relative;
|
|
||||||
width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar-filled::before {
|
|
||||||
content: "";
|
|
||||||
border: 6px solid transparent;
|
|
||||||
border-top-color: var(--progress-bar-fill);
|
|
||||||
position: absolute;
|
|
||||||
top: -12px;
|
|
||||||
right: -6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar-filled::after {
|
|
||||||
color: var(--progress-bar-fill);
|
|
||||||
content: attr(data-filled);
|
|
||||||
display: block;
|
|
||||||
font-size: 12px;
|
|
||||||
white-space: nowrap;
|
|
||||||
position: absolute;
|
|
||||||
border: 6px solid transparent;
|
|
||||||
top: -38px;
|
|
||||||
right: 0;
|
|
||||||
-ms-transform: translateX(50%);
|
|
||||||
transform: translateX(50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar-no-arrow > .progress-bar-filled::before,
|
|
||||||
.progress-bar-no-arrow > .progress-bar-filled::after {
|
|
||||||
content: "";
|
|
||||||
display: none;
|
|
||||||
visibility: hidden;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
margin: var(--global-line-height) 0;
|
|
||||||
color: var(--font-color);
|
|
||||||
font-size: var(--global-font-size);
|
|
||||||
}
|
|
||||||
|
|
||||||
table td,
|
|
||||||
table th {
|
|
||||||
vertical-align: top;
|
|
||||||
border: 1px solid var(--font-color);
|
|
||||||
line-height: var(--global-line-height);
|
|
||||||
padding: calc(var(--global-space) / 2);
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
table thead th {
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
table tfoot tr th {
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
table caption {
|
|
||||||
font-size: 1em;
|
|
||||||
margin: 0 0 1em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
table tbody td:first-child {
|
|
||||||
font-weight: 700;
|
|
||||||
color: var(--secondary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.form {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset {
|
|
||||||
border: 1px solid var(--font-color);
|
|
||||||
padding: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
font-size: 1em;
|
|
||||||
color: var(--font-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="email"],
|
|
||||||
input[type="text"],
|
|
||||||
input[type="number"],
|
|
||||||
input[type="password"],
|
|
||||||
input[type="search"] {
|
|
||||||
border: 1px var(--input-style) var(--font-color);
|
|
||||||
width: 100%;
|
|
||||||
padding: 0.7em 0.5em;
|
|
||||||
font-size: 1em;
|
|
||||||
font-family: var(--font-stack);
|
|
||||||
-webkit-appearance: none;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="email"]:active,
|
|
||||||
input[type="text"]:active,
|
|
||||||
input[type="number"]:active,
|
|
||||||
input[type="password"]:active,
|
|
||||||
input[type="search"]:active,
|
|
||||||
input[type="email"]:focus,
|
|
||||||
input[type="text"]:focus,
|
|
||||||
input[type="number"]:focus,
|
|
||||||
input[type="password"]:focus,
|
|
||||||
input[type="search"]:focus {
|
|
||||||
outline: none;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
border: 1px solid var(--font-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="text"]:not(:placeholder-shown):invalid,
|
|
||||||
input[type="email"]:not(:placeholder-shown):invalid,
|
|
||||||
input[type="password"]:not(:placeholder-shown):invalid,
|
|
||||||
input[type="search"]:not(:placeholder-shown):invalid,
|
|
||||||
input[type="number"]:not(:placeholder-shown):invalid {
|
|
||||||
border-color: var(--error-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
input,
|
|
||||||
textarea {
|
|
||||||
color: var(--font-color);
|
|
||||||
background-color: var(--background-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
input::placeholder,
|
|
||||||
textarea::placeholder {
|
|
||||||
color: var(--secondary-color) !important;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
height: auto;
|
|
||||||
width: 100%;
|
|
||||||
resize: none;
|
|
||||||
border: 1px var(--input-style) var(--font-color);
|
|
||||||
padding: 0.5em;
|
|
||||||
font-size: 1em;
|
|
||||||
font-family: var(--font-stack);
|
|
||||||
-webkit-appearance: none;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea:focus {
|
|
||||||
outline: none;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
border: 1px solid var(--font-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea:not(:placeholder-shown):invalid {
|
|
||||||
border-color: var(--error-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
input:-webkit-autofill,
|
|
||||||
input:-webkit-autofill:hover,
|
|
||||||
input:-webkit-autofill:focus textarea:-webkit-autofill,
|
|
||||||
textarea:-webkit-autofill:hover textarea:-webkit-autofill:focus,
|
|
||||||
select:-webkit-autofill,
|
|
||||||
select:-webkit-autofill:hover,
|
|
||||||
select:-webkit-autofill:focus {
|
|
||||||
border: 1px solid var(--font-color);
|
|
||||||
-webkit-text-fill-color: var(--font-color);
|
|
||||||
box-shadow: 0 0 0 1000px var(--invert-font-color) inset;
|
|
||||||
-webkit-box-shadow: 0 0 0 1000px var(--invert-font-color) inset;
|
|
||||||
transition: background-color 5000s ease-in-out 0s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-group {
|
|
||||||
margin-bottom: var(--global-line-height);
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
border-style: solid;
|
|
||||||
border-width: 1px;
|
|
||||||
display: -ms-inline-flexbox;
|
|
||||||
display: inline-flex;
|
|
||||||
-ms-flex-align: center;
|
|
||||||
align-items: center;
|
|
||||||
-ms-flex-pack: center;
|
|
||||||
justify-content: center;
|
|
||||||
cursor: pointer;
|
|
||||||
outline: none;
|
|
||||||
padding: 0.65em 2em;
|
|
||||||
font-size: 1em;
|
|
||||||
font-family: inherit;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn:active {
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.btn-ghost {
|
|
||||||
border-color: var(--font-color);
|
|
||||||
color: var(--font-color);
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.btn-ghost:focus,
|
|
||||||
.btn.btn-ghost:hover {
|
|
||||||
border-color: var(--tertiary-color);
|
|
||||||
color: var(--tertiary-color);
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.btn-ghost:hover {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-block {
|
|
||||||
width: 100%;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-default {
|
|
||||||
background-color: var(--font-color);
|
|
||||||
border-color: var(--invert-font-color);
|
|
||||||
color: var(--invert-font-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-default:hover,
|
|
||||||
.btn-default:focus:not(.btn-ghost) {
|
|
||||||
background-color: var(--secondary-color);
|
|
||||||
color: var(--invert-font-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-default.btn-ghost:focus,
|
|
||||||
.btn-default.btn-ghost:hover {
|
|
||||||
border-color: var(--secondary-color);
|
|
||||||
color: var(--secondary-color);
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-error {
|
|
||||||
color: var(--invert-font-color);
|
|
||||||
background-color: var(--error-color);
|
|
||||||
border: 1px solid var(--error-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-error:hover,
|
|
||||||
.btn-error:focus:not(.btn-ghost) {
|
|
||||||
background-color: var(--error-color);
|
|
||||||
border-color: var(--error-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-error.btn-ghost {
|
|
||||||
border-color: var(--error-color);
|
|
||||||
color: var(--error-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-error.btn-ghost:focus,
|
|
||||||
.btn-error.btn-ghost:hover {
|
|
||||||
border-color: var(--error-color);
|
|
||||||
color: var(--error-color);
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary {
|
|
||||||
color: var(--invert-font-color);
|
|
||||||
background-color: var(--primary-color);
|
|
||||||
border: 1px solid var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary:hover,
|
|
||||||
.btn-primary:focus:not(.btn-ghost) {
|
|
||||||
background-color: var(--primary-color);
|
|
||||||
border-color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary.btn-ghost {
|
|
||||||
border-color: var(--primary-color);
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary.btn-ghost:focus,
|
|
||||||
.btn-primary.btn-ghost:hover {
|
|
||||||
border-color: var(--primary-color);
|
|
||||||
color: var(--primary-color);
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-small {
|
|
||||||
padding: 0.5em 1.3em !important;
|
|
||||||
font-size: 0.9em !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-group {
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-group .btn {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-group .btn-ghost:not(:first-child) {
|
|
||||||
margin-left: -1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-card {
|
|
||||||
border: 1px solid var(--secondary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-card > header {
|
|
||||||
color: var(--invert-font-color);
|
|
||||||
text-align: center;
|
|
||||||
background-color: var(--secondary-color);
|
|
||||||
padding: 0.5em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-card > div:first-of-type {
|
|
||||||
padding: var(--global-space);
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-timeline {
|
|
||||||
position: relative;
|
|
||||||
padding-left: 70px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-timeline::before {
|
|
||||||
content: ' ';
|
|
||||||
background: var(--secondary-color);
|
|
||||||
display: inline-block;
|
|
||||||
position: absolute;
|
|
||||||
left: 35px;
|
|
||||||
width: 2px;
|
|
||||||
height: 100%;
|
|
||||||
z-index: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-timeline .terminal-card {
|
|
||||||
margin-bottom: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-timeline .terminal-card::before {
|
|
||||||
content: ' ';
|
|
||||||
background: var(--invert-font-color);
|
|
||||||
border: 2px solid var(--secondary-color);
|
|
||||||
display: inline-block;
|
|
||||||
position: absolute;
|
|
||||||
margin-top: 25px;
|
|
||||||
left: 26px;
|
|
||||||
width: 15px;
|
|
||||||
height: 15px;
|
|
||||||
z-index: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-alert {
|
|
||||||
color: var(--font-color);
|
|
||||||
padding: 1em;
|
|
||||||
border: 1px solid var(--font-color);
|
|
||||||
margin-bottom: var(--global-space);
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-alert-error {
|
|
||||||
color: var(--error-color);
|
|
||||||
border-color: var(--error-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-alert-primary {
|
|
||||||
color: var(--primary-color);
|
|
||||||
border-color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 960px) {
|
|
||||||
label {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre::-webkit-scrollbar {
|
|
||||||
height: 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 480px) {
|
|
||||||
form {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (min-width: 30em) {
|
|
||||||
.terminal-nav {
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-menu ul {
|
|
||||||
flex-direction: row;
|
|
||||||
justify-items: flex-end;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-end;
|
|
||||||
margin-top: calc(var(--global-space) * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-menu li {
|
|
||||||
margin: 0;
|
|
||||||
margin-right: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-menu li:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-media:not(:last-child) {
|
|
||||||
margin-bottom: 1.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-media-left {
|
|
||||||
padding-right: var(--global-space);
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-media-left,
|
|
||||||
.terminal-media-right {
|
|
||||||
display: table-cell;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-media-right {
|
|
||||||
padding-left: var(--global-space);
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-media-body {
|
|
||||||
display: table-cell;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-media-heading {
|
|
||||||
font-size: 1em;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-media-content {
|
|
||||||
margin-top: 0.3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-placeholder {
|
|
||||||
background-color: var(--secondary-color);
|
|
||||||
text-align: center;
|
|
||||||
color: var(--font-color);
|
|
||||||
font-size: 1rem;
|
|
||||||
border: 1px solid var(--secondary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
figure > img {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-avatarholder {
|
|
||||||
width: calc(var(--global-space) * 5);
|
|
||||||
height: calc(var(--global-space) * 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-avatarholder img {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
figure {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
figure > figcaption {
|
|
||||||
color: var(--secondary-color);
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs {
|
|
||||||
display: block;
|
|
||||||
overflow-x: auto;
|
|
||||||
padding: 0.5em;
|
|
||||||
background: var(--block-background-color);
|
|
||||||
color: var(--font-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-comment,
|
|
||||||
.hljs-quote {
|
|
||||||
color: var(--secondary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-variable {
|
|
||||||
color: var(--font-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-keyword,
|
|
||||||
.hljs-selector-tag,
|
|
||||||
.hljs-built_in,
|
|
||||||
.hljs-name,
|
|
||||||
.hljs-tag {
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-string,
|
|
||||||
.hljs-title,
|
|
||||||
.hljs-section,
|
|
||||||
.hljs-attribute,
|
|
||||||
.hljs-literal,
|
|
||||||
.hljs-template-tag,
|
|
||||||
.hljs-template-variable,
|
|
||||||
.hljs-type,
|
|
||||||
.hljs-addition {
|
|
||||||
color: var(--secondary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-string {
|
|
||||||
color: var(--secondary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-deletion,
|
|
||||||
.hljs-selector-attr,
|
|
||||||
.hljs-selector-pseudo,
|
|
||||||
.hljs-meta {
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-doctag {
|
|
||||||
color: var(--secondary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-attr {
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-symbol,
|
|
||||||
.hljs-bullet,
|
|
||||||
.hljs-link {
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-emphasis {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-strong {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
title: Kompact.io
|
||||||
|
---
|
|
@ -0,0 +1,109 @@
|
||||||
|
---
|
||||||
|
title: Are we zk-Cardano yet?
|
||||||
|
date: 2023-08-07
|
||||||
|
---
|
||||||
|
|
||||||
|
Not so long ago Emurgo announced they were doing a Cardano centered hackathon.
|
||||||
|
It was a welcome prospect - very few similar such events seem to exist in the space.
|
||||||
|
Things went monotonically south ever since the announcement, but that's a different story.
|
||||||
|
|
||||||
|
One particularly interesting quirk was that of the three "tracks" of the hackathon,
|
||||||
|
one was _Zero Knowledge_ (aka zk).
|
||||||
|
Why particularly interesting quirk? In some sense it is not surprising:
|
||||||
|
zk has been very trendy these last few years around blockchains.
|
||||||
|
However, building on Cardano is notoriously challenging.
|
||||||
|
Building with zk on a zk-native blockchain is itself a very steep learning curve.
|
||||||
|
So combining the two, zk on Cardano seemed... a bit mad.
|
||||||
|
|
||||||
|
This post is borne out of a best effort of how far "zk on Cardano" can be pushed.
|
||||||
|
|
||||||
|
## What is zk?
|
||||||
|
|
||||||
|
There is no shortage of explanations describing what zk is
|
||||||
|
( _eg_ [by Vitalik](https://vitalik.ca/general/2021/01/26/snarks.html) or [a full mooc](https://zk-learning.org/) ).
|
||||||
|
There is also a reasonable breath to the field of zk that includes things like distributed compute.
|
||||||
|
Zk involves some really neat maths that lets you do some seemingly magical feats,
|
||||||
|
and pairs well with blockchain in extending what is functionally possible.
|
||||||
|
Let's stick to a simple and prototypical example.
|
||||||
|
|
||||||
|
Suppose Alice and Bob are playing battleships.
|
||||||
|
The game begins with Alice and Bob placing their ships within their own coordinate grid.
|
||||||
|
They then take in terms picking coordinates to "bomb".
|
||||||
|
If they hit nothing, then their turn ends, but if they hit a ship then they guess again.
|
||||||
|
The winner is the first to sink all their opponent's ships.
|
||||||
|
|
||||||
|
Alice knows Bob has a reputation of being a notorious liar; how can she enjoy the game?
|
||||||
|
Each guess she makes, Bob says gleefully shouts "Miss!".
|
||||||
|
She can't ask Bob to show he's not lying by revealing the actual locations of the ships.
|
||||||
|
She could ask Charlie to independently verify Bob's not lying,
|
||||||
|
but then what if Charlie is actually on team Bob and also lies.
|
||||||
|
Or Bob might suspect Charlie is actually on team Alice, slyly brought in to give could Alice some hints.
|
||||||
|
|
||||||
|
Is there a way that Bob can prove to Alice that each guess is a miss,
|
||||||
|
but without revealing the locations of the ships either to Alice or anyone else?
|
||||||
|
|
||||||
|
The answer is yes.
|
||||||
|
Using zk Bob can produce a proof each time Alice's guess misses if and only if it honestly does.
|
||||||
|
Alice can inspect each proof and verify Bob's response.
|
||||||
|
Alice can interrogate the proof as much as she wants, but she won't learn anything more than
|
||||||
|
her guess was a miss.
|
||||||
|
|
||||||
|
There are multitude of different ways to do this,
|
||||||
|
but essentially it involves modeling the problem as a bunch of algebra
|
||||||
|
over finite fields - like a lot of cryptography.
|
||||||
|
|
||||||
|
What's the snark of zk-snark?
|
||||||
|
Snark stands for _Succinct Non-Interactive Argument of Knowledge_.
|
||||||
|
And without saying anything more: it means that Alice has to do way less algebra than Bob.
|
||||||
|
In applications this is important, because Bob might not be able to lie anymore,
|
||||||
|
but he could still waste Alice's time.
|
||||||
|
|
||||||
|
|
||||||
|
## Sudoku snark
|
||||||
|
|
||||||
|
Sudoku snark was the entrant to Emurgo hackathon.
|
||||||
|
The summary/ pitch/ story deck is [here](https://pub.kompact.io/sudoku-snark).
|
||||||
|
Links to associated repos [plutus-zk](https://github.com/waalge/plutus-zk) and [sudoku-snark](https://github.com/waalge/sudoku-snark).
|
||||||
|
|
||||||
|
Just after the hackathon got underway there was a large PR merged into the main branch of plutus.
|
||||||
|
It's a mammoth PR that is the culmination of many many months of work.
|
||||||
|
In it were some fundamental primitives needed for running zk algos.
|
||||||
|
|
||||||
|
The idea of the project was as follows:
|
||||||
|
|
||||||
|
- write a validator implementing a zk algorithm with the new primitives
|
||||||
|
- write a program to generate the setup and proofs
|
||||||
|
- try to get a version of hydra running this newest version of plutus.
|
||||||
|
|
||||||
|
Unsurprisingly to anyone who's hung around the Cardano repos long enough,
|
||||||
|
this final part is where things got stuck.
|
||||||
|
Things got as far as running a cluster of nodes in the Conway era supposedly with the latest plutus
|
||||||
|
but some unrelated changes seemed to thwart any chance of building transactions.
|
||||||
|
|
||||||
|
The validator uses [groth16](https://eprint.iacr.org/2016/260.pdf).
|
||||||
|
In part because this was already mostly available from the plutus repo itself.
|
||||||
|
It is also the most obvious candidate to begin with.
|
||||||
|
It's relatively mature, relatively simple, can be implemented from the new primitives,
|
||||||
|
and, importantly in Cardano land, has small proof size.
|
||||||
|
(As far as I know, the smallest of comparable algos.)
|
||||||
|
|
||||||
|
The program to generate the setup and proofs uses the arkworks framework.
|
||||||
|
Again this was initially inspired by a script from the IOG team.
|
||||||
|
|
||||||
|
The choice of game, sudoku, was in turn inspired by an arkworks example.
|
||||||
|
It's not the most compelling of choices, but it did for now.
|
||||||
|
|
||||||
|
The intended game play involved locking Ada at a utxo
|
||||||
|
spendable only if a player could provide proof you knew the solution.
|
||||||
|
And through the magic of zk, not disclosing to the competition the solution itself.
|
||||||
|
Other details were TBC: is it first and second prizes? are players whitelisted?
|
||||||
|
|
||||||
|
## So are we zk-Cardano yet?
|
||||||
|
|
||||||
|
We're close.
|
||||||
|
|
||||||
|
There is potentially still quite a stretch between being in the plutus repo and being run on-chain.
|
||||||
|
The word on the street is that it might happen before the end of 2023.
|
||||||
|
|
||||||
|
Before it's available on mainnet there will be versions the Cardano node available,
|
||||||
|
and so possibly plumb-able into hydra without causing oneself an aneurysm.
|
|
@ -0,0 +1,108 @@
|
||||||
|
---
|
||||||
|
title: Are we zk-Cardano yet?
|
||||||
|
date: 2023-08-07
|
||||||
|
---
|
||||||
|
|
||||||
|
Not so long ago Emurgo announced they were doing a Cardano centered hackathon.
|
||||||
|
It was a welcome prospect - very few similar such events seem to exist in the space.
|
||||||
|
Things went monotonically south ever since the announcement, but that's a different story.
|
||||||
|
|
||||||
|
One particularly interesting quirk was that of the three "tracks" of the hackathon,
|
||||||
|
one was _Zero Knowledge_ (aka zk).
|
||||||
|
Why particularly interesting quirk? In some sense it is not suprising:
|
||||||
|
zK has been very trendy these last few years around blockchains.
|
||||||
|
However, building on Cardano is notoriously challenging.
|
||||||
|
Building with zk on a zk-native blockchain is itself a very steep learning curve.
|
||||||
|
So combining the two, zk on Cardano seemed... a bit mad.
|
||||||
|
|
||||||
|
This post is bourne out of a best effort of how far "zk on cardano" can be pushed.
|
||||||
|
|
||||||
|
## What is zk?
|
||||||
|
|
||||||
|
There is no shortage of explanations describing what zk is [TODO: Links].
|
||||||
|
There is also a reasonable breath to the field of zk that includes things like distributed compute.
|
||||||
|
Zk involves some really neat maths that lets you do some seemingly magical feats,
|
||||||
|
and pairs well with blockchain in extending what is functionally possible.
|
||||||
|
Let's stick to a simple and prototypical example.
|
||||||
|
|
||||||
|
Suppose Alice and Bob are playing battleships.
|
||||||
|
The game begins with Alice and Bob placing their ships within their own coordinate grid.
|
||||||
|
They then take in terms picking coordinates to "bomb".
|
||||||
|
If they hit nothing, then their turn ends, but if they hit a ship then they guess again.
|
||||||
|
The winner is the first to sink all their oponents ships.
|
||||||
|
|
||||||
|
Alice knows Bob has a reputation of being a notorious liar; how can she enjoy the game?
|
||||||
|
Each guess she makes, Bob says gleefully shouts "Miss!".
|
||||||
|
She can't ask Bob to show he's not lying by revealing the actual locations of the ships.
|
||||||
|
She could ask Charlie to independently verify Bob's not lying,
|
||||||
|
but then what if Charlie is actually on team Bob and also lies.
|
||||||
|
Or Bob might suspect Charlie is actually on team Alice, slyly brought in to give could Alice some hints.
|
||||||
|
|
||||||
|
Is there a way that Bob can prove to Alice that each guess is a miss,
|
||||||
|
but without revealing the locations of the ships either to Alice or anyone else?
|
||||||
|
|
||||||
|
The answer is yes.
|
||||||
|
Using zk Bob can produce a proof each time Alice's guess misses if and only if it honestly does.
|
||||||
|
Alice can inspect each proof and verify Bob's response.
|
||||||
|
Alice can interogate the proof as much as she wants, but she won't learn anything more than
|
||||||
|
her guess was a miss.
|
||||||
|
|
||||||
|
There are multiplitude of different ways to do this,
|
||||||
|
but essentially it involves modelling the problem as a bunch of algebra
|
||||||
|
over finite fields - like a lot of cryptography.
|
||||||
|
|
||||||
|
What's the snark of zk-snark?
|
||||||
|
Snark stands for _Succinct Non-Interactive Argument of Knowledge_.
|
||||||
|
And without saying anything more: it means that Alice has to do way less algebra than Bob.
|
||||||
|
In applications this is important, because Bob might not be able to lie anymore,
|
||||||
|
but he could still waste Alice's time.
|
||||||
|
|
||||||
|
|
||||||
|
## Sudoku snark
|
||||||
|
|
||||||
|
Sudoku snark was the entrant to Emurgo hackathon.
|
||||||
|
The summary/ pitch/ story deck is [here](https://pub.kompact.io/sudoku-snark).
|
||||||
|
Links to associated repos [plutus-zk]() and [sudoku-snark]().
|
||||||
|
|
||||||
|
Just after the hackathon got underway there was a large PR merged into the main branch of plutus.
|
||||||
|
It's a mammoth PR that is the culmination of many many months of work.
|
||||||
|
In it were some fundamental primitives needed for running zk algos.
|
||||||
|
|
||||||
|
The idea of the project was as follows:
|
||||||
|
|
||||||
|
- write a validator implementing a zk algorithm with the new primitives
|
||||||
|
- write a programme to generate the setup and proofs
|
||||||
|
- try to get a version of hydra running this newest version of plutus.
|
||||||
|
|
||||||
|
Unsurprisingly to anyone who's hung around the Cardano repos long enough,
|
||||||
|
this final part is where things got stuck.
|
||||||
|
Things got as far as running a cluster of nodes in the conway era supposedly with the latest plutus
|
||||||
|
but some unrelated changes seemed to thwart any chance of building transactions.
|
||||||
|
|
||||||
|
The validator uses [groth16].
|
||||||
|
In part because this was already mostly available from the plutus repo itself.
|
||||||
|
It is also the most obvious candidate to begin with.
|
||||||
|
It's relatively mature, relatively simple, can be implemented from the new primitives,
|
||||||
|
and, importantly in cardano land, has small proof size.
|
||||||
|
(As far as I know, the smallest of comparable algos.)
|
||||||
|
|
||||||
|
The program to generate the setup and proofs uses the arkworks framework.
|
||||||
|
Again this was initially inspired by a script from the IOG team.
|
||||||
|
|
||||||
|
The choice of game, sudoku, was in turn inspired by an arkworks example.
|
||||||
|
It's not the most compelling of choices, but it did for now.
|
||||||
|
|
||||||
|
The intended game play involved locking ada at a utxo
|
||||||
|
spendable only if a player could provide proof you knew the solution.
|
||||||
|
And through the magic of zk, not disclosing to the competition the solution itself.
|
||||||
|
Other details were TBC: is it first and second prizes? are players whitelisted?
|
||||||
|
|
||||||
|
## So are we zk-Cardano yet?
|
||||||
|
|
||||||
|
We're close.
|
||||||
|
|
||||||
|
There is potentially still quite a stretch between being in the plutus repo and being run on-chain.
|
||||||
|
The word on the street is that it might happen before the end of 2023.
|
||||||
|
|
||||||
|
Before it's available on mainnet there will be versions the cardano node available,
|
||||||
|
and so possibly plumbable into hydra without causing oneself an aneurysm.
|
|
@ -8,5 +8,6 @@ executable site
|
||||||
build-depends: base == 4.*
|
build-depends: base == 4.*
|
||||||
, hakyll == 4.15.*
|
, hakyll == 4.15.*
|
||||||
, hip == 1.5.*
|
, hip == 1.5.*
|
||||||
|
, filepath
|
||||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
53
site.hs
53
site.hs
|
@ -2,70 +2,62 @@
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
import Data.Monoid (mappend)
|
import Data.Monoid (mappend)
|
||||||
import Hakyll
|
import Hakyll
|
||||||
|
import System.FilePath (splitExtension, joinPath, splitDirectories, replaceExtension)
|
||||||
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = hakyll $ do
|
main = hakyll $ do
|
||||||
match "content/favicon.png" $ do
|
match "content/favicon.png" $ do
|
||||||
route rmContentPrefix
|
route rmPrefix
|
||||||
compile copyFileCompiler
|
compile copyFileCompiler
|
||||||
|
|
||||||
match "content/images/*" $ do
|
match "content/images/*" $ do
|
||||||
route rmContentPrefix
|
route rmPrefix
|
||||||
compile copyFileCompiler
|
compile copyFileCompiler
|
||||||
|
|
||||||
match "content/scripts/*" $ do
|
match "content/scripts/*" $ do
|
||||||
route rmContentPrefix
|
route rmPrefix
|
||||||
compile copyFileCompiler
|
compile copyFileCompiler
|
||||||
|
|
||||||
match "content/css/*" $ do
|
match "content/css/*" $ do
|
||||||
route rmContentPrefix
|
route rmPrefix
|
||||||
compile compressCssCompiler
|
compile compressCssCompiler
|
||||||
|
|
||||||
match "content/fonts/*" $ do
|
match "content/fonts/*" $ do
|
||||||
route rmContentPrefix
|
route rmPrefix
|
||||||
compile copyFileCompiler
|
compile copyFileCompiler
|
||||||
|
|
||||||
match (fromList ["content/about.rst", "content/contact.markdown"]) $ do
|
match "content/posts/*.md" $ do
|
||||||
route $ setExtension "html"
|
route rmPrefixMd
|
||||||
compile $ pandocCompiler
|
|
||||||
>>= loadAndApplyTemplate "templates/default.html" defaultContext
|
|
||||||
>>= relativizeUrls
|
|
||||||
|
|
||||||
match "content/posts/*" $ do
|
|
||||||
route $ setExtension "html"
|
|
||||||
compile $ pandocCompiler
|
compile $ pandocCompiler
|
||||||
>>= loadAndApplyTemplate "templates/post.html" postCtx
|
>>= loadAndApplyTemplate "templates/post.html" postCtx
|
||||||
>>= loadAndApplyTemplate "templates/default.html" postCtx
|
>>= loadAndApplyTemplate "templates/default.html" postCtx
|
||||||
>>= relativizeUrls
|
>>= relativizeUrls
|
||||||
|
|
||||||
create ["archive.html"] $ do
|
create ["blog.html"] $ do
|
||||||
route idRoute
|
route idRoute
|
||||||
compile $ do
|
compile $ do
|
||||||
posts <- recentFirst =<< loadAll "content/posts/*"
|
posts <- recentFirst =<< loadAll "content/posts/*.md"
|
||||||
let archiveCtx =
|
let archiveCtx =
|
||||||
listField "posts" postCtx (return posts) `mappend`
|
listField "posts" postCtx (return posts) `mappend`
|
||||||
constField "title" "Archives" `mappend`
|
constField "title" "Blog" `mappend`
|
||||||
defaultContext
|
defaultContext
|
||||||
|
|
||||||
makeItem ""
|
makeItem ""
|
||||||
>>= loadAndApplyTemplate "templates/archive.html" archiveCtx
|
>>= loadAndApplyTemplate "templates/blog.html" archiveCtx
|
||||||
>>= loadAndApplyTemplate "templates/default.html" archiveCtx
|
>>= loadAndApplyTemplate "templates/default.html" archiveCtx
|
||||||
>>= relativizeUrls
|
>>= relativizeUrls
|
||||||
|
|
||||||
|
|
||||||
match "content/index.html" $ do
|
match "content/index.md" $ do
|
||||||
route rmContentPrefix
|
route rmPrefixMd
|
||||||
compile $ do
|
compile $ do
|
||||||
posts <- recentFirst =<< loadAll "content/posts/*"
|
let indexCtx = defaultContext
|
||||||
let indexCtx =
|
|
||||||
listField "posts" postCtx (return posts) `mappend`
|
|
||||||
defaultContext
|
|
||||||
|
|
||||||
getResourceBody
|
getResourceBody
|
||||||
>>= applyAsTemplate indexCtx
|
>>= applyAsTemplate indexCtx
|
||||||
>>= loadAndApplyTemplate "templates/default.html" indexCtx
|
>>= loadAndApplyTemplate "templates/index.html" indexCtx
|
||||||
>>= relativizeUrls
|
>>= relativizeUrls
|
||||||
|
|
||||||
match "templates/*" $ compile templateBodyCompiler
|
match "templates/*" $ compile templateBodyCompiler
|
||||||
|
@ -74,7 +66,16 @@ main = hakyll $ do
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
postCtx :: Context String
|
postCtx :: Context String
|
||||||
postCtx =
|
postCtx =
|
||||||
dateField "date" "%B %e, %Y" `mappend`
|
dateField "date" "%Y-%m-%d" `mappend`
|
||||||
defaultContext
|
defaultContext
|
||||||
|
|
||||||
rmContentPrefix = gsubRoute "content/" (const "")
|
setExtensionInner :: String -> FilePath -> FilePath
|
||||||
|
setExtensionInner = flip replaceExtension
|
||||||
|
|
||||||
|
rmPrefixInner :: FilePath -> FilePath
|
||||||
|
rmPrefixInner = joinPath . tail . splitDirectories
|
||||||
|
|
||||||
|
rmPrefix :: Routes
|
||||||
|
rmPrefix = customRoute $ rmPrefixInner . toFilePath
|
||||||
|
|
||||||
|
rmPrefixMd = customRoute $ rmPrefixInner . setExtensionInner "html" . toFilePath
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
Here you can find all my previous posts:
|
|
||||||
$partial("templates/post-list.html")$
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
<section id="services" class="py-6 px-2 flex flex-col gap-12">
|
||||||
|
<header class="text-3xl">
|
||||||
|
# blog
|
||||||
|
</header>
|
||||||
|
<div class="text-gray-700 mt-4">
|
||||||
|
A nascent initiative sharing some of the things happening at Kompact.io.
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="py-6 px-2 flex flex-col gap-12">
|
||||||
|
$partial("templates/post-list.html")$
|
||||||
|
</section>
|
|
@ -6,6 +6,7 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="icon" type="image/x-icon" href="/favicon.png">
|
<link rel="icon" type="image/x-icon" href="/favicon.png">
|
||||||
<link href="/css/mini.css" rel="stylesheet">
|
<link href="/css/mini.css" rel="stylesheet">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -13,18 +14,11 @@
|
||||||
<hr />
|
<hr />
|
||||||
$partial("templates/nav.html")$
|
$partial("templates/nav.html")$
|
||||||
<hr />
|
<hr />
|
||||||
$partial("templates/hero.html")$
|
$body$
|
||||||
<hr />
|
|
||||||
$partial("templates/services.html")$
|
|
||||||
<hr />
|
|
||||||
$partial("templates/pricing.html")$
|
|
||||||
<hr />
|
|
||||||
$partial("templates/contact.html")$
|
|
||||||
<hr />
|
<hr />
|
||||||
$partial("templates/footer.html")$
|
$partial("templates/footer.html")$
|
||||||
<hr />
|
|
||||||
$body$
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -0,0 +1,30 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="icon" type="image/x-icon" href="/favicon.png">
|
||||||
|
<title>$title$</title>
|
||||||
|
<link href="/css/mini.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container mx-auto">
|
||||||
|
<hr />
|
||||||
|
$partial("templates/nav.html")$
|
||||||
|
<hr />
|
||||||
|
$partial("templates/hero.html")$
|
||||||
|
<hr />
|
||||||
|
$partial("templates/services.html")$
|
||||||
|
<hr />
|
||||||
|
$partial("templates/pricing.html")$
|
||||||
|
<hr />
|
||||||
|
$partial("templates/contact.html")$
|
||||||
|
<hr />
|
||||||
|
$partial("templates/footer.html")$
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -1,25 +1,22 @@
|
||||||
<nav class="mx-2 sm:mx-4">
|
<nav class="mx-2 sm:mx-4">
|
||||||
<div class="relative flex h-16 items-center justify-between ">
|
<div class="relative flex h-16 items-center justify-between ">
|
||||||
<div>
|
<div>
|
||||||
Kompact.io
|
<a href="/">
|
||||||
|
Kompact.io
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<ul class="flex flex-row gap-4 md:gap-8">
|
<ul class="flex flex-row gap-4 md:gap-8">
|
||||||
<li>
|
<li>
|
||||||
<a href="#services">
|
<a href="/index.html#contact">
|
||||||
services
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="#pricing">
|
|
||||||
pricing
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="#contact">
|
|
||||||
contact
|
contact
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/blog.html">
|
||||||
|
blog
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
<ul>
|
<ul class="text-lg ml-4">
|
||||||
$for(posts)$
|
$for(posts)$
|
||||||
<li>
|
<li class="mt-4">
|
||||||
<a href="$url$">$title$</a> - $date$
|
<a href="$url$">
|
||||||
</li>
|
<span class="text-gray-700">
|
||||||
$endfor$
|
$date$ ::
|
||||||
|
</span>
|
||||||
|
$title$
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
$endfor$
|
||||||
</ul>
|
</ul>
|
|
@ -1,11 +1,20 @@
|
||||||
<article>
|
<article>
|
||||||
<section class="header">
|
<section class="header">
|
||||||
Posted on $date$
|
<h1>
|
||||||
$if(author)$
|
$title$
|
||||||
by $author$
|
</h1>
|
||||||
$endif$
|
$if(date)$
|
||||||
</section>
|
<p>
|
||||||
<section>
|
Posted on $date$
|
||||||
$body$
|
</p>
|
||||||
</section>
|
$endif$
|
||||||
|
$if(author)$
|
||||||
|
<p>
|
||||||
|
by $author$
|
||||||
|
</p>
|
||||||
|
$endif$
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
$body$
|
||||||
|
</section>
|
||||||
</article>
|
</article>
|
Loading…
Reference in New Issue