Compare commits
24 Commits
flake-upda
...
main
Author | SHA1 | Date | |
---|---|---|---|
7e9d590408 | |||
|
ae0ca32563 | ||
3a26ac4323 | |||
|
fc8c260cb5 | ||
96bba0171f | |||
|
584c6f2e01 | ||
25f0ea66b7 | |||
|
fe19b2591c | ||
58ea1d309a | |||
|
27e955e12f | ||
75c7f6052c | |||
|
2834c998f2 | ||
42a4bd5068 | |||
c225dc56b1 | |||
7910e332be | |||
d72a88cd3a | |||
46b4c704ac | |||
3461ee83e0 | |||
6591d73f7c | |||
345216fcb4 | |||
b410b826f4 | |||
0c3192e3cc | |||
|
7bc0506669 | ||
320090825e |
23
README.md
@ -1,27 +1,13 @@
|
||||
# Getting start with the repo
|
||||
|
||||
This is the source for the homepage.
|
||||
We use [zola](https://www.getzola.org/) for building a static website.
|
||||
|
||||
## Build the homepage
|
||||
|
||||
This will build the website including pages defined in the clan-core repo under `/docs`:
|
||||
|
||||
```command
|
||||
$ nix build
|
||||
```
|
||||
This is the source for the Clan homepage.
|
||||
|
||||
## Start a local webserver
|
||||
|
||||
This server will include all the pages from clan-core, but doesn't automatically refresh. Also make sure to wipe your browsers cache after each change.
|
||||
|
||||
```command
|
||||
$ nix run .#serve
|
||||
```
|
||||
|
||||
## zola build & serve
|
||||
Alternatively `zola build` and `zola serve` can be used for development but the result will be missing the pages defined in the clan-core repo.
|
||||
|
||||
## Contributing
|
||||
|
||||
Send changes to https://git.clan.lol/clan/clan-homepage
|
||||
@ -31,10 +17,3 @@ Send changes to https://git.clan.lol/clan/clan-homepage
|
||||
```
|
||||
$ nix run .#deploy
|
||||
```
|
||||
|
||||
|
||||
## Create a new post
|
||||
|
||||
```
|
||||
$ nix run .#new-post "September Changelog"
|
||||
```
|
||||
|
@ -1,41 +0,0 @@
|
||||
{
|
||||
perSystem = {
|
||||
lib,
|
||||
pkgs,
|
||||
self',
|
||||
...
|
||||
}: {
|
||||
apps.new-post.program = builtins.toString (pkgs.writeShellScript "new-post.sh" ''
|
||||
export PATH="${lib.makeBinPath [
|
||||
pkgs.coreutils pkgs.gitMinimal
|
||||
]}"
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: new-post.sh <title>"
|
||||
exit 1
|
||||
fi
|
||||
title=$(echo "$1" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
|
||||
root=$(git rev-parse --show-toplevel)
|
||||
fname="$root/content/blog/$(date +%Y-%m-%d)-$title.md"
|
||||
if [ -f "$fname" ]; then
|
||||
echo "File already exists: $fname"
|
||||
exit 1
|
||||
fi
|
||||
cat <<EOF > "$fname"
|
||||
+++
|
||||
title = "$1"
|
||||
date = "$(date --iso-8601=seconds)"
|
||||
draft = true
|
||||
template = "blog/page.html"
|
||||
[taxonomies]
|
||||
authors = [] # TODO
|
||||
[extra]
|
||||
lead = "Some lead"
|
||||
+++
|
||||
|
||||
Some text
|
||||
EOF
|
||||
echo "Created $fname"
|
||||
git add "$fname"
|
||||
'');
|
||||
};
|
||||
}
|
@ -28,7 +28,7 @@
|
||||
packages.serve = pkgs.writeShellScriptBin "serve-local" ''
|
||||
echo "serving: ${self'.packages.website-localhost}"
|
||||
${pkgs.python3}/bin/python -m http.server 1111 \
|
||||
-d ${self'.packages.website-localhost}
|
||||
-d website
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
20
flake.lock
@ -5,11 +5,11 @@
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1719745305,
|
||||
"narHash": "sha256-xwgjVUpqSviudEkpQnioeez1Uo2wzrsMaJKJClh+Bls=",
|
||||
"lastModified": 1722555600,
|
||||
"narHash": "sha256-XOQkdLafnb/p9ij77byFQjDf5m5QYl9b2REiVClC+x4=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "c3c5ecc05edc7dafba779c6c1a61cd08ac6583e9",
|
||||
"rev": "8471fe90ad337a8074e957b69ca4d0089218391d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -20,11 +20,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1719506693,
|
||||
"narHash": "sha256-C8e9S7RzshSdHB7L+v9I51af1gDM5unhJ2xO1ywxNH8=",
|
||||
"lastModified": 1723637854,
|
||||
"narHash": "sha256-med8+5DSWa2UnOqtdICndjDAEjxr5D7zaIiK4pn0Q7c=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b2852eb9365c6de48ffb0dc2c9562591f652242a",
|
||||
"rev": "c3aa7b8938b17aebd2deecf7be0636000d62a2b9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -36,14 +36,14 @@
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1717284937,
|
||||
"narHash": "sha256-lIbdfCsf8LMFloheeE6N31+BMIeixqyQWbSr2vk79EQ=",
|
||||
"lastModified": 1722555339,
|
||||
"narHash": "sha256-uFf2QeW7eAHlYXuDktm9c25OxOyCoUOQmh5SZ9amE5Q=",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz"
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/a5d394176e64ab29c852d03346c1fc9b0b7d33eb.tar.gz"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz"
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/a5d394176e64ab29c852d03346c1fc9b0b7d33eb.tar.gz"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
|
@ -12,7 +12,6 @@
|
||||
imports = [
|
||||
./flake-parts/deploy.nix
|
||||
./flake-parts/devShells
|
||||
./flake-parts/new-post.nix
|
||||
./flake-parts/website.nix
|
||||
];
|
||||
perSystem = {pkgs, ...}: {
|
||||
|
BIN
static/cLAN/cLAN--black.jpg
Normal file
After Width: | Height: | Size: 266 KiB |
BIN
static/cLAN/cLAN--black.png
Normal file
After Width: | Height: | Size: 108 KiB |
BIN
static/cLAN/cLAN--white.png
Normal file
After Width: | Height: | Size: 106 KiB |
7823
static/cLAN/cLAN.ai
Normal file
BIN
static/cLAN/cLAN.png
Normal file
After Width: | Height: | Size: 149 KiB |
7121
static/cLAN/cLAN.svg
Normal file
After Width: | Height: | Size: 682 KiB |
BIN
static/cLAN/with text favicon/128x128.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
static/cLAN/with text favicon/16x16.png
Normal file
After Width: | Height: | Size: 555 B |
BIN
static/cLAN/with text favicon/32x32.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
static/cLAN/with text favicon/64x64.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
static/cLAN/without text favicon- black/128x128.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
static/cLAN/without text favicon- black/16x16.png
Normal file
After Width: | Height: | Size: 360 B |
BIN
static/cLAN/without text favicon- black/32x32.png
Normal file
After Width: | Height: | Size: 815 B |
BIN
static/cLAN/without text favicon- black/64x64.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
static/cLAN/without text favicon- white/128x128.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
static/cLAN/without text favicon- white/16x16.png
Normal file
After Width: | Height: | Size: 375 B |
BIN
static/cLAN/without text favicon- white/32x32.png
Normal file
After Width: | Height: | Size: 717 B |
BIN
static/cLAN/without text favicon- white/64x64.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
static/cLAN/without text favicon/128x128.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
static/cLAN/without text favicon/16x16.png
Normal file
After Width: | Height: | Size: 490 B |
BIN
static/cLAN/without text favicon/32x32.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
static/cLAN/without text favicon/64x64.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 167 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 174 KiB |
@ -150,6 +150,9 @@ section {
|
||||
|
||||
body {
|
||||
line-height: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: 3.5em;
|
||||
}
|
||||
|
||||
ol,
|
||||
@ -210,11 +213,6 @@ html {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
background: #ffffff;
|
||||
}
|
||||
@ -248,7 +246,6 @@ a {
|
||||
-webkit-transition: color 0.2s ease-in-out, border-bottom-color 0.2s ease-in-out;
|
||||
-ms-transition: color 0.2s ease-in-out, border-bottom-color 0.2s ease-in-out;
|
||||
transition: color 0.2s ease-in-out, border-bottom-color 0.2s ease-in-out;
|
||||
border-bottom: dotted 1px;
|
||||
color: #4eb980;
|
||||
text-decoration: none;
|
||||
}
|
||||
@ -379,22 +376,6 @@ blockquote {
|
||||
|
||||
}
|
||||
|
||||
@media screen and (max-width: 736px) {
|
||||
|
||||
.container {
|
||||
width: 90% !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
|
||||
.container {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Row */
|
||||
|
||||
.row {
|
||||
@ -1863,7 +1844,12 @@ blockquote {
|
||||
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
@media screen and (max-width: 580px) {
|
||||
|
||||
.header-nav-links a:first-child {
|
||||
flex-basis: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
@ -2328,6 +2314,21 @@ textarea {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.image p {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
background-color: #2C2C2C;
|
||||
width: 66%;
|
||||
padding: 0.1em 0.5em 0.1em 0.5em;
|
||||
}
|
||||
|
||||
.image:after {
|
||||
-moz-transition: opacity 0.25s ease-in-out;
|
||||
-webkit-transition: opacity 0.25s ease-in-out;
|
||||
@ -2875,7 +2876,7 @@ input[type="button"].small,
|
||||
background-repeat: repeat-x, repeat, no-repeat;
|
||||
background-size: 3200px 460px, auto, cover;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
padding: 10em 0 20em 0;
|
||||
padding: 1em 0 10vw 0;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
@ -2953,7 +2954,7 @@ input[type="button"].small,
|
||||
}
|
||||
|
||||
#header h1 {
|
||||
font-size: 2.5em;
|
||||
font-size: 2em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@ -3128,6 +3129,9 @@ input[type="button"].small,
|
||||
font-size: 14pt;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.15em;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
@ -3141,31 +3145,23 @@ input[type="button"].small,
|
||||
header.major p {
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
|
||||
#header {
|
||||
padding: 8em 0 16em 0;
|
||||
}
|
||||
|
||||
#header h1 {
|
||||
font-size: 2.25em;
|
||||
}
|
||||
|
||||
#header p {
|
||||
font-size: 1.25em;
|
||||
line-height: 1.65em;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Normal */
|
||||
|
||||
@media screen and (max-width: 1280px) {
|
||||
|
||||
#header {
|
||||
padding-bottom: 6em;
|
||||
}
|
||||
|
||||
#header h1 {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
#clan-logo {
|
||||
width: 14em;
|
||||
height: 14em;
|
||||
width: 11em;
|
||||
height: 11em;
|
||||
}
|
||||
|
||||
/* Basic */
|
||||
@ -3224,7 +3220,6 @@ input[type="button"].small,
|
||||
background-attachment: scroll, scroll, scroll;
|
||||
background-image: url("images/top-1600.svg"), url("images/overlay.png"), url("../../images/header.jpg");
|
||||
background-size: 1600px 230px, auto, cover;
|
||||
padding: 6em 0 12em 0;
|
||||
}
|
||||
|
||||
#header:before {
|
||||
@ -3235,14 +3230,6 @@ input[type="button"].small,
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
#header h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
#header p {
|
||||
font-size: 1.15em;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
|
||||
#footer {
|
||||
@ -3292,10 +3279,6 @@ input[type="button"].small,
|
||||
height: 14em;
|
||||
}
|
||||
|
||||
#header h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
/* Section/Article */
|
||||
|
||||
header.major {
|
||||
@ -3315,15 +3298,15 @@ input[type="button"].small,
|
||||
@media screen and (max-width: 736px) {
|
||||
|
||||
#clan-logo {
|
||||
width: 12em;
|
||||
height: 12em;
|
||||
width: 11em;
|
||||
height: 11em;
|
||||
}
|
||||
|
||||
|
||||
/* Basic */
|
||||
|
||||
h2 {
|
||||
font-size: 1em;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@ -3399,7 +3382,6 @@ input[type="button"].small,
|
||||
#header {
|
||||
background-image: url("images/top-1280.svg"), url("images/overlay.png"), url("../../images/header.jpg");
|
||||
background-size: 1280px 184px, auto, cover;
|
||||
padding: 3em 0 7em 0;
|
||||
}
|
||||
|
||||
#header:before {
|
||||
@ -3410,18 +3392,6 @@ input[type="button"].small,
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
#header .logo {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
#header h1 {
|
||||
font-size: 1.75em;
|
||||
}
|
||||
|
||||
#header p {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
|
||||
#footer {
|
||||
@ -3456,10 +3426,6 @@ input[type="button"].small,
|
||||
height: 10em;
|
||||
}
|
||||
|
||||
#header h1 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
/* Section/Article */
|
||||
|
||||
header.major {
|
||||
@ -3522,12 +3488,6 @@ input[type="button"].small,
|
||||
|
||||
/* Header */
|
||||
|
||||
#header {
|
||||
padding-left: 2em;
|
||||
padding-right: 2em;
|
||||
padding-top: 5em;
|
||||
}
|
||||
|
||||
#header br {
|
||||
display: none;
|
||||
}
|
||||
|
@ -1,223 +0,0 @@
|
||||
// breakpoints.scss v1.0 | @ajlkn | MIT licensed */
|
||||
|
||||
// Vars.
|
||||
|
||||
/// Breakpoints.
|
||||
/// @var {list}
|
||||
$breakpoints: () !global;
|
||||
|
||||
// Mixins.
|
||||
|
||||
/// Sets breakpoints.
|
||||
/// @param {map} $x Breakpoints.
|
||||
@mixin breakpoints($x: ()) {
|
||||
$breakpoints: $x !global;
|
||||
}
|
||||
|
||||
/// Wraps @content in a @media block targeting a specific orientation.
|
||||
/// @param {string} $orientation Orientation.
|
||||
@mixin orientation($orientation) {
|
||||
@media screen and (orientation: #{$orientation}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// Wraps @content in a @media block using a given query.
|
||||
/// @param {string} $query Query.
|
||||
@mixin breakpoint($query: null) {
|
||||
|
||||
$breakpoint: null;
|
||||
$op: null;
|
||||
$media: null;
|
||||
|
||||
// Determine operator, breakpoint.
|
||||
|
||||
// Greater than or equal.
|
||||
@if (str-slice($query, 0, 2) == '>=') {
|
||||
|
||||
$op: 'gte';
|
||||
$breakpoint: str-slice($query, 3);
|
||||
|
||||
}
|
||||
|
||||
// Less than or equal.
|
||||
@elseif (str-slice($query, 0, 2) == '<=') {
|
||||
|
||||
$op: 'lte';
|
||||
$breakpoint: str-slice($query, 3);
|
||||
|
||||
}
|
||||
|
||||
// Greater than.
|
||||
@elseif (str-slice($query, 0, 1) == '>') {
|
||||
|
||||
$op: 'gt';
|
||||
$breakpoint: str-slice($query, 2);
|
||||
|
||||
}
|
||||
|
||||
// Less than.
|
||||
@elseif (str-slice($query, 0, 1) == '<') {
|
||||
|
||||
$op: 'lt';
|
||||
$breakpoint: str-slice($query, 2);
|
||||
|
||||
}
|
||||
|
||||
// Not.
|
||||
@elseif (str-slice($query, 0, 1) == '!') {
|
||||
|
||||
$op: 'not';
|
||||
$breakpoint: str-slice($query, 2);
|
||||
|
||||
}
|
||||
|
||||
// Equal.
|
||||
@else {
|
||||
|
||||
$op: 'eq';
|
||||
$breakpoint: $query;
|
||||
|
||||
}
|
||||
|
||||
// Build media.
|
||||
@if ($breakpoint and map-has-key($breakpoints, $breakpoint)) {
|
||||
|
||||
$a: map-get($breakpoints, $breakpoint);
|
||||
|
||||
// Range.
|
||||
@if (type-of($a) == 'list') {
|
||||
|
||||
$x: nth($a, 1);
|
||||
$y: nth($a, 2);
|
||||
|
||||
// Max only.
|
||||
@if ($x == null) {
|
||||
|
||||
// Greater than or equal (>= 0 / anything)
|
||||
@if ($op == 'gte') {
|
||||
$media: 'screen';
|
||||
}
|
||||
|
||||
// Less than or equal (<= y)
|
||||
@elseif ($op == 'lte') {
|
||||
$media: 'screen and (max-width: ' + $y + ')';
|
||||
}
|
||||
|
||||
// Greater than (> y)
|
||||
@elseif ($op == 'gt') {
|
||||
$media: 'screen and (min-width: ' + ($y + 1) + ')';
|
||||
}
|
||||
|
||||
// Less than (< 0 / invalid)
|
||||
@elseif ($op == 'lt') {
|
||||
$media: 'screen and (max-width: -1px)';
|
||||
}
|
||||
|
||||
// Not (> y)
|
||||
@elseif ($op == 'not') {
|
||||
$media: 'screen and (min-width: ' + ($y + 1) + ')';
|
||||
}
|
||||
|
||||
// Equal (<= y)
|
||||
@else {
|
||||
$media: 'screen and (max-width: ' + $y + ')';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Min only.
|
||||
@else if ($y == null) {
|
||||
|
||||
// Greater than or equal (>= x)
|
||||
@if ($op == 'gte') {
|
||||
$media: 'screen and (min-width: ' + $x + ')';
|
||||
}
|
||||
|
||||
// Less than or equal (<= inf / anything)
|
||||
@elseif ($op == 'lte') {
|
||||
$media: 'screen';
|
||||
}
|
||||
|
||||
// Greater than (> inf / invalid)
|
||||
@elseif ($op == 'gt') {
|
||||
$media: 'screen and (max-width: -1px)';
|
||||
}
|
||||
|
||||
// Less than (< x)
|
||||
@elseif ($op == 'lt') {
|
||||
$media: 'screen and (max-width: ' + ($x - 1) + ')';
|
||||
}
|
||||
|
||||
// Not (< x)
|
||||
@elseif ($op == 'not') {
|
||||
$media: 'screen and (max-width: ' + ($x - 1) + ')';
|
||||
}
|
||||
|
||||
// Equal (>= x)
|
||||
@else {
|
||||
$media: 'screen and (min-width: ' + $x + ')';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Min and max.
|
||||
@else {
|
||||
|
||||
// Greater than or equal (>= x)
|
||||
@if ($op == 'gte') {
|
||||
$media: 'screen and (min-width: ' + $x + ')';
|
||||
}
|
||||
|
||||
// Less than or equal (<= y)
|
||||
@elseif ($op == 'lte') {
|
||||
$media: 'screen and (max-width: ' + $y + ')';
|
||||
}
|
||||
|
||||
// Greater than (> y)
|
||||
@elseif ($op == 'gt') {
|
||||
$media: 'screen and (min-width: ' + ($y + 1) + ')';
|
||||
}
|
||||
|
||||
// Less than (< x)
|
||||
@elseif ($op == 'lt') {
|
||||
$media: 'screen and (max-width: ' + ($x - 1) + ')';
|
||||
}
|
||||
|
||||
// Not (< x and > y)
|
||||
@elseif ($op == 'not') {
|
||||
$media: 'screen and (max-width: ' + ($x - 1) + '), screen and (min-width: ' + ($y + 1) + ')';
|
||||
}
|
||||
|
||||
// Equal (>= x and <= y)
|
||||
@else {
|
||||
$media: 'screen and (min-width: ' + $x + ') and (max-width: ' + $y + ')';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// String.
|
||||
@else {
|
||||
|
||||
// Missing a media type? Prefix with "screen".
|
||||
@if (str-slice($a, 0, 1) == '(') {
|
||||
$media: 'screen and ' + $a;
|
||||
}
|
||||
|
||||
// Otherwise, use as-is.
|
||||
@else {
|
||||
$media: $a;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Output.
|
||||
@media #{$media} {
|
||||
@content;
|
||||
}
|
||||
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
/// Removes a specific item from a list.
|
||||
/// @author Hugo Giraudel
|
||||
/// @param {list} $list List.
|
||||
/// @param {integer} $index Index.
|
||||
/// @return {list} Updated list.
|
||||
@function remove-nth($list, $index) {
|
||||
|
||||
$result: null;
|
||||
|
||||
@if type-of($index) != number {
|
||||
@warn "$index: #{quote($index)} is not a number for `remove-nth`.";
|
||||
}
|
||||
@else if $index == 0 {
|
||||
@warn "List index 0 must be a non-zero integer for `remove-nth`.";
|
||||
}
|
||||
@else if abs($index) > length($list) {
|
||||
@warn "List index is #{$index} but list is only #{length($list)} item long for `remove-nth`.";
|
||||
}
|
||||
@else {
|
||||
|
||||
$result: ();
|
||||
$index: if($index < 0, length($list) + $index + 1, $index);
|
||||
|
||||
@for $i from 1 through length($list) {
|
||||
|
||||
@if $i != $index {
|
||||
$result: append($result, nth($list, $i));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@return $result;
|
||||
|
||||
}
|
||||
|
||||
/// Gets a value from a map.
|
||||
/// @author Hugo Giraudel
|
||||
/// @param {map} $map Map.
|
||||
/// @param {string} $keys Key(s).
|
||||
/// @return {string} Value.
|
||||
@function val($map, $keys...) {
|
||||
|
||||
@if nth($keys, 1) == null {
|
||||
$keys: remove-nth($keys, 1);
|
||||
}
|
||||
|
||||
@each $key in $keys {
|
||||
$map: map-get($map, $key);
|
||||
}
|
||||
|
||||
@return $map;
|
||||
|
||||
}
|
||||
|
||||
/// Gets a duration value.
|
||||
/// @param {string} $keys Key(s).
|
||||
/// @return {string} Value.
|
||||
@function _duration($keys...) {
|
||||
@return val($duration, $keys...);
|
||||
}
|
||||
|
||||
/// Gets a font value.
|
||||
/// @param {string} $keys Key(s).
|
||||
/// @return {string} Value.
|
||||
@function _font($keys...) {
|
||||
@return val($font, $keys...);
|
||||
}
|
||||
|
||||
/// Gets a misc value.
|
||||
/// @param {string} $keys Key(s).
|
||||
/// @return {string} Value.
|
||||
@function _misc($keys...) {
|
||||
@return val($misc, $keys...);
|
||||
}
|
||||
|
||||
/// Gets a palette value.
|
||||
/// @param {string} $keys Key(s).
|
||||
/// @return {string} Value.
|
||||
@function _palette($keys...) {
|
||||
@return val($palette, $keys...);
|
||||
}
|
||||
|
||||
/// Gets a size value.
|
||||
/// @param {string} $keys Key(s).
|
||||
/// @return {string} Value.
|
||||
@function _size($keys...) {
|
||||
@return val($size, $keys...);
|
||||
}
|
@ -1,149 +0,0 @@
|
||||
// html-grid.scss v1.0 | @ajlkn | MIT licensed */
|
||||
|
||||
// Mixins.
|
||||
|
||||
/// Initializes the current element as an HTML grid.
|
||||
/// @param {mixed} $gutters Gutters (either a single number to set both column/row gutters, or a list to set them individually).
|
||||
/// @param {mixed} $suffix Column class suffix (optional; either a single suffix or a list).
|
||||
@mixin html-grid($gutters: 1.5em, $suffix: '') {
|
||||
|
||||
// Initialize.
|
||||
$cols: 12;
|
||||
$multipliers: 0, 0.25, 0.5, 1, 1.50, 2.00;
|
||||
$unit: 100% / $cols;
|
||||
|
||||
// Suffixes.
|
||||
$suffixes: null;
|
||||
|
||||
@if (type-of($suffix) == 'list') {
|
||||
$suffixes: $suffix;
|
||||
}
|
||||
@else {
|
||||
$suffixes: ($suffix);
|
||||
}
|
||||
|
||||
// Gutters.
|
||||
$guttersCols: null;
|
||||
$guttersRows: null;
|
||||
|
||||
@if (type-of($gutters) == 'list') {
|
||||
|
||||
$guttersCols: nth($gutters, 1);
|
||||
$guttersRows: nth($gutters, 2);
|
||||
|
||||
}
|
||||
@else {
|
||||
|
||||
$guttersCols: $gutters;
|
||||
$guttersRows: 0;
|
||||
|
||||
}
|
||||
|
||||
// Row.
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
box-sizing: border-box;
|
||||
align-items: stretch;
|
||||
|
||||
// Columns.
|
||||
> * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
// Gutters.
|
||||
&.gtr-uniform {
|
||||
> * {
|
||||
> :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Alignment.
|
||||
&.aln-left {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
&.aln-center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&.aln-right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
&.aln-top {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
&.aln-middle {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&.aln-bottom {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
// Step through suffixes.
|
||||
@each $suffix in $suffixes {
|
||||
|
||||
// Suffix.
|
||||
@if ($suffix != '') {
|
||||
$suffix: '-' + $suffix;
|
||||
}
|
||||
@else {
|
||||
$suffix: '';
|
||||
}
|
||||
|
||||
// Row.
|
||||
|
||||
// Important.
|
||||
> .imp#{$suffix} {
|
||||
order: -1;
|
||||
}
|
||||
|
||||
// Columns, offsets.
|
||||
@for $i from 1 through $cols {
|
||||
> .col-#{$i}#{$suffix} {
|
||||
width: $unit * $i;
|
||||
}
|
||||
|
||||
> .off-#{$i}#{$suffix} {
|
||||
margin-left: $unit * $i;
|
||||
}
|
||||
}
|
||||
|
||||
// Step through multipliers.
|
||||
@each $multiplier in $multipliers {
|
||||
|
||||
// Gutters.
|
||||
$class: null;
|
||||
|
||||
@if ($multiplier != 1) {
|
||||
$class: '.gtr-' + ($multiplier * 100);
|
||||
}
|
||||
|
||||
&#{$class} {
|
||||
margin-top: ($guttersRows * $multiplier * -1);
|
||||
margin-left: ($guttersCols * $multiplier * -1);
|
||||
|
||||
> * {
|
||||
padding: ($guttersRows * $multiplier) 0 0 ($guttersCols * $multiplier);
|
||||
}
|
||||
|
||||
// Uniform.
|
||||
&.gtr-uniform {
|
||||
margin-top: $guttersCols * $multiplier * -1;
|
||||
|
||||
> * {
|
||||
padding-top: $guttersCols * $multiplier;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
/// Makes an element's :before pseudoelement a FontAwesome icon.
|
||||
/// @param {string} $content Optional content value to use.
|
||||
/// @param {string} $category Optional category to use.
|
||||
/// @param {string} $where Optional pseudoelement to target (before or after).
|
||||
@mixin icon($content: false, $category: regular, $where: before) {
|
||||
|
||||
text-decoration: none;
|
||||
|
||||
&:#{$where} {
|
||||
|
||||
@if $content {
|
||||
content: $content;
|
||||
}
|
||||
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
display: inline-block;
|
||||
font-style: normal;
|
||||
font-variant: normal;
|
||||
text-rendering: auto;
|
||||
line-height: 1;
|
||||
text-transform: none !important;
|
||||
|
||||
@if ($category == brands) {
|
||||
font-family: 'Font Awesome 5 Brands';
|
||||
}
|
||||
@elseif ($category == solid) {
|
||||
font-family: 'Font Awesome 5 Free';
|
||||
font-weight: 900;
|
||||
}
|
||||
@else {
|
||||
font-family: 'Font Awesome 5 Free';
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Applies padding to an element, taking the current element-margin value into account.
|
||||
/// @param {mixed} $tb Top/bottom padding.
|
||||
/// @param {mixed} $lr Left/right padding.
|
||||
/// @param {list} $pad Optional extra padding (in the following order top, right, bottom, left)
|
||||
/// @param {bool} $important If true, adds !important.
|
||||
@mixin padding($tb, $lr, $pad: (0,0,0,0), $important: null) {
|
||||
|
||||
@if $important {
|
||||
$important: '!important';
|
||||
}
|
||||
|
||||
$x: 0.1em;
|
||||
|
||||
@if unit(_size(element-margin)) == 'rem' {
|
||||
$x: 0.1rem;
|
||||
}
|
||||
|
||||
padding: ($tb + nth($pad,1)) ($lr + nth($pad,2)) max($x, $tb - _size(element-margin) + nth($pad,3)) ($lr + nth($pad,4)) #{$important};
|
||||
|
||||
}
|
||||
|
||||
/// Encodes a SVG data URL so IE doesn't choke (via codepen.io/jakob-e/pen/YXXBrp).
|
||||
/// @param {string} $svg SVG data URL.
|
||||
/// @return {string} Encoded SVG data URL.
|
||||
@function svg-url($svg) {
|
||||
|
||||
$svg: str-replace($svg, '"', '\'');
|
||||
$svg: str-replace($svg, '%', '%25');
|
||||
$svg: str-replace($svg, '<', '%3C');
|
||||
$svg: str-replace($svg, '>', '%3E');
|
||||
$svg: str-replace($svg, '&', '%26');
|
||||
$svg: str-replace($svg, '#', '%23');
|
||||
$svg: str-replace($svg, '{', '%7B');
|
||||
$svg: str-replace($svg, '}', '%7D');
|
||||
$svg: str-replace($svg, ';', '%3B');
|
||||
|
||||
@return url("data:image/svg+xml;charset=utf8,#{$svg}");
|
||||
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
// Misc.
|
||||
$misc: (
|
||||
);
|
||||
|
||||
// Duration.
|
||||
$duration: (
|
||||
);
|
||||
|
||||
// Size.
|
||||
$size: (
|
||||
border-radius: 4px
|
||||
);
|
||||
|
||||
// Font.
|
||||
$font: (
|
||||
);
|
||||
|
||||
// Palette.
|
||||
$palette: (
|
||||
bg: #ffffff,
|
||||
fg: #6e6e6e,
|
||||
fg-light: #888888,
|
||||
fg-bold: #5b5b5b,
|
||||
border: rgba(224,224,224,0.75),
|
||||
border-bg: rgba(224,224,224,0.15),
|
||||
border-bg2: rgba(224,224,224,0.35),
|
||||
|
||||
accent1: (
|
||||
bg: #4eb980,
|
||||
fg: rgba(255,255,255,0.8),
|
||||
fg-light: rgba(255,255,255,0.5),
|
||||
fg-bold: #ffffff
|
||||
),
|
||||
|
||||
accent2: (
|
||||
bg: #544d55,
|
||||
fg: rgba(255,255,255,0.8),
|
||||
fg-light: rgba(255,255,255,0.35),
|
||||
fg-bold: #ffffff
|
||||
)
|
||||
);
|
@ -1,376 +0,0 @@
|
||||
// vendor.scss v1.0 | @ajlkn | MIT licensed */
|
||||
|
||||
// Vars.
|
||||
|
||||
/// Vendor prefixes.
|
||||
/// @var {list}
|
||||
$vendor-prefixes: (
|
||||
'-moz-',
|
||||
'-webkit-',
|
||||
'-ms-',
|
||||
''
|
||||
);
|
||||
|
||||
/// Properties that should be vendorized.
|
||||
/// Data via caniuse.com, github.com/postcss/autoprefixer, and developer.mozilla.org
|
||||
/// @var {list}
|
||||
$vendor-properties: (
|
||||
|
||||
// Animation.
|
||||
'animation',
|
||||
'animation-delay',
|
||||
'animation-direction',
|
||||
'animation-duration',
|
||||
'animation-fill-mode',
|
||||
'animation-iteration-count',
|
||||
'animation-name',
|
||||
'animation-play-state',
|
||||
'animation-timing-function',
|
||||
|
||||
// Appearance.
|
||||
'appearance',
|
||||
|
||||
// Backdrop filter.
|
||||
'backdrop-filter',
|
||||
|
||||
// Background image options.
|
||||
'background-clip',
|
||||
'background-origin',
|
||||
'background-size',
|
||||
|
||||
// Box sizing.
|
||||
'box-sizing',
|
||||
|
||||
// Clip path.
|
||||
'clip-path',
|
||||
|
||||
// Filter effects.
|
||||
'filter',
|
||||
|
||||
// Flexbox.
|
||||
'align-content',
|
||||
'align-items',
|
||||
'align-self',
|
||||
'flex',
|
||||
'flex-basis',
|
||||
'flex-direction',
|
||||
'flex-flow',
|
||||
'flex-grow',
|
||||
'flex-shrink',
|
||||
'flex-wrap',
|
||||
'justify-content',
|
||||
'order',
|
||||
|
||||
// Font feature.
|
||||
'font-feature-settings',
|
||||
'font-language-override',
|
||||
'font-variant-ligatures',
|
||||
|
||||
// Font kerning.
|
||||
'font-kerning',
|
||||
|
||||
// Fragmented borders and backgrounds.
|
||||
'box-decoration-break',
|
||||
|
||||
// Grid layout.
|
||||
'grid-column',
|
||||
'grid-column-align',
|
||||
'grid-column-end',
|
||||
'grid-column-start',
|
||||
'grid-row',
|
||||
'grid-row-align',
|
||||
'grid-row-end',
|
||||
'grid-row-start',
|
||||
'grid-template-columns',
|
||||
'grid-template-rows',
|
||||
|
||||
// Hyphens.
|
||||
'hyphens',
|
||||
'word-break',
|
||||
|
||||
// Masks.
|
||||
'mask',
|
||||
'mask-border',
|
||||
'mask-border-outset',
|
||||
'mask-border-repeat',
|
||||
'mask-border-slice',
|
||||
'mask-border-source',
|
||||
'mask-border-width',
|
||||
'mask-clip',
|
||||
'mask-composite',
|
||||
'mask-image',
|
||||
'mask-origin',
|
||||
'mask-position',
|
||||
'mask-repeat',
|
||||
'mask-size',
|
||||
|
||||
// Multicolumn.
|
||||
'break-after',
|
||||
'break-before',
|
||||
'break-inside',
|
||||
'column-count',
|
||||
'column-fill',
|
||||
'column-gap',
|
||||
'column-rule',
|
||||
'column-rule-color',
|
||||
'column-rule-style',
|
||||
'column-rule-width',
|
||||
'column-span',
|
||||
'column-width',
|
||||
'columns',
|
||||
|
||||
// Object fit.
|
||||
'object-fit',
|
||||
'object-position',
|
||||
|
||||
// Regions.
|
||||
'flow-from',
|
||||
'flow-into',
|
||||
'region-fragment',
|
||||
|
||||
// Scroll snap points.
|
||||
'scroll-snap-coordinate',
|
||||
'scroll-snap-destination',
|
||||
'scroll-snap-points-x',
|
||||
'scroll-snap-points-y',
|
||||
'scroll-snap-type',
|
||||
|
||||
// Shapes.
|
||||
'shape-image-threshold',
|
||||
'shape-margin',
|
||||
'shape-outside',
|
||||
|
||||
// Tab size.
|
||||
'tab-size',
|
||||
|
||||
// Text align last.
|
||||
'text-align-last',
|
||||
|
||||
// Text decoration.
|
||||
'text-decoration-color',
|
||||
'text-decoration-line',
|
||||
'text-decoration-skip',
|
||||
'text-decoration-style',
|
||||
|
||||
// Text emphasis.
|
||||
'text-emphasis',
|
||||
'text-emphasis-color',
|
||||
'text-emphasis-position',
|
||||
'text-emphasis-style',
|
||||
|
||||
// Text size adjust.
|
||||
'text-size-adjust',
|
||||
|
||||
// Text spacing.
|
||||
'text-spacing',
|
||||
|
||||
// Transform.
|
||||
'transform',
|
||||
'transform-origin',
|
||||
|
||||
// Transform 3D.
|
||||
'backface-visibility',
|
||||
'perspective',
|
||||
'perspective-origin',
|
||||
'transform-style',
|
||||
|
||||
// Transition.
|
||||
'transition',
|
||||
'transition-delay',
|
||||
'transition-duration',
|
||||
'transition-property',
|
||||
'transition-timing-function',
|
||||
|
||||
// Unicode bidi.
|
||||
'unicode-bidi',
|
||||
|
||||
// User select.
|
||||
'user-select',
|
||||
|
||||
// Writing mode.
|
||||
'writing-mode',
|
||||
|
||||
);
|
||||
|
||||
/// Values that should be vendorized.
|
||||
/// Data via caniuse.com, github.com/postcss/autoprefixer, and developer.mozilla.org
|
||||
/// @var {list}
|
||||
$vendor-values: (
|
||||
|
||||
// Cross fade.
|
||||
'cross-fade',
|
||||
|
||||
// Element function.
|
||||
'element',
|
||||
|
||||
// Filter function.
|
||||
'filter',
|
||||
|
||||
// Flexbox.
|
||||
'flex',
|
||||
'inline-flex',
|
||||
|
||||
// Grab cursors.
|
||||
'grab',
|
||||
'grabbing',
|
||||
|
||||
// Gradients.
|
||||
'linear-gradient',
|
||||
'repeating-linear-gradient',
|
||||
'radial-gradient',
|
||||
'repeating-radial-gradient',
|
||||
|
||||
// Grid layout.
|
||||
'grid',
|
||||
'inline-grid',
|
||||
|
||||
// Image set.
|
||||
'image-set',
|
||||
|
||||
// Intrinsic width.
|
||||
'max-content',
|
||||
'min-content',
|
||||
'fit-content',
|
||||
'fill',
|
||||
'fill-available',
|
||||
'stretch',
|
||||
|
||||
// Sticky position.
|
||||
'sticky',
|
||||
|
||||
// Transform.
|
||||
'transform',
|
||||
|
||||
// Zoom cursors.
|
||||
'zoom-in',
|
||||
'zoom-out',
|
||||
|
||||
);
|
||||
|
||||
// Functions.
|
||||
|
||||
/// Removes a specific item from a list.
|
||||
/// @author Hugo Giraudel
|
||||
/// @param {list} $list List.
|
||||
/// @param {integer} $index Index.
|
||||
/// @return {list} Updated list.
|
||||
@function remove-nth($list, $index) {
|
||||
|
||||
$result: null;
|
||||
|
||||
@if type-of($index) != number {
|
||||
@warn "$index: #{quote($index)} is not a number for `remove-nth`.";
|
||||
}
|
||||
@else if $index == 0 {
|
||||
@warn "List index 0 must be a non-zero integer for `remove-nth`.";
|
||||
}
|
||||
@else if abs($index) > length($list) {
|
||||
@warn "List index is #{$index} but list is only #{length($list)} item long for `remove-nth`.";
|
||||
}
|
||||
@else {
|
||||
|
||||
$result: ();
|
||||
$index: if($index < 0, length($list) + $index + 1, $index);
|
||||
|
||||
@for $i from 1 through length($list) {
|
||||
|
||||
@if $i != $index {
|
||||
$result: append($result, nth($list, $i));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@return $result;
|
||||
|
||||
}
|
||||
|
||||
/// Replaces a substring within another string.
|
||||
/// @author Hugo Giraudel
|
||||
/// @param {string} $string String.
|
||||
/// @param {string} $search Substring.
|
||||
/// @param {string} $replace Replacement.
|
||||
/// @return {string} Updated string.
|
||||
@function str-replace($string, $search, $replace: '') {
|
||||
|
||||
$index: str-index($string, $search);
|
||||
|
||||
@if $index {
|
||||
@return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
|
||||
}
|
||||
|
||||
@return $string;
|
||||
|
||||
}
|
||||
|
||||
/// Replaces a substring within each string in a list.
|
||||
/// @param {list} $strings List of strings.
|
||||
/// @param {string} $search Substring.
|
||||
/// @param {string} $replace Replacement.
|
||||
/// @return {list} Updated list of strings.
|
||||
@function str-replace-all($strings, $search, $replace: '') {
|
||||
|
||||
@each $string in $strings {
|
||||
$strings: set-nth($strings, index($strings, $string), str-replace($string, $search, $replace));
|
||||
}
|
||||
|
||||
@return $strings;
|
||||
|
||||
}
|
||||
|
||||
// Mixins.
|
||||
|
||||
/// Wraps @content in vendorized keyframe blocks.
|
||||
/// @param {string} $name Name.
|
||||
@mixin keyframes($name) {
|
||||
|
||||
@-moz-keyframes #{$name} { @content; }
|
||||
@-webkit-keyframes #{$name} { @content; }
|
||||
@-ms-keyframes #{$name} { @content; }
|
||||
@keyframes #{$name} { @content; }
|
||||
|
||||
}
|
||||
|
||||
/// Vendorizes a declaration's property and/or value(s).
|
||||
/// @param {string} $property Property.
|
||||
/// @param {mixed} $value String/list of value(s).
|
||||
@mixin vendor($property, $value) {
|
||||
|
||||
// Determine if property should expand.
|
||||
$expandProperty: index($vendor-properties, $property);
|
||||
|
||||
// Determine if value should expand (and if so, add '-prefix-' placeholder).
|
||||
$expandValue: false;
|
||||
|
||||
@each $x in $value {
|
||||
@each $y in $vendor-values {
|
||||
@if $y == str-slice($x, 1, str-length($y)) {
|
||||
|
||||
$value: set-nth($value, index($value, $x), '-prefix-' + $x);
|
||||
$expandValue: true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Expand property?
|
||||
@if $expandProperty {
|
||||
@each $vendor in $vendor-prefixes {
|
||||
#{$vendor}#{$property}: #{str-replace-all($value, '-prefix-', $vendor)};
|
||||
}
|
||||
}
|
||||
|
||||
// Expand just the value?
|
||||
@elseif $expandValue {
|
||||
@each $vendor in $vendor-prefixes {
|
||||
#{$property}: #{str-replace-all($value, '-prefix-', $vendor)};
|
||||
}
|
||||
}
|
||||
|
||||
// Neither? Treat them as a normal declaration.
|
||||
@else {
|
||||
#{$property}: #{$value};
|
||||
}
|
||||
|
||||
}
|
@ -26,8 +26,8 @@
|
||||
<header class="top-header">
|
||||
<div class="container">
|
||||
<nav class="header-nav-links">
|
||||
<a href="https://docs.clan.lol/">Get started</a>
|
||||
<a href="https://docs.clan.lol/blog/">Blog</a>
|
||||
<a href="https://docs.clan.lol/">Getting Started</a>
|
||||
<a href="https://matrix.to/#/#clan:lassul.us">Chat</a>
|
||||
<a href="https://git.clan.lol/clan/clan-core">Code</a>
|
||||
</nav>
|
||||
@ -53,44 +53,52 @@
|
||||
|
||||
<div class="box alt container">
|
||||
<section class="feature left">
|
||||
<a href="https://docs.clan.lol/" class="image"><img src="images/open_source.webp" alt="" /></a>
|
||||
<a href="https://docs.clan.lol/" class="image">
|
||||
<img src="images/fleet_management.webp" alt="" />
|
||||
<p>Your computers, your rules</p>
|
||||
</a>
|
||||
<div class="content">
|
||||
<h3>Community Owned</h3>
|
||||
<h3>Declarative Fleet Management</h3>
|
||||
<!-- customization and control -->
|
||||
<p>
|
||||
Clan is a proudly open-source project, inviting everyone to contribute and collaborate.
|
||||
No fear of lock-in or vendor restrictions. Your data, your rules.
|
||||
Customize and control your entire network from a single Git repository.
|
||||
Recreate any setup with the same configuration and data on a whim.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
<section class="feature right">
|
||||
<a href="https://docs.clan.lol/" class="image"><img src="images/fleet_management.webp" alt="" /></a>
|
||||
<a href="https://docs.clan.lol/" class="image">
|
||||
<img src="images/mesh_vpn.webp" alt="" />
|
||||
<p>Become independent of a centralized internet</p>
|
||||
</a>
|
||||
<div class="content">
|
||||
<h3>Machine Management</h3>
|
||||
<h3>Private Internet</h3>
|
||||
<!-- privacy and independence -->
|
||||
<p>
|
||||
Easily manage fleets of interconnected computers without a central server.
|
||||
Deploy your computers everywhere, with the same configuration and data.
|
||||
Connect all your devices in a peer-to-peer virtual private network.
|
||||
Run self-hosted services and provide access to your family, friends, or coworkers.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
<section class="feature left">
|
||||
<a href="https://docs.clan.lol/" class="image"><img src="images/mesh_vpn.webp" alt="" /></a>
|
||||
<a href="https://docs.clan.lol/" class="image">
|
||||
<img src="images/open_source.webp" alt="" />
|
||||
<p>Own the code you run</p>
|
||||
</a>
|
||||
<div class="content">
|
||||
<h3>Private Internet</h3>
|
||||
<h3>Community Owned</h3>
|
||||
<!-- ownership and sovereignty -->
|
||||
<p>
|
||||
Connect all your devices into a secure, private network with our peer-to-peer Mesh VPN.
|
||||
Share services with your friends & coworkers, without the need to expose them to the public internet.
|
||||
No vendor lock-in or artificial restrictions.
|
||||
Proudly open-source for everyone to learn, contribute, and collaborate.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
|
||||
<footer class="major container medium">
|
||||
<h3>What is Clan?</h3>
|
||||
<p>Discover our features by reading further</p>
|
||||
<ul class="actions special">
|
||||
<li><a href="wclan.html" class="button">Learn More</a></li>
|
||||
</ul>
|
||||
<p class="actions special"><a href="what-is-clan.html" class="button">What is Clan?</a></p>
|
||||
<p>Continue reading to learn more.</p>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
@ -108,7 +116,6 @@
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="assets/js/main.js"></script>
|
||||
</body>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
@ -2,14 +2,15 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>What is Clan? A feature overview</title>
|
||||
<title>What is Clan? Feature overview</title>
|
||||
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
|
||||
<link rel="stylesheet" href="assets/css/main.css" />
|
||||
<link rel="icon" type="image/png" href="static/dark-favicon/128x128.png">
|
||||
|
||||
<meta property="og:title" content="What is Clan?" />
|
||||
<meta property="og:description" content="What is Clan? A guide through its features" />
|
||||
<meta property="og:title" content="Clan - Build your own Darknet" />
|
||||
<meta property="og:description" content="Peer-to-Peer self-hosting made easy for developers. Deploy your computers everywhere, with the same configuration and data." />
|
||||
<meta property="og:image" content="https://clan.lol/static/dark-favicon/128x128.png" />
|
||||
<meta property="og:url" content="https://docs.clan.lol" />
|
||||
<meta property="og:type" content="website" />
|
||||
@ -40,17 +41,10 @@
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
|
||||
#highlight {
|
||||
color: #5b5b5b;
|
||||
padding: 1em;
|
||||
border-radius: 5px;
|
||||
font-size: 1.2em;
|
||||
font-size: 1.05em;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin: 2em 0;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@ -59,8 +53,8 @@
|
||||
<header class="top-header">
|
||||
<div class="container">
|
||||
<nav class="header-nav-links">
|
||||
<a href="https://docs.clan.lol/">Get started</a>
|
||||
<a href="https://docs.clan.lol/blog/">Blog</a>
|
||||
<a href="https://docs.clan.lol/">Getting Started</a>
|
||||
<a href="https://matrix.to/#/#clan:lassul.us">Chat</a>
|
||||
<a href="https://git.clan.lol/clan/clan-core">Code</a>
|
||||
</nav>
|
||||
@ -71,38 +65,48 @@
|
||||
<div id="main">
|
||||
<header class="major container medium">
|
||||
<h2>What is Clan?</h2>
|
||||
<p class="highlight">Clan is a setup tool that centralizes machine configurations for peer-to-peer self-hosted networks.</p>
|
||||
<p id="highlight">
|
||||
Clan is a configuration management, secret provisioning, and backup automation framework.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<div class="box alt container content-section">
|
||||
<details>
|
||||
<summary><b>Unified Git Repository</b>: Centralize secrets & configurations in a single repository</summary>
|
||||
<p>Clan uses a single Git repository to define everything about your machines. This central repository utilizes Nix or JSON files to specify configurations, including disk formatting. This streamlined and unified approach gives you the power to manage your servers from a central point without relying on a centralized provider, scaling your IT infrastructure on your own terms.</p>
|
||||
<summary><b>Uniform interface:</b> Manage your networks from a single source of truth</summary>
|
||||
<p>
|
||||
Clan allows you specify everything about the machines you control, using a single Git repository.
|
||||
Declare disk layout, service configuration, access control, backup strategies, and more in the <a href="https://nix.dev/manual/nix/stable/language/">Nix language</a> or <a href="https://www.json.org">JSON</a>.
|
||||
Scale your IT infrastructure on your own terms.
|
||||
No need to rely on a centralized provider.
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Automated Secret Management</b>: Auto-generate and share secrets with your peers</summary>
|
||||
<p>Passwords and other sensitive information are encrypted within the Git repository and automatically decrypted during deployment. This keeps your secrets safe while also simplifying their management. Clan supports sharing secrets between admins, fostering collaboration and maintaining reproducibility and convenience without sacrificing security.</p>
|
||||
<summary><b>Automated secret management:</b> Automatically generate and provision secrets</summary>
|
||||
<p>
|
||||
Passwords and other sensitive information are encrypted next to your configuration data, and automatically decrypted during deployment of services and their clients.
|
||||
This keeps your secrets safe while also simplifying their management.
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Automated Service Setup</b>: Install services as if they were applications</summary>
|
||||
<summary><b>Automated Service Setup:</b> Install services as if they were applications</summary>
|
||||
<p>Setting up a service can be quite complex: many server adjustments need to be made, from setting up a database to adjusting webserver configurations and generating the correct private keys. Clan aims to make setting up a service as easy as installing an application. Through the <a href="https://docs.clan.lol/reference/clanModules/borgbackup-static/">Modules</a> system, everything down to secrets can be set up through a smooth automated process.</p>
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary><b>Automated Backups</b>: Synchronize state and backup to other peers automatically</summary>
|
||||
<summary><b>Automated Backups:</b> Synchronize state and backup to other peers automatically</summary>
|
||||
<p>Each clan service designates a state directory where all service state data is stored. This setup enables the automatic backup of every service to other peers, including Postgres databases. Using the <a href="https://docs.clan.lol/reference/clanModules/syncthing/">Syncthing</a> clan module, you can create perfect replicas of your laptop.</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Peer-to-peer Mesh VPN</b>: Securely connect machines over a private network.</summary>
|
||||
<summary><b>Peer-to-peer Mesh VPN:</b> Securely connect machines over a private network.</summary>
|
||||
<p>All machines in your Clan are interconnected through a self-configuring peer-to-peer mesh VPN. This additional layer of protection ensures that sensitive services, which might have too much attack surface to be hosted on the public internet, can still be made available on your Clan's network.</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Live Overwrites</b>: Deploy configurations over existing Linux distributions via SSH.</summary>
|
||||
<summary><b>Live Overwrites:</b> Deploy configurations over existing Linux distributions via SSH.</summary>
|
||||
<p>With Clan, you can skip the cumbersome task of bootstrapping specific installation images. Clan allows you to overwrite any existing Linux distribution live over SSH, eliminating time-consuming setup processes. Deploy updates or new configurations swiftly and efficiently, maximizing uptime and minimizing hassle.</p>
|
||||
</details>
|
||||
|
||||
@ -122,6 +126,7 @@
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Footer -->
|
||||
<div id="footer">
|
||||
<div class="container medium">
|