feat(web/website): init
This adds a new Website/Docs for Snix, using Thulite / Doks, which is mostly hugo and a bit of npm. Change-Id: Iea10d4068fa783ec0ddd6bcaba5c8d92b1a1168f
5
web/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
/node_modules
|
||||||
|
/public
|
||||||
|
/hugo_stats.json
|
||||||
|
/resources/_gen
|
||||||
|
/.hugo_build.lock
|
||||||
14
web/README.md
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# snix-website
|
||||||
|
|
||||||
|
This is the Snix website, hosted on https://snix.dev.
|
||||||
|
|
||||||
|
It uses [Doks](https://getdoks.org/), which uses [Thulite](https://thulite.io).
|
||||||
|
|
||||||
|
You can either `mg build :website` to use the Nix build, or get an interactive,
|
||||||
|
live-reloading version.
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ mg shell :shell
|
||||||
|
$ npm i
|
||||||
|
$ npm run dev
|
||||||
|
```
|
||||||
BIN
web/assets/cover.png
Normal file
|
After Width: | Height: | Size: 8 KiB |
2
web/assets/crate-diagram.svg
Normal file
|
After Width: | Height: | Size: 263 KiB |
BIN
web/assets/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
web/assets/favicon.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
1
web/assets/favicon.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#E1E8ED" d="M32.415 9.586l-9-9C23.054.225 22.553 0 22 0c-1.104 0-1.999.896-2 2 0 .552.224 1.053.586 1.415l-3.859 3.859 9 9 3.859-3.859c.362.361.862.585 1.414.585 1.104 0 2.001-.896 2-2 0-.552-.224-1.052-.585-1.414z"/><path fill="#CCD6DD" d="M22 0H7C4.791 0 3 1.791 3 4v28c0 2.209 1.791 4 4 4h22c2.209 0 4-1.791 4-4V11h-9c-1 0-2-1-2-2V0z"/><path fill="#99AAB5" d="M22 0h-2v9c0 2.209 1.791 4 4 4h9v-2h-9c-1 0-2-1-2-2V0zm-5 8c0 .552-.448 1-1 1H8c-.552 0-1-.448-1-1s.448-1 1-1h8c.552 0 1 .448 1 1zm0 4c0 .552-.448 1-1 1H8c-.552 0-1-.448-1-1s.448-1 1-1h8c.552 0 1 .448 1 1zm12 4c0 .552-.447 1-1 1H8c-.552 0-1-.448-1-1s.448-1 1-1h20c.553 0 1 .448 1 1zm0 4c0 .553-.447 1-1 1H8c-.552 0-1-.447-1-1 0-.553.448-1 1-1h20c.553 0 1 .447 1 1zm0 4c0 .553-.447 1-1 1H8c-.552 0-1-.447-1-1 0-.553.448-1 1-1h20c.553 0 1 .447 1 1zm0 4c0 .553-.447 1-1 1H8c-.552 0-1-.447-1-1 0-.553.448-1 1-1h20c.553 0 1 .447 1 1z"/></svg>
|
||||||
|
After Width: | Height: | Size: 972 B |
0
web/assets/images/.gitkeep
Normal file
1
web/assets/js/custom.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
// Put your custom JS code here
|
||||||
8
web/assets/jsconfig.json
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"*": ["*", "..\\node_modules\\@thulite\\doks-core\\assets\\*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
web/assets/mask-icon.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#E1E8ED" d="M32.415 9.586l-9-9C23.054.225 22.553 0 22 0c-1.104 0-1.999.896-2 2 0 .552.224 1.053.586 1.415l-3.859 3.859 9 9 3.859-3.859c.362.361.862.585 1.414.585 1.104 0 2.001-.896 2-2 0-.552-.224-1.052-.585-1.414z"/><path fill="#CCD6DD" d="M22 0H7C4.791 0 3 1.791 3 4v28c0 2.209 1.791 4 4 4h22c2.209 0 4-1.791 4-4V11h-9c-1 0-2-1-2-2V0z"/><path fill="#99AAB5" d="M22 0h-2v9c0 2.209 1.791 4 4 4h9v-2h-9c-1 0-2-1-2-2V0zm-5 8c0 .552-.448 1-1 1H8c-.552 0-1-.448-1-1s.448-1 1-1h8c.552 0 1 .448 1 1zm0 4c0 .552-.448 1-1 1H8c-.552 0-1-.448-1-1s.448-1 1-1h8c.552 0 1 .448 1 1zm12 4c0 .552-.447 1-1 1H8c-.552 0-1-.448-1-1s.448-1 1-1h20c.553 0 1 .448 1 1zm0 4c0 .553-.447 1-1 1H8c-.552 0-1-.447-1-1 0-.553.448-1 1-1h20c.553 0 1 .447 1 1zm0 4c0 .553-.447 1-1 1H8c-.552 0-1-.447-1-1 0-.553.448-1 1-1h20c.553 0 1 .447 1 1zm0 4c0 .553-.447 1-1 1H8c-.552 0-1-.447-1-1 0-.553.448-1 1-1h20c.553 0 1 .447 1 1z"/></svg>
|
||||||
|
After Width: | Height: | Size: 972 B |
1
web/assets/scss/common/_custom.scss
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
// Put your custom SCSS code here
|
||||||
1
web/assets/scss/common/_variables-custom.scss
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
// Put your custom SCSS variables here
|
||||||
43
web/assets/snix-logo.svg
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
width="1200pt"
|
||||||
|
height="1200pt"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 1200 1200"
|
||||||
|
id="svg1"
|
||||||
|
sodipodi:docname="snix-logo.svg"
|
||||||
|
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="pt"
|
||||||
|
inkscape:zoom="0.57290673"
|
||||||
|
inkscape:cx="824.74158"
|
||||||
|
inkscape:cy="780.23171"
|
||||||
|
inkscape:window-width="1320"
|
||||||
|
inkscape:window-height="346"
|
||||||
|
inkscape:window-x="45"
|
||||||
|
inkscape:window-y="29"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg1" />
|
||||||
|
<path
|
||||||
|
d="M 1016.7023,455.30233 H 183.42233 l -90.237995,-15.961 c -3.8398,-0.71875 -7.9219,0.35938 -10.922,2.8789 -3.0001,2.51952 -4.8008,6.3594 -4.8008,10.199 v 295.08 c 0,3.9609 1.8008,7.6797 4.8008,10.199 3,2.5195 7.0781,3.6016 10.922,2.8789 l 90.237995,-15.961 h 833.27997 l 90.238,15.961 c 3.8398,0.71875 7.9219,-0.35938 10.922,-2.8789 3,-2.5195 4.8008,-6.2383 4.8008,-10.199 v -294.96 c 0,-3.9609 -1.8008,-7.6797 -4.8008,-10.199 -3,-2.5195 -7.0781,-3.6016 -10.922,-2.8789 z m -9.9609,262.68 h -31.80097 v -235.92 h 31.80097 z m -813.35997,-235.92 h 31.801 v 235.92 h -31.801 z m 54.121,235.92 v -31.68 h 503.64 c 4.9219,0 8.8789,-3.9609 8.8789,-8.8789 0,-4.9219 -3.9609,-9.0039 -8.8828,-9.0039 h -503.64 v -186.36 h 705.12 l -0.004,235.92 z m -143.28,-31.68 h 32.281 c 4.9219,0 8.8789,-3.9609 8.8789,-8.8789 0,-4.9219 -3.9609,-8.8789 -8.8789,-8.8789 l -32.281,-0.004 v -59.52 h 32.281 c 4.9219,0 8.8789,-3.9609 8.8789,-8.8789 0,-4.9219 -3.9609,-8.8789 -8.8789,-8.8789 l -32.281,-0.004 v -59.52 h 32.281 c 4.9219,0 8.8789,-3.9609 8.8789,-8.8789 0,-4.9219 -3.9609,-8.8789 -8.8789,-8.8789 h -32.281 v -45.238 l 66.84,11.762 v 239.28 l -66.84,11.762 z m 991.67997,-172.56 h -39.48 c -4.9219,0 -8.8789,3.9609 -8.8789,8.8789 0,4.9219 3.9609,8.8789 8.8789,8.8789 h 39.48 v 59.52 h -39.48 c -4.9219,0 -8.8789,3.9609 -8.8789,8.8789 0,4.9219 3.9609,8.8789 8.8789,8.8789 h 39.48 v 59.645 h -39.48 c -4.9219,0 -8.8789,3.9609 -8.8789,8.8789 0,4.9219 3.9609,8.8789 8.8789,8.8789 h 39.48 v 45.238 l -66.84,-11.762 v -239.4 l 66.84,-11.762 z"
|
||||||
|
id="path1" />
|
||||||
|
<path
|
||||||
|
style="font-weight:bold;font-size:174.083px;font-family:'ComicShannsMono Nerd Font Propo';-inkscape-font-specification:'ComicShannsMono Nerd Font Propo Bold';letter-spacing:6.885px;stroke-width:5.93464"
|
||||||
|
d="m 474.40628,538.76714 c 1.39266,0.34817 2.95941,0.52225 4.70024,0.52225 0.52225,0 1.21858,0 1.91491,0 4.178,-0.34816 6.09291,-4.17799 6.09291,-7.48557 0,-3.82982 -2.26308,-8.1819 -6.96332,-9.92273 -5.39657,-1.91491 -19.14913,-2.61124 -23.32712,-2.61124 -30.81269,0 -49.09141,16.88605 -49.09141,36.03518 0,14.10072 13.75256,24.02345 26.46062,25.24203 32.37944,3.1335 34.12027,13.92664 34.12027,21.41221 0,12.88214 -16.53789,21.76037 -28.7237,21.76037 -10.96723,0 -16.18972,-6.0929 -17.93055,-8.87823 -2.08899,-2.95941 -4.35207,-5.57065 -8.1819,-5.57065 -1.74083,0 -3.48166,0.52224 -5.57065,1.39266 -2.089,0.87041 -5.04841,3.48166 -5.04841,8.00782 0,5.91882 4.70024,12.53397 14.44889,17.93055 6.0929,3.48166 13.40439,5.0484 21.76037,5.0484 24.71979,0 49.78774,-14.79705 49.78774,-41.60583 0,-30.29044 -29.94228,-34.46844 -41.43175,-34.99068 -18.10463,-0.87042 -18.97505,-10.96723 -18.97505,-12.88215 0,-9.92273 14.44889,-15.66747 27.15695,-15.66747 8.00782,0 10.61906,0.17409 18.80096,2.26308 z m 50.40562,31.33494 c 0,-3.82982 0,-7.65965 -0.17408,-11.31539 13.40439,29.94227 37.07967,66.67378 41.43175,76.07427 2.08899,4.17799 7.65965,4.52615 9.57456,4.52615 2.26308,0 4.35208,-0.34816 6.44107,-1.04449 5.39658,-1.56675 6.44107,-4.35208 7.13741,-22.45671 0.87041,-18.80096 1.04449,-37.77601 1.04449,-51.1804 0,-8.00782 -0.17408,-13.92664 -0.17408,-16.71197 -0.17408,-13.40439 -0.17408,-18.97504 -1.74083,-22.4567 -1.91491,-3.1335 -6.0929,-3.30758 -8.53007,-3.30758 -4.52615,0 -9.05231,3.13349 -9.05231,7.83373 0,2.26308 1.74083,7.13741 1.74083,49.78774 0,10.2709 -0.17408,19.67138 -0.17408,25.93837 -12.01173,-20.01955 -36.20927,-63.01805 -41.08359,-77.29285 -2.26308,-5.91882 -8.87823,-5.91882 -10.79315,-6.09291 -0.34816,0 -1.04449,0 -1.91491,0 -11.14131,0 -11.83764,7.48557 -11.83764,9.57457 0,0.17408 0.34816,5.74474 0.34816,21.06404 0,29.07186 -1.21858,74.33344 -1.21858,75.02977 0,3.13349 0.34817,5.74474 1.39267,7.83373 1.21858,2.089 4.35207,3.1335 7.1374,3.1335 4.87432,0 9.40048,-3.1335 9.40048,-9.40048 0,-0.17409 0,-0.52225 0,-0.69634 0,-0.69633 1.0445,-45.60974 1.0445,-58.84005 z m 160.94832,68.76278 c 6.61515,0 7.65965,-6.26698 7.65965,-9.40048 v 0 c -0.52225,-7.1374 -5.57066,-8.35598 -8.87823,-8.35598 -0.17409,0 -0.17409,0 -0.17409,0 -17.75646,0 -18.62688,0 -24.02345,0 0.17408,-12.35989 1.0445,-21.41221 1.0445,-35.33885 0,-9.40048 -0.34817,-14.10072 -0.34817,-24.71978 0,-5.39658 0,-11.83765 0.34817,-21.58629 6.44107,0.34816 16.71197,0.87041 21.41221,1.56674 0.52225,0 1.04449,0.17409 1.74083,0.17409 6.0929,0 8.53006,-5.74474 8.53006,-9.74865 0,0 0,0 0,0 v -0.17409 c -0.52225,-6.61515 -6.26698,-8.00781 -9.40048,-8.1819 -10.79314,-1.21858 -23.32712,-1.74083 -39.34275,-1.74083 -7.48557,0 -16.01564,0.17409 -25.41612,0.52225 -9.92273,0.34817 -10.2709,8.00782 -10.2709,8.87824 0,5.39657 3.82983,9.05231 9.92273,9.05231 0.87042,0 3.48166,-0.34816 11.14131,-0.34816 3.48166,0 7.13741,0.17408 10.96723,0.17408 0,0.17408 -0.52225,10.27089 -0.52225,12.53397 0,8.70415 0.34817,31.85719 0.34817,32.72761 0,14.79705 0,15.14522 -1.0445,37.07967 -9.05231,0.34817 -16.01563,0.52225 -21.93446,0.69634 -9.57456,0.34816 -10.09681,6.96332 -10.09681,8.53006 0,0.17409 0,0.34817 0,0.34817 0,6.96332 7.65965,7.65965 10.44498,7.65965 0.69633,0 40.73542,-1.21858 52.74715,-1.21858 11.31539,0 13.2303,0.87041 15.14522,0.87041 z m 111.50874,-4.70024 c 0,-2.95941 -1.21858,-6.26698 -3.82983,-10.27089 -2.95941,-4.178 -8.35598,-12.88214 -14.2748,-22.80488 -4.35208,-6.78923 -8.87824,-14.2748 -13.40439,-20.88995 0.17408,-0.34817 11.66356,-17.93055 14.79705,-22.80488 13.40439,-22.4567 14.97114,-25.06795 14.97114,-28.20144 0,-2.95941 -3.1335,-7.65965 -9.40048,-7.65965 -3.1335,0 -6.44107,1.56674 -8.87824,4.52615 -6.0929,8.35599 -17.58238,28.37553 -22.28262,36.55743 -10.27089,-16.01563 -16.3638,-25.5902 -20.54179,-31.50902 -5.22249,-6.96332 -7.48557,-8.87823 -11.14131,-8.87823 -3.1335,0 -11.48948,0.69633 -11.48948,7.83373 0,3.30758 1.21858,5.22249 8.1819,16.53789 1.91491,2.78533 6.61515,9.74865 22.10854,32.03127 -8.35598,13.23031 -22.10854,33.59802 -24.37162,36.90559 -6.0929,9.74865 -8.35598,13.57848 -8.35598,17.23422 0,2.95941 3.65574,8.1819 9.74865,8.1819 2.78532,0 5.74473,-1.39266 8.00781,-4.00391 1.39267,-1.56675 4.17799,-6.44107 8.00782,-13.05622 5.39657,-8.70415 12.35989,-20.19363 17.93055,-28.37553 1.56675,2.61124 3.30758,5.39657 5.22249,8.35598 14.97114,25.93837 21.06404,36.73151 29.24594,36.73151 3.65574,0 9.74865,-1.91491 9.74865,-6.44107 z"
|
||||||
|
id="text1"
|
||||||
|
aria-label="SNIX" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 7.2 KiB |
0
web/assets/svgs/.gitkeep
Normal file
86
web/config/_default/hugo.toml
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
title = "Snix"
|
||||||
|
baseurl = "http://snix.dev/"
|
||||||
|
canonifyURLs = false
|
||||||
|
disableAliases = true
|
||||||
|
disableHugoGeneratorInject = true
|
||||||
|
# disableKinds = ["taxonomy", "term"]
|
||||||
|
enableEmoji = true
|
||||||
|
enableGitInfo = false
|
||||||
|
enableRobotsTXT = true
|
||||||
|
languageCode = "en-US"
|
||||||
|
pagerSize = 10
|
||||||
|
rssLimit = 10
|
||||||
|
summarylength = 20 # 70 (default)
|
||||||
|
|
||||||
|
# Multilingual
|
||||||
|
defaultContentLanguage = "en"
|
||||||
|
disableLanguages = ["de", "nl"]
|
||||||
|
defaultContentLanguageInSubdir = false
|
||||||
|
|
||||||
|
copyRight = "Copyright (c) 2025 The Snix Project"
|
||||||
|
|
||||||
|
[build.buildStats]
|
||||||
|
enable = true
|
||||||
|
|
||||||
|
[outputs]
|
||||||
|
home = ["HTML", "RSS", "searchIndex"]
|
||||||
|
section = ["HTML", "RSS", "SITEMAP"]
|
||||||
|
|
||||||
|
[outputFormats.searchIndex]
|
||||||
|
mediaType = "application/json"
|
||||||
|
baseName = "search-index"
|
||||||
|
isPlainText = true
|
||||||
|
notAlternative = true
|
||||||
|
|
||||||
|
# Add output format for section sitemap.xml
|
||||||
|
[outputFormats.SITEMAP]
|
||||||
|
mediaType = "application/xml"
|
||||||
|
baseName = "sitemap"
|
||||||
|
isHTML = false
|
||||||
|
isPlainText = true
|
||||||
|
noUgly = true
|
||||||
|
rel = "sitemap"
|
||||||
|
|
||||||
|
[sitemap]
|
||||||
|
changefreq = "monthly"
|
||||||
|
filename = "sitemap.xml"
|
||||||
|
priority = 0.5
|
||||||
|
|
||||||
|
[caches]
|
||||||
|
[caches.getjson]
|
||||||
|
dir = ":cacheDir/:project"
|
||||||
|
maxAge = -1 # "30m"
|
||||||
|
|
||||||
|
[taxonomies]
|
||||||
|
contributor = "contributors"
|
||||||
|
category = "categories"
|
||||||
|
tag = "tags"
|
||||||
|
|
||||||
|
[permalinks]
|
||||||
|
blog = "/blog/:slug/"
|
||||||
|
docs = "/docs/:sections[1:]/:slug/"
|
||||||
|
# docs = "/docs/1.0/:sections[1:]/:slug/"
|
||||||
|
|
||||||
|
[minify.tdewolff.html]
|
||||||
|
keepWhitespace = false
|
||||||
|
|
||||||
|
[related]
|
||||||
|
threshold = 80
|
||||||
|
includeNewer = true
|
||||||
|
toLower = false
|
||||||
|
[[related.indices]]
|
||||||
|
name = "categories"
|
||||||
|
weight = 100
|
||||||
|
[[related.indices]]
|
||||||
|
name = "tags"
|
||||||
|
weight = 80
|
||||||
|
[[related.indices]]
|
||||||
|
name = "date"
|
||||||
|
weight = 10
|
||||||
|
|
||||||
|
[imaging]
|
||||||
|
anchor = "Center"
|
||||||
|
bgColor = "#ffffff"
|
||||||
|
hint = "photo"
|
||||||
|
quality = 85
|
||||||
|
resampleFilter = "Lanczos"
|
||||||
9
web/config/_default/languages.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[en]
|
||||||
|
languageName = "English"
|
||||||
|
contentDir = "content/en"
|
||||||
|
weight = 10
|
||||||
|
[en.params]
|
||||||
|
languageISO = "EN"
|
||||||
|
languageTag = "en-US"
|
||||||
|
footer = ''
|
||||||
|
# alertText = '<a class="alert-link stretched-link fw-normal" href="/blog/example-post/">Doks version 1.0 just shipped!</a>'
|
||||||
33
web/config/_default/markup.toml
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
defaultMarkdownHandler = "goldmark"
|
||||||
|
|
||||||
|
[goldmark]
|
||||||
|
[goldmark.extensions]
|
||||||
|
linkify = false
|
||||||
|
[goldmark.parser]
|
||||||
|
autoHeadingID = true
|
||||||
|
autoHeadingIDType = "github"
|
||||||
|
[goldmark.parser.attribute]
|
||||||
|
block = true
|
||||||
|
title = true
|
||||||
|
[goldmark.renderer]
|
||||||
|
unsafe = true
|
||||||
|
|
||||||
|
[highlight]
|
||||||
|
anchorLineNos = false
|
||||||
|
codeFences = true
|
||||||
|
guessSyntax = false
|
||||||
|
hl_Lines = ''
|
||||||
|
hl_inline = false
|
||||||
|
lineAnchors = ''
|
||||||
|
lineNoStart = 1
|
||||||
|
lineNos = false
|
||||||
|
lineNumbersInTable = false
|
||||||
|
noClasses = false
|
||||||
|
noHl = false
|
||||||
|
style = 'monokai'
|
||||||
|
tabWidth = 2
|
||||||
|
|
||||||
|
[tableOfContents]
|
||||||
|
endLevel = 3
|
||||||
|
ordered = false
|
||||||
|
startLevel = 2
|
||||||
105
web/config/_default/menus/menus.en.toml
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
# [[docs]]
|
||||||
|
# name = "Prologue"
|
||||||
|
# weight = 10
|
||||||
|
# identifier = "prologue"
|
||||||
|
# url = "/docs/prologue/"
|
||||||
|
|
||||||
|
# [[docs]]
|
||||||
|
# name = "Help"
|
||||||
|
# weight = 60
|
||||||
|
# identifier = "help"
|
||||||
|
# url = "/docs/help/"
|
||||||
|
|
||||||
|
# [[docs]]
|
||||||
|
# name = "Lorem"
|
||||||
|
# weight = 70
|
||||||
|
# identifier = "lorem"
|
||||||
|
# url = "/docs/lorem/"
|
||||||
|
|
||||||
|
[[guide]]
|
||||||
|
name = "Lorem"
|
||||||
|
weight = 10
|
||||||
|
identifier = "lorem"
|
||||||
|
url = "/guide/lorem/"
|
||||||
|
|
||||||
|
[[tutorial]]
|
||||||
|
name = "Lorem"
|
||||||
|
weight = 10
|
||||||
|
identifier = "lorem"
|
||||||
|
url = "/tutorial/lorem/"
|
||||||
|
|
||||||
|
[[main]]
|
||||||
|
name = "About"
|
||||||
|
url = "/about/"
|
||||||
|
weight = 10
|
||||||
|
|
||||||
|
[[main]]
|
||||||
|
name = "Docs"
|
||||||
|
url = "/docs/components/architecture/"
|
||||||
|
# url = "/docs/1.0/prologue/introduction/"
|
||||||
|
weight = 20
|
||||||
|
|
||||||
|
# [[main]]
|
||||||
|
# name = "Blog"
|
||||||
|
# url = "/blog/"
|
||||||
|
# weight = 30
|
||||||
|
|
||||||
|
[[main]]
|
||||||
|
name = "Contact"
|
||||||
|
url = "/contact/"
|
||||||
|
weight = 31
|
||||||
|
|
||||||
|
# [[social]]
|
||||||
|
# name = "X"
|
||||||
|
# pre = '<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-brand-x" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M4 4l11.733 16h4.267l-11.733 -16z"></path><path d="M4 20l6.768 -6.768m2.46 -2.46l6.772 -6.772"></path></svg>'
|
||||||
|
# url = "https://twitter.com/getdoks"
|
||||||
|
# weight = 10
|
||||||
|
#
|
||||||
|
# [[social]]
|
||||||
|
# name = "Discord"
|
||||||
|
# pre = '<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-brand-discord" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 12a1 1 0 1 0 2 0a1 1 0 0 0 -2 0"></path><path d="M14 12a1 1 0 1 0 2 0a1 1 0 0 0 -2 0"></path><path d="M8.5 17c0 1 -1.356 3 -1.832 3c-1.429 0 -2.698 -1.667 -3.333 -3c-.635 -1.667 -.476 -5.833 1.428 -11.5c1.388 -1.015 2.782 -1.34 4.237 -1.5l.975 1.923a11.913 11.913 0 0 1 4.053 0l.972 -1.923c1.5 .16 3.043 .485 4.5 1.5c2 5.667 2.167 9.833 1.5 11.5c-.667 1.333 -2 3 -3.5 3c-.5 0 -2 -2 -2 -3"></path><path d="M7 16.5c3.5 1 6.5 1 10 0"></path></svg>'
|
||||||
|
# url = "https://getdoks.org/chat"
|
||||||
|
# weight = 20
|
||||||
|
|
||||||
|
[[social]]
|
||||||
|
name = "Gerrit"
|
||||||
|
pre = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-brand-git"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M16 12m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" /><path d="M12 8m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" /><path d="M12 16m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" /><path d="M12 15v-6" /><path d="M15 11l-2 -2" /><path d="M11 7l-1.9 -1.9" /><path d="M13.446 2.6l7.955 7.954a2.045 2.045 0 0 1 0 2.892l-7.955 7.955a2.045 2.045 0 0 1 -2.892 0l-7.955 -7.955a2.045 2.045 0 0 1 0 -2.892l7.955 -7.955a2.045 2.045 0 0 1 2.892 0z" /></svg>'
|
||||||
|
url = "https://cl.snix.dev"
|
||||||
|
weight = 30
|
||||||
|
|
||||||
|
[[social]]
|
||||||
|
name = "Code"
|
||||||
|
pre = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-code"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M7 8l-4 4l4 4" /><path d="M17 8l4 4l-4 4" /><path d="M14 4l-4 16" /></svg>'
|
||||||
|
url = "https://git.snix.dev/snix/snix"
|
||||||
|
weight = 31
|
||||||
|
|
||||||
|
[[social]]
|
||||||
|
name = "Rustdoc"
|
||||||
|
pre = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" id="Cubes--Streamline-Font-Awesome" height="16" width="16"><desc>Cubes Streamline Icon: https://streamlinehq.com</desc><!--! Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc.--><path d="m8.074847222222221 2.352027777777778 2.133852777777778 0.8083611111111111 -2.210061111111111 0.849186111111111 -2.210061111111111 -0.849186111111111 2.133852777777778 -0.8083611111111111c0.04899166666666666 -0.019049999999999997 0.10342499999999999 -0.019049999999999997 0.15513888888888888 0Zm-4.213266666666667 1.19485v3.0538027777777774c-0.03538333333333333 0.010886111111111112 -0.07076666666666666 0.021772222222222224 -0.10615 0.03538333333333333l-2.6128777777777774 0.9907166666666666C0.5519333333333333 7.8499638888888885 0.15999999999999998 8.418808333333333 0.15999999999999998 9.050255555555553v3.244325c0 0.6042277777777777 0.35655 1.1513 0.9117861111111111 1.3962583333333334l2.6128805555555554 1.1485777777777777c0.39193055555555556 0.17146944444444445 0.8355777777777778 0.17146944444444445 1.2275083333333332 0l3.086463888888889 -1.3581527777777778 3.089186111111111 1.3581527777777778c0.3919333333333333 0.17146944444444445 0.8355777777777778 0.17146944444444445 1.2275083333333332 0l2.6128805555555554 -1.1485777777777777c0.5525166666666667 -0.2422361111111111 0.9117861111111111 -0.7920305555555556 0.9117861111111111 -1.3962583333333334V9.050255555555553c0 -0.6341694444444445 -0.39193055555555556 -1.2002916666666668 -0.9825527777777776 -1.4261972222222221l-2.6128777777777774 -0.9907166666666666c-0.03538333333333333 -0.013608333333333333 -0.07076666666666666 -0.024497222222222222 -0.10615 -0.03538333333333333V3.5468777777777776c0 -0.6341694444444445 -0.39193055555555556 -1.2002916666666668 -0.9825499999999999 -1.4261972222222221l-2.6128805555555554 -0.9907166666666666c-0.3483833333333333 -0.13064444444444442 -0.73215 -0.13064444444444442 -1.0805333333333333 0l-2.6128805555555554 0.9907166666666666c-0.5960638888888888 0.22590555555555555 -0.9879944444444444 0.79475 -0.9879944444444444 1.4261972222222221Zm6.967677777777777 3.2143861111111107 -2.242722222222222 0.849186111111111v-2.4278027777777775l2.242722222222222 -0.8600722222222221v2.4386888888888887Zm-6.455988888888889 1.0968638888888889 2.13385 0.8083611111111111 -2.210061111111111 0.8464638888888888 -2.2100583333333335 -0.8464638888888888 2.13385 -0.8083611111111111c0.04899166666666666 -0.019052777777777776 0.10342777777777777 -0.019052777777777776 0.15513888888888888 0Zm0.5116888888888889 5.563258333333333V10.686027777777777l2.242722222222222 -0.860075V12.43611111111111l-2.242722222222222 0.985275Zm6.739052777777777 -5.563258333333333c0.04898888888888889 -0.019052777777777776 0.10342499999999999 -0.019052777777777776 0.15513888888888888 0l2.13385 0.8083611111111111 -2.2127805555555553 0.8464638888888888 -2.210061111111111 -0.8464638888888888 2.13385 -0.8083611111111111Zm2.776183333333333 4.635141666666667 -2.112077777777778 0.9281166666666666V10.686027777777777l2.242722222222222 -0.860075v2.4686277777777774c0 0.08709722222222221 -0.051713888888888886 0.16330555555555554 -0.13064444444444442 0.1986888888888889Z" fill="currentColor" stroke-width="0.0278"></path></svg>'
|
||||||
|
url = "https://snix.dev/rustdoc"
|
||||||
|
weight = 32
|
||||||
|
|
||||||
|
# [[sidebar_docs]]
|
||||||
|
# name = "Guides"
|
||||||
|
# pageRef = "/docs/guides"
|
||||||
|
# weight = 10
|
||||||
|
#
|
||||||
|
# [[sidebar_docs]]
|
||||||
|
# name = "Reference"
|
||||||
|
# pageRef = "/docs/reference"
|
||||||
|
# weight = 20
|
||||||
|
#
|
||||||
|
# [[sidebar_docs]]
|
||||||
|
# name = "Resources"
|
||||||
|
# pageRef = "/docs/resources"
|
||||||
|
# weight = 30
|
||||||
|
|
||||||
|
# [[footer]]
|
||||||
|
# name = "Privacy Policy"
|
||||||
|
# url = "/privacy/"
|
||||||
|
# weight = 10
|
||||||
|
|
||||||
|
# [[footer]]
|
||||||
|
# name = "Terms of Service"
|
||||||
|
# url = "/terms/"
|
||||||
|
# weight = 20
|
||||||
87
web/config/_default/module.toml
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
# mounts
|
||||||
|
## archetypes
|
||||||
|
[[mounts]]
|
||||||
|
source = "node_modules/@thulite/doks-core/archetypes"
|
||||||
|
target = "archetypes"
|
||||||
|
|
||||||
|
[[mounts]]
|
||||||
|
source = "archetypes"
|
||||||
|
target = "archetypes"
|
||||||
|
|
||||||
|
## assets
|
||||||
|
[[mounts]]
|
||||||
|
source = "node_modules/@thulite/core/assets"
|
||||||
|
target = "assets"
|
||||||
|
|
||||||
|
[[mounts]]
|
||||||
|
source = "node_modules/@thulite/images/assets"
|
||||||
|
target = "assets"
|
||||||
|
|
||||||
|
[[mounts]]
|
||||||
|
source = "node_modules/@thulite/doks-core/assets"
|
||||||
|
target = "assets"
|
||||||
|
|
||||||
|
[[mounts]]
|
||||||
|
source = "node_modules/@tabler/icons/icons"
|
||||||
|
target = "assets/svgs/tabler-icons"
|
||||||
|
|
||||||
|
[[mounts]]
|
||||||
|
source = "assets"
|
||||||
|
target = "assets"
|
||||||
|
|
||||||
|
## content
|
||||||
|
[[mounts]]
|
||||||
|
source = "content"
|
||||||
|
target = "content"
|
||||||
|
|
||||||
|
## data
|
||||||
|
[[mounts]]
|
||||||
|
source = "node_modules/@thulite/doks-core/data"
|
||||||
|
target = "data"
|
||||||
|
|
||||||
|
[[mounts]]
|
||||||
|
source = "data"
|
||||||
|
target = "data"
|
||||||
|
|
||||||
|
## i18n
|
||||||
|
[[mounts]]
|
||||||
|
source = "node_modules/@thulite/doks-core/i18n"
|
||||||
|
target = "i18n"
|
||||||
|
|
||||||
|
[[mounts]]
|
||||||
|
source = "i18n"
|
||||||
|
target = "i18n"
|
||||||
|
|
||||||
|
## layouts
|
||||||
|
[[mounts]]
|
||||||
|
source = "node_modules/@thulite/core/layouts"
|
||||||
|
target = "layouts"
|
||||||
|
|
||||||
|
[[mounts]]
|
||||||
|
source = "node_modules/@thulite/seo/layouts"
|
||||||
|
target = "layouts"
|
||||||
|
|
||||||
|
[[mounts]]
|
||||||
|
source = "node_modules/@thulite/images/layouts"
|
||||||
|
target = "layouts"
|
||||||
|
|
||||||
|
[[mounts]]
|
||||||
|
source = "node_modules/@thulite/doks-core/layouts"
|
||||||
|
target = "layouts"
|
||||||
|
|
||||||
|
[[mounts]]
|
||||||
|
source = "node_modules/@thulite/inline-svg/layouts"
|
||||||
|
target = "layouts"
|
||||||
|
|
||||||
|
[[mounts]]
|
||||||
|
source = "layouts"
|
||||||
|
target = "layouts"
|
||||||
|
|
||||||
|
## static
|
||||||
|
[[mounts]]
|
||||||
|
source = "node_modules/@thulite/doks-core/static"
|
||||||
|
target = "static"
|
||||||
|
|
||||||
|
[[mounts]]
|
||||||
|
source = "static"
|
||||||
|
target = "static"
|
||||||
138
web/config/_default/params.toml
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
# Hugo
|
||||||
|
title = "My Docs"
|
||||||
|
description = "Congrats on setting up a new Doks project!"
|
||||||
|
images = ["cover.png"]
|
||||||
|
|
||||||
|
# mainSections
|
||||||
|
mainSections = ["docs"]
|
||||||
|
|
||||||
|
[social]
|
||||||
|
twitter = "getdoks"
|
||||||
|
|
||||||
|
# Doks (@thulite/doks-core)
|
||||||
|
[doks]
|
||||||
|
# Color mode
|
||||||
|
colorMode = "auto" # auto (default), light or dark
|
||||||
|
colorModeToggler = true # true (default) or false (this setting is only relevant when colorMode = auto)
|
||||||
|
|
||||||
|
# Navbar
|
||||||
|
navbarSticky = true # true (default) or false
|
||||||
|
containerBreakpoint = "lg" # "", "sm", "md", "lg" (default), "xl", "xxl", or "fluid"
|
||||||
|
|
||||||
|
## Button
|
||||||
|
navBarButton = false # false (default) or true
|
||||||
|
navBarButtonUrl = "/docs/prologue/introduction/"
|
||||||
|
navBarButtonText = "Get started"
|
||||||
|
|
||||||
|
# FlexSearch
|
||||||
|
flexSearch = true # true (default) or false
|
||||||
|
searchExclKinds = [] # list of page kinds to exclude from search indexing (e.g. ["home", "taxonomy", "term"] )
|
||||||
|
searchExclTypes = [] # list of content types to exclude from search indexing (e.g. ["blog", "docs", "legal", "contributors", "categories"])
|
||||||
|
showSearch = [] # [] (all pages, default) or homepage (optionally) and list of sections (e.g. ["homepage", "blog", "guides"])
|
||||||
|
indexSummary = false # true or false (default); whether to index only the `.Summary` instead of the full `.Content`; limits the respective JSON field size and thus increases loading time
|
||||||
|
|
||||||
|
## Search results
|
||||||
|
showDate = false # false (default) or true
|
||||||
|
showSummary = true # true (default) or false
|
||||||
|
searchLimit = 99 # 0 (no limit, default) or natural number
|
||||||
|
|
||||||
|
# Global alert
|
||||||
|
alert = false # false (default) or true
|
||||||
|
alertDismissable = true # true (default) or false
|
||||||
|
|
||||||
|
# Bootstrap
|
||||||
|
bootstrapJavascript = false # false (default) or true
|
||||||
|
|
||||||
|
# Nav
|
||||||
|
sectionNav = ["docs"] # ["docs"] (default) or list of sections (e.g. ["docs", "guides"])
|
||||||
|
toTopButton = false # false (default) or true
|
||||||
|
breadcrumbTrail = false # false (default) or true
|
||||||
|
headlineHash = true # true (default) or false
|
||||||
|
scrollSpy = true # true (default) or false
|
||||||
|
|
||||||
|
# Multilingual
|
||||||
|
multilingualMode = false # false (default) or true
|
||||||
|
showMissingLanguages = true # whether or not to show untranslated languages in the language menu; true (default) or false
|
||||||
|
|
||||||
|
# Versioning
|
||||||
|
docsVersioning = false # false (default) or true
|
||||||
|
docsVersion = "1.0"
|
||||||
|
|
||||||
|
# UX
|
||||||
|
headerBar = false # true (default) or false
|
||||||
|
backgroundDots = true # true (default) or false
|
||||||
|
|
||||||
|
# Homepage
|
||||||
|
sectionFooter = false # false (default) or true
|
||||||
|
|
||||||
|
# Blog
|
||||||
|
relatedPosts = false # false (default) or true
|
||||||
|
imageList = true # true (default) or false
|
||||||
|
imageSingle = true # true (default) or false
|
||||||
|
|
||||||
|
# Repository
|
||||||
|
editPage = false # false (default) or true
|
||||||
|
lastMod = false # false (default) or true
|
||||||
|
repoHost = "GitHub" # GitHub (default), Gitea, GitLab, Bitbucket, or BitbucketServer
|
||||||
|
docsRepo = "https://github.com/h-enk/doks"
|
||||||
|
docsRepoBranch = "main" # main (default), master, or <branch name>
|
||||||
|
docsRepoSubPath = "" # "" (none, default) or <sub path>
|
||||||
|
|
||||||
|
# SCSS colors
|
||||||
|
# backGround = "yellowgreen"
|
||||||
|
## Dark theme
|
||||||
|
# textDark = "#dee2e6" # "#dee2e6" (default), "#dee2e6" (orignal), or custom color
|
||||||
|
# accentDark = "#5d2f86" # "#5d2f86" (default), "#5d2f86" (original), or custom color
|
||||||
|
## Light theme
|
||||||
|
# textLight = "#1d2d35" # "#1d2d35" (default), "#1d2d35" (orignal), or custom color
|
||||||
|
# accentLight = "#8ed6fb" # "#8ed6fb" (default), "#8ed6fb" (orignal), or custom color
|
||||||
|
|
||||||
|
# [doks.menu]
|
||||||
|
# [doks.menu.section]
|
||||||
|
# auto = true # true (default) or false
|
||||||
|
# collapsibleSidebar = true # true (default) or false
|
||||||
|
|
||||||
|
# Debug
|
||||||
|
[render_hooks.image]
|
||||||
|
errorLevel = 'ignore' # ignore (default), warning, or error (fails the build)
|
||||||
|
|
||||||
|
[render_hooks.link]
|
||||||
|
errorLevel = 'ignore' # ignore (default), warning, or error (fails the build)
|
||||||
|
highlightBroken = false # true or false (default)
|
||||||
|
|
||||||
|
# Images (@thulite/images)
|
||||||
|
[thulite_images]
|
||||||
|
[thulite_images.defaults]
|
||||||
|
decoding = "async" # sync, async, or auto (default)
|
||||||
|
fetchpriority = "auto" # high, low, or auto (default)
|
||||||
|
loading = "lazy" # eager or lazy (default)
|
||||||
|
widths = [480, 576, 768, 1025, 1200, 1440] # [640, 768, 1024, 1366, 1600, 1920] for example
|
||||||
|
sizes = "auto" # 100vw (default), 75vw, or auto for example
|
||||||
|
process = "" # "fill 1600x900" or "fill 2100x900" for example
|
||||||
|
lqip = "16x webp q20" # "16x webp q20" or "21x webp q20" for example
|
||||||
|
|
||||||
|
# Inline SVG (@thulite/inline-svg)
|
||||||
|
[inline_svg]
|
||||||
|
iconSetDir = "tabler-icons" # "tabler-icons" (default)
|
||||||
|
|
||||||
|
# SEO (@thulite/seo)
|
||||||
|
[seo]
|
||||||
|
[seo.title]
|
||||||
|
separator = " | "
|
||||||
|
suffix = ""
|
||||||
|
[seo.favicons]
|
||||||
|
sizes = []
|
||||||
|
icon = "favicon.png" # favicon.png (default)
|
||||||
|
svgIcon = "favicon.svg" # favicon.svg (default)
|
||||||
|
maskIcon = "mask-icon.svg" # mask-icon.svg (default)
|
||||||
|
maskIconColor = "white" # white (default)
|
||||||
|
[seo.schemas]
|
||||||
|
type = "Organization" # Organization (default) or Person
|
||||||
|
logo = "favicon-512x512.png" # Logo of Organization — favicon-512x512.png (default)
|
||||||
|
name = "Thulite" # Name of Organization or Person
|
||||||
|
sameAs = [] # E.g. ["https://github.com/thuliteio/thulite", "https://fosstodon.org/@thulite"]
|
||||||
|
images = ["cover.png"] # ["cover.png"] (default)
|
||||||
|
article = [] # Article sections
|
||||||
|
newsArticle = [] # NewsArticle sections
|
||||||
|
blogPosting = ["blog"] # BlogPosting sections
|
||||||
|
product = [] # Product sections
|
||||||
17
web/config/babel.config.js
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
[
|
||||||
|
'@babel/preset-env',
|
||||||
|
{
|
||||||
|
targets: {
|
||||||
|
browsers: [
|
||||||
|
// Best practice: https://github.com/babel/babel/issues/7789
|
||||||
|
'>=1%',
|
||||||
|
'not ie 11',
|
||||||
|
'not op_mini all'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
};
|
||||||
2
web/config/next/hugo.toml
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
# Overrides for next environment
|
||||||
|
baseurl = "/"
|
||||||
64
web/config/postcss.config.js
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
const autoprefixer = require('autoprefixer');
|
||||||
|
const purgecss = require('@fullhuman/postcss-purgecss');
|
||||||
|
const whitelister = require('purgecss-whitelister');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
plugins: [
|
||||||
|
autoprefixer(),
|
||||||
|
purgecss({
|
||||||
|
content: ['./hugo_stats.json'],
|
||||||
|
extractors: [
|
||||||
|
{
|
||||||
|
extractor: (content) => {
|
||||||
|
const els = JSON.parse(content).htmlElements;
|
||||||
|
return els.tags.concat(els.classes, els.ids);
|
||||||
|
},
|
||||||
|
extensions: ['json']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
dynamicAttributes: [
|
||||||
|
'aria-expanded',
|
||||||
|
'data-bs-popper',
|
||||||
|
'data-bs-target',
|
||||||
|
'data-bs-theme',
|
||||||
|
'data-dark-mode',
|
||||||
|
'data-global-alert',
|
||||||
|
'data-pane', // tabs.js
|
||||||
|
'data-popper-placement',
|
||||||
|
'data-sizes',
|
||||||
|
'data-toggle-tab', // tabs.js
|
||||||
|
'id',
|
||||||
|
'size',
|
||||||
|
'type'
|
||||||
|
],
|
||||||
|
safelist: [
|
||||||
|
'active',
|
||||||
|
'btn-clipboard', // clipboards.js
|
||||||
|
'clipboard', // clipboards.js
|
||||||
|
'disabled',
|
||||||
|
'hidden',
|
||||||
|
'modal-backdrop', // search-modal.js
|
||||||
|
'selected', // search-modal.js
|
||||||
|
'show',
|
||||||
|
'img-fluid',
|
||||||
|
'blur-up',
|
||||||
|
'lazyload',
|
||||||
|
'lazyloaded',
|
||||||
|
'alert-link',
|
||||||
|
'container-fw ',
|
||||||
|
'container-lg',
|
||||||
|
'container-fluid',
|
||||||
|
'offcanvas-backdrop',
|
||||||
|
'figcaption',
|
||||||
|
'dt',
|
||||||
|
'dd',
|
||||||
|
'showing',
|
||||||
|
'hiding',
|
||||||
|
'page-item',
|
||||||
|
'page-link',
|
||||||
|
'not-content',
|
||||||
|
...whitelister(['./assets/scss/**/*.scss', './node_modules/@thulite/doks-core/assets/scss/components/_code.scss', './node_modules/@thulite/doks-core/assets/scss/components/_expressive-code.scss', './node_modules/@thulite/doks-core/assets/scss/common/_syntax.scss'])
|
||||||
|
]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
};
|
||||||
2
web/config/production/hugo.toml
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
# Overrides for production environment
|
||||||
|
baseurl = "/"
|
||||||
13
web/content/_index.md
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
title: "Snix"
|
||||||
|
description: "A modern Rust re-implementation of the components of the Nix package manager."
|
||||||
|
lead: "A modern Rust re-implementation of the components of the Nix package manager."
|
||||||
|
date: 2023-09-07T16:33:54+02:00
|
||||||
|
lastmod: 2023-09-07T16:33:54+02:00
|
||||||
|
draft: false
|
||||||
|
seo:
|
||||||
|
title: "" # custom title (optional)
|
||||||
|
description: "" # custom description (recommended)
|
||||||
|
canonical: "" # custom canonical URL (optional)
|
||||||
|
robots: "" # custom robot tags (optional)
|
||||||
|
---
|
||||||
57
web/content/about.md
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
---
|
||||||
|
title: "About Snix"
|
||||||
|
slug: about
|
||||||
|
description: ""
|
||||||
|
summary: ""
|
||||||
|
date: 2025-03-14T14:14:35+01:00
|
||||||
|
lastmod: 2025-03-14T14:14:35+01:00
|
||||||
|
draft: false
|
||||||
|
weight: 999
|
||||||
|
toc: false
|
||||||
|
---
|
||||||
|
|
||||||
|
<center>
|
||||||
|
{{< inline-svg src="snix-logo.svg" width="200px" height="200px" class="svg-inline-custom svg-monochrome" >}}
|
||||||
|
</center>
|
||||||
|
|
||||||
|
Snix is a modern Rust re-implementation of the components of the Nix package
|
||||||
|
manager.
|
||||||
|
|
||||||
|
Snix modularity & composability allows recombining its parts in novel ways. It
|
||||||
|
also provides library access to Nix data formats and concepts. In the long-run,
|
||||||
|
Snix aims to produce a Nixpkgs-compatible alternative to [NixOS/nix][] with
|
||||||
|
respects to evaluation and building Nix expressions & systems.
|
||||||
|
|
||||||
|
{{< callout >}}
|
||||||
|
Snix still is in its early stages of development. None of our current APIs
|
||||||
|
should be considered stable in any way.
|
||||||
|
|
||||||
|
There is no full-featured drop-in replacement for Nix on your machine yet.
|
||||||
|
{{</callout>}}
|
||||||
|
|
||||||
|
Snix already provides a few binaries / tools exposing some usecases, such as:
|
||||||
|
|
||||||
|
* A `snix-store` binary, providing access to `snix-[ca]store`
|
||||||
|
* run a gRPC daemon exposing contents to other parties
|
||||||
|
* import local files or copy store paths into `snix-store`
|
||||||
|
* provide FUSE or virtiofs views into `snix-store`.
|
||||||
|
* `nar-bridge`, a Nix HTTP Binary Cache frontend for `snix-store`.
|
||||||
|
It allows Nix to interact with `snix-store`, both to substitute from as well
|
||||||
|
as copy into.
|
||||||
|
* `snix-boot`, tooling to boot microVMs off of `snix-store` (using virtiofs)
|
||||||
|
* `snix-cli`, combining various components together to provide a Nix evaluator
|
||||||
|
CLI and REPL.
|
||||||
|
* `snixbolt`, a version of the Snix evaluator running in your browser (using
|
||||||
|
WASM)
|
||||||
|
|
||||||
|
{{<callout>}}
|
||||||
|
Early adopters are encouraged to use (and extend) Snix to solve their
|
||||||
|
own usecases.
|
||||||
|
If you're missing certain functionality, or run into bugs, [reach out](),
|
||||||
|
so we can coordinate how to add/fix it.
|
||||||
|
{{</callout>}}
|
||||||
|
|
||||||
|
Snix is developed as a GPLv3-licensed free software project with source code
|
||||||
|
available on [our own Forgejo](https://git.snix.dev/) instance.
|
||||||
|
|
||||||
|
[NixOS/nix]: https://github.com/NixOS/nix
|
||||||
14
web/content/blog/_index.md
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
---
|
||||||
|
title: "Blog"
|
||||||
|
description: ""
|
||||||
|
summary: ""
|
||||||
|
date: 2023-09-07T16:21:44+02:00
|
||||||
|
lastmod: 2023-09-07T16:21:44+02:00
|
||||||
|
draft: false
|
||||||
|
weight: 50
|
||||||
|
categories: []
|
||||||
|
tags: []
|
||||||
|
contributors: []
|
||||||
|
pinned: false
|
||||||
|
homepage: false
|
||||||
|
---
|
||||||
44
web/content/contact.md
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
---
|
||||||
|
title: "Contact"
|
||||||
|
slug: contact
|
||||||
|
description: ""
|
||||||
|
summary: ""
|
||||||
|
date: 2025-03-14T14:14:35+01:00
|
||||||
|
lastmod: 2025-03-14T14:14:35+01:00
|
||||||
|
draft: false
|
||||||
|
weight: 1000
|
||||||
|
toc: false
|
||||||
|
---
|
||||||
|
|
||||||
|
## IRC
|
||||||
|
Discussion on Snix primarily happens on IRC. We're on the [Hackint][hackint] network.
|
||||||
|
Feel free to join the `#snix` channel, best through your IRC client or via the
|
||||||
|
[Webchat][snix-webchat] [^1].
|
||||||
|
|
||||||
|
### Bridges to Matrix and XMPP
|
||||||
|
Hackint also bridges to [XMPP][hackint-xmpp] ([link][snix-xmpp]) and
|
||||||
|
[Matrix][hackint-matrix] ([link][snix-matrix]), though the bridges sometimes
|
||||||
|
don't work reliably, which is outside our control.
|
||||||
|
|
||||||
|
## Issue tracking
|
||||||
|
We use the [Issue Tracker][issues] on our [Forgejo Instance][code] to track
|
||||||
|
issues.
|
||||||
|
If you want to work on some of these issues, it's best to reach out first, to
|
||||||
|
make sure noone is already working on this and to exchange ideas on how to solve
|
||||||
|
it.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
Please also check out our [Contribution Guide]({{< ref "/docs/guides/contributing" >}}),
|
||||||
|
which describes how to send changes.
|
||||||
|
|
||||||
|
|
||||||
|
[^1]: please be patient, it might take a while to get a response.
|
||||||
|
|
||||||
|
[hackint]: https://hackint.org/
|
||||||
|
[hackint-matrix]: https://hackint.org/transport/matrix
|
||||||
|
[hackint-xmpp]: https://hackint.org/transport/xmpp
|
||||||
|
[snix-xmpp]: xmpp:#snix@irc.hackint.org?join
|
||||||
|
[snix-matrix]: https://matrix.to/#/#snix:hackint.org
|
||||||
|
[snix-webchat]: https://chat.hackint.org/?join=snix
|
||||||
|
[issues]: https://git.snix.dev/snix/snix/issues
|
||||||
|
[code]: https://git.snix.dev/snix/snix
|
||||||
11
web/content/docs/_index.md
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
title: "Docs"
|
||||||
|
description: ""
|
||||||
|
summary: ""
|
||||||
|
date: 2023-09-07T16:12:03+02:00
|
||||||
|
lastmod: 2023-09-07T16:12:03+02:00
|
||||||
|
draft: false
|
||||||
|
weight: 999
|
||||||
|
toc: true
|
||||||
|
---
|
||||||
|
|
||||||
12
web/content/docs/components/_index.md
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
title: "Components"
|
||||||
|
description: ""
|
||||||
|
summary: ""
|
||||||
|
date: 2023-09-07T16:12:37+02:00
|
||||||
|
lastmod: 2023-09-07T16:12:37+02:00
|
||||||
|
draft: false
|
||||||
|
weight: 30
|
||||||
|
toc: true
|
||||||
|
sidebar:
|
||||||
|
collapsed: false
|
||||||
|
---
|
||||||
26
web/content/docs/components/architecture.md
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
---
|
||||||
|
title: "Architecture"
|
||||||
|
slug: architecture
|
||||||
|
description: ""
|
||||||
|
summary: ""
|
||||||
|
date: 2025-03-14T14:14:35+01:00
|
||||||
|
lastmod: 2025-03-14T14:14:35+01:00
|
||||||
|
draft: false
|
||||||
|
weight: 31
|
||||||
|
toc: true
|
||||||
|
---
|
||||||
|
|
||||||
|
Snix is more decoupled than the existing, monolithic Nix implementation.
|
||||||
|
|
||||||
|
In practice, we expect to gain several benefits from this, such as:
|
||||||
|
|
||||||
|
* Ability to use different builders
|
||||||
|
* Ability to use different store implementations
|
||||||
|
* No monopolisation of the implementation, allowing users to replace components
|
||||||
|
that they are unhappy with (up to and including the language evaluator)
|
||||||
|
* Less hidden intra-dependencies between tools due to explicit RPC/IPC
|
||||||
|
boundaries
|
||||||
|
|
||||||
|
In addition to many individual backend implementations, Builders and Store
|
||||||
|
backends also provide a gRPC server and clients, allowing to plug in your own
|
||||||
|
implementation.
|
||||||
13
web/content/docs/components/build/_index.md
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
title: "Builder"
|
||||||
|
description: ""
|
||||||
|
summary: ""
|
||||||
|
date: 2023-09-07T16:12:37+02:00
|
||||||
|
lastmod: 2023-09-07T16:12:37+02:00
|
||||||
|
draft: false
|
||||||
|
weight: 40
|
||||||
|
toc: true
|
||||||
|
sidebar:
|
||||||
|
collapsed: true
|
||||||
|
---
|
||||||
|
|
||||||
17
web/content/docs/components/build/oci.md
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
---
|
||||||
|
title: "OCI Builder"
|
||||||
|
slug: oci
|
||||||
|
description: ""
|
||||||
|
summary: ""
|
||||||
|
date: 2023-09-07T16:12:37+02:00
|
||||||
|
lastmod: 2023-09-07T16:12:37+02:00
|
||||||
|
draft: false
|
||||||
|
weight: 42
|
||||||
|
toc: true
|
||||||
|
sidebar:
|
||||||
|
collapsed: true
|
||||||
|
---
|
||||||
|
|
||||||
|
The OCI builder creates a OCI Runtime specification out of the received
|
||||||
|
`BuildRequest`, then mounts the specified inputs using snix-castore, and then
|
||||||
|
invokes `runc`.
|
||||||
35
web/content/docs/components/build/protocol.md
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
---
|
||||||
|
title: "Protocol"
|
||||||
|
slug: protocol
|
||||||
|
description: ""
|
||||||
|
summary: ""
|
||||||
|
date: 2025-03-14T14:14:35+01:00
|
||||||
|
lastmod: 2025-03-14T14:14:35+01:00
|
||||||
|
draft: false
|
||||||
|
weight: 41
|
||||||
|
toc: true
|
||||||
|
---
|
||||||
|
|
||||||
|
One goal of the builder protocol is to not be too tied to the Nix implementation
|
||||||
|
itself, allowing it to be used for other builds/workloads in the future.
|
||||||
|
|
||||||
|
This means the builder protocol is versatile enough to express the environment a
|
||||||
|
Nix build expects, while not being aware of "what any of this means".
|
||||||
|
|
||||||
|
For example, it is not aware of how certain environment variables are set in a
|
||||||
|
nix build, but allows specifying environment variables that should be set.
|
||||||
|
|
||||||
|
It's also not aware of what nix store paths are. Instead, it allows:
|
||||||
|
|
||||||
|
- specifying a list of paths expected to be produced during the build
|
||||||
|
- specifying a list of castore root nodes to be present in a specified
|
||||||
|
`inputs_dir`.
|
||||||
|
- specifying which paths are write-able during build.
|
||||||
|
|
||||||
|
In case all specified paths are produced, and the command specified in
|
||||||
|
`command_args` succeeds, the build is considered to be successful.
|
||||||
|
|
||||||
|
This happens to be sufficient to *also* express how Nix builds works.
|
||||||
|
|
||||||
|
Check `build/protos/build.proto` for a detailed description of the individual
|
||||||
|
fields, and the tests in `glue/src/tvix_build.rs` for some examples.
|
||||||
45
web/content/docs/components/build/reference-scanning.md
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
---
|
||||||
|
title: "Reference Scanning"
|
||||||
|
summary: ""
|
||||||
|
date: 2025-03-14T14:14:35+01:00
|
||||||
|
lastmod: 2025-03-14T14:14:35+01:00
|
||||||
|
draft: false
|
||||||
|
weight: 45
|
||||||
|
toc: true
|
||||||
|
---
|
||||||
|
|
||||||
|
At the end of a build, Nix does scan a store path for references to other store
|
||||||
|
paths (*out of the set of all store paths present during the build*).
|
||||||
|
It does do this by (only) looking for a list of nixbase32-encoded hashes in
|
||||||
|
filenames (?), symlink targets and blob contents.
|
||||||
|
|
||||||
|
As outlined in the [Builder Protocol]({{< relref "protocol" >}}) page, we
|
||||||
|
don't want to introduce Nix specifics to the builder protocol, but if we simply
|
||||||
|
do refscanning on the coordinator side, that side would need to download the
|
||||||
|
produced inputs and scan them locally.
|
||||||
|
|
||||||
|
This is undesireable, as the builder already has all produced
|
||||||
|
outputs locally, and it'd make more sense for it do do it.
|
||||||
|
|
||||||
|
Instead, we want to describe reference scanning in a generic, non-Nix-specific
|
||||||
|
fashion.
|
||||||
|
|
||||||
|
## Proposal
|
||||||
|
|
||||||
|
One way to do this is to add an additional field `refscan_needles` to the
|
||||||
|
`BuildRequest` message.
|
||||||
|
If this is an non-empty list, all `outputs` are scanned for these.
|
||||||
|
|
||||||
|
The `Build` response message would then be extended with an `outputs_needles`
|
||||||
|
field, containing the same number of elements as the existing `outputs` field,
|
||||||
|
describing which `refscan_needles` are found for each output.
|
||||||
|
|
||||||
|
If there's needles found, they will be a list of indexes into the
|
||||||
|
`refscan_needles` field specified in the `BuildRequest` field.
|
||||||
|
|
||||||
|
For Nix, `refscan_needles` would be populated with the nixbase32 hash parts of
|
||||||
|
every input store path and output store path. The latter is necessary to scan
|
||||||
|
for references between multi-output derivations.
|
||||||
|
|
||||||
|
This is sufficient to construct the referred store paths in each build output on
|
||||||
|
the build client.
|
||||||
98
web/content/docs/components/overview.md
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
---
|
||||||
|
title: "Component Overview"
|
||||||
|
slug: overview
|
||||||
|
description: ""
|
||||||
|
summary: ""
|
||||||
|
date: 2025-03-14T14:14:35+01:00
|
||||||
|
lastmod: 2025-03-14T14:14:35+01:00
|
||||||
|
draft: false
|
||||||
|
weight: 32
|
||||||
|
toc: true
|
||||||
|
---
|
||||||
|
|
||||||
|
This diagram gives an overview over the different crates in the repository, the
|
||||||
|
different contained components and the dependencies in between them.
|
||||||
|
|
||||||
|
If you scroll further down, you find a textual description of what each component does.
|
||||||
|
Check the individual documentation pages for more details.
|
||||||
|
|
||||||
|
{{< inline-svg src="crate-diagram.svg" width="800px" height="800px" class="svg-inline-custom" >}}
|
||||||
|
|
||||||
|
|
||||||
|
## Castore
|
||||||
|
`snix-castore` is a content-addressed data storage / syncing engine.
|
||||||
|
|
||||||
|
It uses a merkle structure to store filesystem trees, as well as a chunked blob
|
||||||
|
storage for individual file contents.
|
||||||
|
|
||||||
|
It is not Nix-specific.
|
||||||
|
|
||||||
|
|
||||||
|
## Store
|
||||||
|
`snix-store` is a Nix store implementation using `snix-castore` for the
|
||||||
|
underlying data structure.
|
||||||
|
|
||||||
|
It only stores metadata like store path names, nar hashes, references,
|
||||||
|
signatures etc, and offloads content storage to `snix-castore`, by storing the
|
||||||
|
root node describing the contents.
|
||||||
|
|
||||||
|
There's also a CLI entrypoint that can be used to host a gRPC server endpoint,
|
||||||
|
copy into a store, or mount a store as a FUSE/virtiofs.
|
||||||
|
|
||||||
|
## Nix-Compat
|
||||||
|
`nix-compat` is a library providing access to various data formats, protocols
|
||||||
|
and concepts of Nix.
|
||||||
|
|
||||||
|
It does not depend on other Snix crates, making it a low-dependency crate to
|
||||||
|
include in other (non-snix) projects as well.
|
||||||
|
|
||||||
|
Other snix crates are usually the primary consumers and drive new functionality
|
||||||
|
in there - new formats etc. are usually "factored out into nix-compat".
|
||||||
|
|
||||||
|
## Builder
|
||||||
|
The builder consumes build requests from a client, runs builds and sends
|
||||||
|
logs/telemetry to the client.
|
||||||
|
|
||||||
|
There currently exists an OCI builder, as well as gRPC server adapter and client
|
||||||
|
implementations, allowing to run the builder both locally or remotely.
|
||||||
|
|
||||||
|
## Eval
|
||||||
|
`snix-eval` is a bytecode interpreter evaluator. It knows about basic Nix
|
||||||
|
language data structures and semantics, constructs bytecode and provides a VM
|
||||||
|
executing this bytecode.
|
||||||
|
|
||||||
|
It also provides some "core" builtins, though builtins are pluggable - you can
|
||||||
|
construct an evaluator and bring your own builtins.
|
||||||
|
|
||||||
|
It also defines the `EvalIO` trait and provides some very simple implementations
|
||||||
|
of it, which is how the evaluator does do IO.
|
||||||
|
|
||||||
|
|
||||||
|
## Glue
|
||||||
|
`snix-glue` provides some more builtins (those interacting with the Builder and
|
||||||
|
Store mostly).
|
||||||
|
|
||||||
|
It allows keeping `snix-eval` relatively simple.
|
||||||
|
|
||||||
|
## CLI
|
||||||
|
`snix-cli` is a REPL interface, constructing an Evaluator and populating it with
|
||||||
|
most builtins present in Nix. It is our main vehicle to evaluate Nixpkgs and
|
||||||
|
check for differences.
|
||||||
|
|
||||||
|
## Serde
|
||||||
|
`snix-serde` is a crate allowing (de)-serialisation of Rust data structures
|
||||||
|
to/from Nix. It allows you to use (a subset of) Nix as a configuration language
|
||||||
|
in/for your application.
|
||||||
|
|
||||||
|
## Tracing
|
||||||
|
`snix-tracing` contains some common tracing / logging / progress reporting code
|
||||||
|
that's used in various CLI entrypoints.
|
||||||
|
|
||||||
|
## Nar-Bridge
|
||||||
|
`nar-bridge` provides a Nix HTTP Binary cache server endpoint (read-write),
|
||||||
|
using `snix-[ca]store` to store the underlying data. It allows you to host your
|
||||||
|
own binary cache that Nix can talk to.
|
||||||
|
|
||||||
|
## Snixbolt
|
||||||
|
This uses `snix-eval`, providing a WASM bytecode explorer running in your
|
||||||
|
browser.
|
||||||
10
web/content/docs/guides/_index.md
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
title: "Guides"
|
||||||
|
description: ""
|
||||||
|
summary: ""
|
||||||
|
date: 2023-09-07T16:06:50+02:00
|
||||||
|
lastmod: 2023-09-07T16:06:50+02:00
|
||||||
|
draft: false
|
||||||
|
weight: 10
|
||||||
|
toc: true
|
||||||
|
---
|
||||||
73
web/content/docs/guides/building.md
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
---
|
||||||
|
title: "Building Snix"
|
||||||
|
slug: building
|
||||||
|
description: ""
|
||||||
|
summary: ""
|
||||||
|
date: 2025-03-14T14:14:35+01:00
|
||||||
|
lastmod: 2025-03-14T14:14:35+01:00
|
||||||
|
draft: false
|
||||||
|
weight: 11
|
||||||
|
toc: true
|
||||||
|
---
|
||||||
|
|
||||||
|
This document describes how to build the project locally, both for interactive
|
||||||
|
development as well as referring to it from Nix code (for example, to run one of
|
||||||
|
its binaries on your machine).
|
||||||
|
|
||||||
|
{{<callout>}}
|
||||||
|
Please check the [Contribution Guide]({{< relref "contributing" >}}) on how to
|
||||||
|
contribute after following this guide.
|
||||||
|
{{</callout>}}
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
- Ensure you have [Direnv][] installed and [hooked into your shell][direnv-inst].
|
||||||
|
- Ensure you have [Nix][] installed.
|
||||||
|
|
||||||
|
### Getting the sources
|
||||||
|
Snix is hosted in its own Forgejo instance, hosted on [git.snix.dev](https://git.snix.dev/snix/snix), and a
|
||||||
|
(read-only) mirror on [GitHub](https://github.com/snix-project/snix).
|
||||||
|
|
||||||
|
Check out the source code as follows:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ git clone https://git.snix.dev/snix-project/snix.git
|
||||||
|
```
|
||||||
|
|
||||||
|
### Interactive development
|
||||||
|
```console
|
||||||
|
$ direnv allow
|
||||||
|
$ mg shell //snix:shell
|
||||||
|
```
|
||||||
|
|
||||||
|
This provides all the necessary tools and dependencies to interactively build
|
||||||
|
the source code, using `cargo build` etc.
|
||||||
|
|
||||||
|
### Building only
|
||||||
|
|
||||||
|
It is also possible to build the different Snix crates with Nix,
|
||||||
|
in which you don't need to enter the shell.
|
||||||
|
From the root of the repository, you can build as follows:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ nix-build -A snix.cli
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can use the `mg` wrapper from anywhere in the repository (requires the direnv setup from above):
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ mg build //snix:cli
|
||||||
|
```
|
||||||
|
|
||||||
|
This uses [crate2nix][] to build each crate dependency individually.
|
||||||
|
|
||||||
|
Checkout the [Component Overview]({{< ref "/docs/components/overview" >}})
|
||||||
|
to learn more about the project structure.
|
||||||
|
|
||||||
|
|
||||||
|
[Direnv]: https://direnv.net
|
||||||
|
[direnv-inst]: https://direnv.net/docs/installation.html
|
||||||
|
[Nix]: https://nixos.org/nix/
|
||||||
|
[mg]: https://code.tvl.fyi/tree/tools/magrathea
|
||||||
|
[crate2nix]: https://github.com/nix-community/crate2nix/
|
||||||
|
|
||||||
|
|
||||||
127
web/content/docs/guides/contributing.md
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
---
|
||||||
|
title: "Contributing"
|
||||||
|
description: ""
|
||||||
|
summary: ""
|
||||||
|
date: 2025-03-14T14:14:35+01:00
|
||||||
|
lastmod: 2025-03-14T14:14:35+01:00
|
||||||
|
draft: false
|
||||||
|
weight: 12
|
||||||
|
toc: true
|
||||||
|
---
|
||||||
|
|
||||||
|
You want to start contributing? Nice!
|
||||||
|
|
||||||
|
We do use [Gerrit](https://www.gerritcodereview.com) for Code Review.
|
||||||
|
It allows a more granular review (per-commit granularity rather than PR
|
||||||
|
granularity), as well as keeping track as how commits change over time.
|
||||||
|
It greatly simplifies the review process, and leads to overall more high-quality
|
||||||
|
contributions.
|
||||||
|
|
||||||
|
While it might initially look a bit intimidating, you hopefully will spend less
|
||||||
|
time learning its workflow than writing actual Snix code.
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-mood-wink-2"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 21a9 9 0 1 1 0 -18a9 9 0 0 1 0 18z" /><path d="M9 10h-.01" /><path d="M14.5 15a3.5 3.5 0 0 1 -5 0" /><path d="M15.5 8.5l-1.5 1.5l1.5 1.5" /></svg>
|
||||||
|
|
||||||
|
{{<callout>}}
|
||||||
|
This assumes you have the repo already cloned and the necessary tools installed
|
||||||
|
as described in [Building Snix]({{< relref "./building" >}}), so make sure you
|
||||||
|
went through these instructions first.
|
||||||
|
{{</callout>}}
|
||||||
|
|
||||||
|
### Creating a Gerrit account
|
||||||
|
- Navigate to [our Gerrit instance][snix-gerrit]. Hit the "Sign in" button
|
||||||
|
(which allows SSO with a GitHub account) [^1]
|
||||||
|
- In the User settings, paste an SSH public key and hit the "Add New SSH key"
|
||||||
|
button. [^2]
|
||||||
|
- Alternatively, you can also create "HTTP Credentials" (though saving the HTTP
|
||||||
|
password is messy).
|
||||||
|
|
||||||
|
### Update your git remote URL
|
||||||
|
Instead of trying to push to Forgejo, reconfigure your git remote URL to
|
||||||
|
interact with Gerrit directly.
|
||||||
|
|
||||||
|
Replace `$USER` with your `Username` shown in the Gerrit settings.
|
||||||
|
|
||||||
|
#### If using SSH authentication:
|
||||||
|
```console
|
||||||
|
$ git remote set-url origin "ssh://$USER@cl.snix.dev:29418/snix"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### If using HTTP authentication:
|
||||||
|
```console
|
||||||
|
$ git remote set-url origin "https://$USER@cl.snix.dev/a/snix"
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- TODO: fix replication to include refs/changes/… etc, and ensure it
|
||||||
|
replicates fast enough, then update to --push only -->
|
||||||
|
|
||||||
|
### Install the commit-msg hook
|
||||||
|
Gerrit uses a `commit-msg` hook to add a `Change-Id: …` field to each commit
|
||||||
|
message if not present already. This allows Gerrit to identify new revisions /
|
||||||
|
updates of old commits, and track them as new revisions of the same "CL" [^3].
|
||||||
|
|
||||||
|
To install the commit-msg hook, run the following from the repo root:
|
||||||
|
|
||||||
|
```console
|
||||||
|
mkdir -p .git/hooks
|
||||||
|
curl -Lo .git/hooks/commit-msg https://cl.snix.dev/tools/hooks/commit-msg
|
||||||
|
chmod +x .git/hooks/commit-msg
|
||||||
|
```
|
||||||
|
|
||||||
|
{{< callout context="tip" title="Did you know?" icon="outline/rocket" >}}
|
||||||
|
Gerrit refuses receiving commits without these `Change-Id: …` fields.
|
||||||
|
|
||||||
|
If you already have some local commits without `Change-Id` field, `git commit
|
||||||
|
--amend` them after installing the `commit-msg` hook to add them.
|
||||||
|
{{< /callout >}}
|
||||||
|
|
||||||
|
### Push your changes
|
||||||
|
Do some local changes, and push them to Gerrit as follows:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ git push origin HEAD:refs/for/canon
|
||||||
|
```
|
||||||
|
|
||||||
|
Gerrit will print links to newly created CLs to your terminal.
|
||||||
|
|
||||||
|
If you want to update/edit your CL, simply squash these changes into your local
|
||||||
|
commit and push again.
|
||||||
|
|
||||||
|
### The Gerrit model
|
||||||
|
If do not have experience with the Gerrit, consider reading the
|
||||||
|
[<cite>Working with Gerrit: An example</cite>][Gerrit Walkthrough] or
|
||||||
|
[<cite>Basic Gerrit Walkthrough — For GitHub Users</cite>][gerrit-for-github-users].
|
||||||
|
|
||||||
|
Some more tips:
|
||||||
|
|
||||||
|
* Assign a reviewer to review your changes.
|
||||||
|
* React on comments and mark them as resolved once you did.
|
||||||
|
* Comments are only "Drafts" (stored server-side) until you send them off.
|
||||||
|
This can be done by the `Reply` button on the top, for example.
|
||||||
|
* Once CI is green, it's up to the *Author* of the CL to submit, not the
|
||||||
|
reviewer.
|
||||||
|
If you want a bot to automatically submit in this case, you can add the
|
||||||
|
`Autosubmit+1` label.
|
||||||
|
* Rebase on `origin/canon` regularly. You cannot push if you still have an old
|
||||||
|
version of a now-submitted CL in your git log.
|
||||||
|
|
||||||
|
{{< callout context="tip" title="Did you know?" icon="outline/rocket" >}}
|
||||||
|
You can immediately assign reviewers and other fields while pushing a
|
||||||
|
new/updated change, by adding it to the push URL.
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ git push origin HEAD:refs/for/canon%r=alice,cc=bob,l=Autosubmit+1,publish-comments
|
||||||
|
```
|
||||||
|
* will set `alice` as a reviewer
|
||||||
|
* will set `bob` as CC
|
||||||
|
* adds the `Autosubmit+1` label
|
||||||
|
* publishes any outstanding draft comments
|
||||||
|
{{< /callout >}}
|
||||||
|
|
||||||
|
|
||||||
|
[snix-gerrit]: https://cl.snix.dev
|
||||||
|
[Gerrit walkthrough]: https://gerrit-review.googlesource.com/Documentation/intro-gerrit-walkthrough.html
|
||||||
|
[gerrit-for-github-users]: https://gerrit.wikimedia.org/r/Documentation/intro-gerrit-walkthrough-github.html
|
||||||
|
[^1]: more SSO providers to come
|
||||||
|
[^2]: currently, `ssh-*-sk` keytypes are not supported, so use an `ssh-ed25519` key.
|
||||||
|
[^3]: abbreviation for "change list", and the review unit in Gerrit.
|
||||||
37
web/content/docs/guides/use-as-library.md
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
---
|
||||||
|
title: "Use as a library"
|
||||||
|
slug: use-as-library
|
||||||
|
description: ""
|
||||||
|
summary: ""
|
||||||
|
date: 2025-03-14T14:14:35+01:00
|
||||||
|
lastmod: 2025-03-14T14:14:35+01:00
|
||||||
|
draft: false
|
||||||
|
weight: 13
|
||||||
|
toc: true
|
||||||
|
---
|
||||||
|
|
||||||
|
If you want to use (parts of) Snix in your own project, you can simply refer to
|
||||||
|
it using cargo and specifying the git sources. `cargo` will pin the exact rev
|
||||||
|
in `Cargo.lock`. See [The Cargo Book](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#specifying-dependencies-from-git-repositories) for details.
|
||||||
|
|
||||||
|
We do not publish to crates.io yet, due to the interfaces still being a bit
|
||||||
|
in flux.
|
||||||
|
|
||||||
|
For example, to add `nix-compat`, exposing a lot of Nix data types and formats,
|
||||||
|
add the following line to your `Cargo.toml`'s `[dependencies]`':
|
||||||
|
|
||||||
|
|
||||||
|
```toml
|
||||||
|
nix-compat = { git = "https://git.snix.dev/snix/snix.git" }
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
{{<callout>}}
|
||||||
|
Keep in mind some crates have additional requirements on their environment.
|
||||||
|
|
||||||
|
For example, `snix-castore` and `snix-store` need to have access to a `protobuf`
|
||||||
|
compiler and the proto defintions (setting `PROTO_ROOT` usually).
|
||||||
|
`tvix-build` wants `TVIX_BUILD_SANDBOX_SHELL` to be set, etc.
|
||||||
|
|
||||||
|
Check each crates' `build.rs` scripts for details.
|
||||||
|
{{</callout>}}
|
||||||
17
web/content/docs/reference/_index.md
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
---
|
||||||
|
title: "Reference"
|
||||||
|
description: ""
|
||||||
|
summary: ""
|
||||||
|
date: 2023-09-07T16:12:37+02:00
|
||||||
|
lastmod: 2023-09-07T16:12:37+02:00
|
||||||
|
draft: false
|
||||||
|
weight: 900
|
||||||
|
toc: true
|
||||||
|
sidebar:
|
||||||
|
collapsed: true
|
||||||
|
seo:
|
||||||
|
title: "" # custom title (optional)
|
||||||
|
description: "" # custom description (recommended)
|
||||||
|
canonical: "" # custom canonical URL (optional)
|
||||||
|
robots: "" # custom robot tags (optional)
|
||||||
|
---
|
||||||
18
web/content/docs/reference/component-overview.md
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
title: "Component Overview"
|
||||||
|
slug: component-overview
|
||||||
|
description: ""
|
||||||
|
summary: ""
|
||||||
|
date: 2023-09-07T16:12:37+02:00
|
||||||
|
lastmod: 2023-09-07T16:12:37+02:00
|
||||||
|
draft: false
|
||||||
|
weight: 900
|
||||||
|
toc: true
|
||||||
|
sidebar:
|
||||||
|
collapsed: true
|
||||||
|
seo:
|
||||||
|
title: "" # custom title (optional)
|
||||||
|
description: "" # custom description (recommended)
|
||||||
|
canonical: "" # custom canonical URL (optional)
|
||||||
|
robots: "" # custom robot tags (optional)
|
||||||
|
---
|
||||||
21
web/content/docs/reference/example.md
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
title: "Example Reference"
|
||||||
|
description: "Reference pages are ideal for outlining how things work in terse and clear terms."
|
||||||
|
summary: ""
|
||||||
|
date: 2023-09-07T16:13:18+02:00
|
||||||
|
lastmod: 2023-09-07T16:13:18+02:00
|
||||||
|
draft: false
|
||||||
|
weight: 910
|
||||||
|
toc: true
|
||||||
|
seo:
|
||||||
|
title: "" # custom title (optional)
|
||||||
|
description: "" # custom description (recommended)
|
||||||
|
canonical: "" # custom canonical URL (optional)
|
||||||
|
robots: "" # custom robot tags (optional)
|
||||||
|
---
|
||||||
|
|
||||||
|
Reference pages are ideal for outlining how things work in terse and clear terms. Less concerned with telling a story or addressing a specific use case, they should give a comprehensive outline of what your documenting.
|
||||||
|
|
||||||
|
## Further reading
|
||||||
|
|
||||||
|
- Read [about reference](https://diataxis.fr/reference/) in the Diátaxis framework
|
||||||
17
web/content/docs/resources.md
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
---
|
||||||
|
title: "Resources"
|
||||||
|
description: ""
|
||||||
|
summary: ""
|
||||||
|
date: 2024-02-27T09:30:56+01:00
|
||||||
|
lastmod: 2024-02-27T09:30:56+01:00
|
||||||
|
draft: false
|
||||||
|
weight: 999
|
||||||
|
toc: true
|
||||||
|
seo:
|
||||||
|
title: "" # custom title (optional)
|
||||||
|
description: "" # custom description (recommended)
|
||||||
|
canonical: "" # custom canonical URL (optional)
|
||||||
|
robots: "" # custom robot tags (optional)
|
||||||
|
---
|
||||||
|
|
||||||
|
Link to valuable, relevant resources.
|
||||||
21
web/default.nix
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
{ pkgs, depot, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
shell = pkgs.mkShell {
|
||||||
|
name = "tvix-website";
|
||||||
|
packages = [
|
||||||
|
pkgs.nodejs
|
||||||
|
pkgs.hugo
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
website = depot.third_party.npmlock2nix.v2.build {
|
||||||
|
pname = "snix-website";
|
||||||
|
version = "0.0.0";
|
||||||
|
|
||||||
|
src = depot.third_party.gitignoreSource ./.;
|
||||||
|
|
||||||
|
installPhase = "cp -r public/. $out";
|
||||||
|
buildCommands = [ "PATH=\"$PATH:${pkgs.hugo}/bin\" npm run build" ];
|
||||||
|
};
|
||||||
|
}
|
||||||
63
web/layouts/index.html
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
{{ define "main" }}
|
||||||
|
<section class="section container-fluid mt-n3 pb-3">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-12 text-center">
|
||||||
|
<h1>{{ .Title }}</h1>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-9 col-xl-8 text-center">
|
||||||
|
<p class="lead">{{ .Params.lead | safeHTML }}</p>
|
||||||
|
<a class="btn btn-primary btn-cta rounded-pill btn-lg my-3" href="/about" role="button">Learn More</a>
|
||||||
|
{{ .Content }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ define "sidebar-prefooter" }}
|
||||||
|
{{ if site.Params.doks.backgroundDots -}}
|
||||||
|
<div class="d-flex justify-content-start">
|
||||||
|
<div class="bg-dots"></div>
|
||||||
|
</div>
|
||||||
|
{{ end -}}
|
||||||
|
{{ if eq $.Site.Language.LanguageName "English" }}
|
||||||
|
<section class="section section-md section-features">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center text-center">
|
||||||
|
<div class="col-lg-5">
|
||||||
|
<h2 class="h4">Composable and Modular by Design</h2>
|
||||||
|
<p>Snix is architected with a focus on composability. Different components representing different aspects of Nix can be combined and extended freely, allowing it to be tailored to your usecase.</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-5">
|
||||||
|
<h2 class="h4">Library-first Approach</h2>
|
||||||
|
<p>Designed to be embedded in your project, it opens up the possibility to interact with Nix expressions and concepts more natively than conventional Nix CLI-based tools.</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-5">
|
||||||
|
<h2 class="h4">Robust Unit Test Coverage</h2>
|
||||||
|
<p>Snix has a strong commitment to reliability and compatibility with Nix' behaviour, resulting in an extensive test suite, documentation and regression testing.</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-5">
|
||||||
|
<h2 class="h4">Content-addressed Storage model</h2>
|
||||||
|
<p>With its own content-addressed storage engine, Snix can store and exchange store path contents in a much more granular fashion, while providing great deduplication, consistency and integrity across build artifacts and dependencies.</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-5">
|
||||||
|
<h2 class="h4">Interoperability with Nix</h2>
|
||||||
|
<p>While potentially doing thing differently underneath, it provides a "Nix-compatible surface". This results in nixpkgs compatibility, allowing to produce the same build expressions as Nix, bit-by-bit, and interoperability with existing Nix binary caches.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ define "sidebar-footer" }}
|
||||||
|
{{ if site.Params.doks.sectionFooter -}}
|
||||||
|
<section class="section section-md container-fluid bg-light">
|
||||||
|
<div class="row justify-content-center text-center">
|
||||||
|
<div class="col-lg-7">
|
||||||
|
<h2 class="mt-2">Start building with Doks today</h2>
|
||||||
|
<a class="btn btn-primary rounded-pill px-4 my-2" href="/docs/{{ if site.Params.doks.docsVersioning }}{{ site.Params.doks.docsVersion }}/{{ end }}prologue/introduction/" role="button">{{ i18n "get-started" }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{{ end -}}
|
||||||
|
{{ end }}
|
||||||
13
web/layouts/partials/footer/script-footer-custom.html
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
{{/* Put your custom <script></script> tags here */}}
|
||||||
|
|
||||||
|
{{/* EXAMPLE - only load script for production
|
||||||
|
{{ if eq (hugo.Environment) "production" -}}
|
||||||
|
{{ partial "footer/esbuild" (dict "src" "js/instantpage.js" "load" "async" "transpile" false) -}}
|
||||||
|
{{ end -}}
|
||||||
|
*/}}
|
||||||
|
|
||||||
|
{{/* EXAMPLE - only load script for a page type e.g. contact or gallery
|
||||||
|
{{ if eq .Type "gallery" -}}
|
||||||
|
{{ partial "footer/esbuild" (dict "src" "js/gallery.js" "load" "async" "transpile" false) -}}
|
||||||
|
{{ end -}}
|
||||||
|
*/}}
|
||||||
1
web/layouts/partials/head/custom-head.html
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<!-- Custom head -->
|
||||||
1
web/layouts/partials/head/script-header.html
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<!-- Insert scripts NOT needed by stylesheets here -->
|
||||||
49
web/netlify.toml
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
[build]
|
||||||
|
publish = "public"
|
||||||
|
functions = "functions"
|
||||||
|
|
||||||
|
[build.environment]
|
||||||
|
NODE_VERSION = "20.11.0"
|
||||||
|
NPM_VERSION = "10.2.4"
|
||||||
|
HUGO_VERSION = "0.125.1"
|
||||||
|
|
||||||
|
[context.production]
|
||||||
|
command = "npm run build"
|
||||||
|
|
||||||
|
[context.deploy-preview]
|
||||||
|
command = "npm run build"
|
||||||
|
|
||||||
|
[context.branch-deploy]
|
||||||
|
command = "npm run build"
|
||||||
|
|
||||||
|
[context.next]
|
||||||
|
command = "npm run build"
|
||||||
|
|
||||||
|
[context.next.environment]
|
||||||
|
HUGO_ENV = "next"
|
||||||
|
|
||||||
|
[dev]
|
||||||
|
framework = "#custom"
|
||||||
|
command = "npm run dev"
|
||||||
|
targetPort = 1313
|
||||||
|
port = 8888
|
||||||
|
publish = "public"
|
||||||
|
autoLaunch = false
|
||||||
|
|
||||||
|
# Redirects and rewrites — https://docs.netlify.com/routing/redirects/#syntax-for-the-netlify-configuration-file
|
||||||
|
|
||||||
|
# Custom headers — https://docs.netlify.com/routing/headers/#syntax-for-the-netlify-configuration-file
|
||||||
|
[[headers]]
|
||||||
|
for = "/*"
|
||||||
|
[headers.values]
|
||||||
|
Strict-Transport-Security = "max-age=31536000; includeSubDomains; preload"
|
||||||
|
X-Content-Type-Options = "nosniff"
|
||||||
|
X-XSS-Protection = "1; mode=block"
|
||||||
|
Content-Security-Policy = "default-src 'self'; manifest-src 'self'; connect-src 'self'; font-src 'self'; img-src 'self' https://avatars.githubusercontent.com data:; script-src 'self' 'nonce-dXNlcj0iaGVsbG8iLGRvbWFpbj0iaGVua3ZlcmxpbmRlLmNvbSIsZG9jdW1lbnQud3JpdGUodXNlcisiQCIrZG9tYWluKTs=' 'sha256-aWZ3y/RxbBYKHXH0z8+8ljrHG1mSBvyzSfxSMjBSaXk='; style-src 'self'"
|
||||||
|
X-Frame-Options = "SAMEORIGIN"
|
||||||
|
Referrer-Policy = "strict-origin"
|
||||||
|
Permissions-Policy = "geolocation=(self), microphone=(), camera=()"
|
||||||
|
Cache-Control= '''
|
||||||
|
public,
|
||||||
|
max-age=31536000'''
|
||||||
|
Access-Control-Allow-Origin = "*"
|
||||||
4679
web/package-lock.json
generated
Normal file
28
web/package.json
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"name": "snix-website",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "The Snix Website",
|
||||||
|
"author": "The Snix Project",
|
||||||
|
"scripts": {
|
||||||
|
"create": "hugo new",
|
||||||
|
"dev": "hugo server --disableFastRender --noHTTPCache",
|
||||||
|
"format": "prettier **/** -w -c",
|
||||||
|
"build": "hugo --minify --gc",
|
||||||
|
"preview": "vite preview --outDir public"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@thulite/doks-core": "^1.8.0",
|
||||||
|
"@thulite/images": "^3.3.0",
|
||||||
|
"@thulite/inline-svg": "^1.1.0",
|
||||||
|
"@thulite/seo": "^2.4.1",
|
||||||
|
"@tabler/icons": "^3.12.0",
|
||||||
|
"thulite": "^2.5.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"prettier": "^3.3.3",
|
||||||
|
"vite": "^5.4.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.11.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
0
web/static/.gitkeep
Normal file
25
web/website/content/blog/example/index.md
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
title: "Example Post"
|
||||||
|
description: "Just an example post."
|
||||||
|
summary: "You can use blog posts for announcing product updates and features."
|
||||||
|
date: 2023-09-07T16:27:22+02:00
|
||||||
|
lastmod: 2023-09-07T16:27:22+02:00
|
||||||
|
draft: true
|
||||||
|
weight: 50
|
||||||
|
categories: []
|
||||||
|
tags: []
|
||||||
|
contributors: []
|
||||||
|
pinned: false
|
||||||
|
homepage: false
|
||||||
|
seo:
|
||||||
|
title: "" # custom title (optional)
|
||||||
|
description: "" # custom description (recommended)
|
||||||
|
canonical: "" # custom canonical URL (optional)
|
||||||
|
robots: "" # custom robot tags (optional)
|
||||||
|
---
|
||||||
|
|
||||||
|
Well-thought-through product announcements will help increase feature awareness and engage users with new functionality. Just like [sharing your public roadmap](https://canny.io/blog/should-you-have-a-public-roadmap/), it's also a great way to let potential customers see that you're constantly improving.
|
||||||
|
|
||||||
|
## Further reading
|
||||||
|
|
||||||
|
- Read [How to announce product updates and features](https://canny.io/blog/announce-product-updates-features/)
|
||||||