Initial commit
All checks were successful
deploy-pages Deployed in 22 seconds

This commit is contained in:
2023-01-01 00:33:05 +01:00
commit 6246856fda
23 changed files with 2596 additions and 0 deletions

13
.editorconfig Normal file
View File

@@ -0,0 +1,13 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.{hs,js,css}]
indent_style = tab
tab_width = 4

1
.envrc Normal file
View File

@@ -0,0 +1 @@
use nix

15
.gitattributes vendored Normal file
View File

@@ -0,0 +1,15 @@
*.nix text eol=lf
flake.lock text eol=lf
*.hs text eol=lf
*.cabal text eol=lf
cabal.project* text eol=lf
*.ps1 text eol=lf
*.css text eol=lf
*.html text eol=lf
*.js text eol=lf
*.md text eol=lf
*.yaml text eol=lf

15
.gitignore vendored Normal file
View File

@@ -0,0 +1,15 @@
.direnv/
result*
.cabal-sandbox/
cabal.sandbox.config
cabal.project.local
.stack-work/
dist*/
_generator/
_cache/
public/
thumbs.db

126
00-site.ps1 Executable file
View File

@@ -0,0 +1,126 @@
#!/usr/bin/env pwsh
$Env:PATH = "$PSScriptRoot\_generator\site;$PSScriptRoot\_generator\vips;$Env:PATH"
# Check if ConsoleGuiTools are available.
$cgt = Get-Module -ListAvailable Microsoft.PowerShell.ConsoleGuiTools
if ($cgt -eq $null) {
Write-Output 'Missing ConsoleGuiTools, please make sure you have PowerShell 7 and run the following command as an administrator:'
Write-Output ' Install-Module Microsoft.PowerShell.ConsoleGuiTools'
Read-Host
Exit 1
}
function FetchGenerator {
$tempFile = New-TemporaryFile
$url = 'https://temp.ogion.cz/site-zahradka.zip'
Invoke-WebRequest -Uri $url -OutFile $tempFile
Expand-Archive $tempFile -DestinationPath '_generator' -Force
}
function EnsureGenerator {
if (!(Test-Path '_generator/site/site.exe')) {
FetchGenerator
}
}
function SiteWatch {
EnsureGenerator
site watch
}
function SiteCheck {
EnsureGenerator
site check
Read-Host
}
function SiteBuild {
EnsureGenerator
site build
Read-Host
}
function SiteRebuild {
EnsureGenerator
site rebuild
Read-Host
}
function UpdateGenerator {
FetchGenerator
Read-Host
}
function Terminate {
[Terminal.Gui.Application]::RequestStop()
}
$action = $null
function MakeUi {
Import-Module Microsoft.PowerShell.ConsoleGuiTools
$module = (Get-Module Microsoft.PowerShell.ConsoleGuiTools -List).ModuleBase
Add-Type -Path (Join-path $module Terminal.Gui.dll)
[Terminal.Gui.Application]::Init()
$window = [Terminal.Gui.Window]::new()
$window.Title = 'site: mala-zahradka-pro-radost.cz'
[Terminal.Gui.Application]::Top.Add($window)
$watchButton = [Terminal.Gui.Button]::new()
$watchButton.Text = 'watch: Start test server and watch for changes'
$watchButton.add_Clicked({
$script:action = $function:SiteWatch
Terminate
})
$window.Add($watchButton)
$checkButton = [Terminal.Gui.Button]::new()
$checkButton.Text = 'check: Check links'
$checkButton.add_Clicked({
$script:action = $function:SiteCheck
Terminate
})
$checkButton.Y = [Terminal.Gui.Pos]::Bottom($watchButton)
$window.Add($checkButton)
$buildButton = [Terminal.Gui.Button]::new()
$buildButton.Text = 'build: Update output directory'
$buildButton.add_Clicked({
$script:action = $function:SiteBuild
Terminate
})
$buildButton.Y = [Terminal.Gui.Pos]::Bottom($checkButton) + 1
$window.Add($buildButton)
$rebuildButton = [Terminal.Gui.Button]::new()
$rebuildButton.Text = 'rebuild: Rebuild site from scratch'
$rebuildButton.add_Clicked({
$result = [Terminal.Gui.MessageBox]::Query('Rebuild', "Do you want to rebuild the web site output from scratch?`nIt can take a minute", @('Yes', 'No'))
if ($result -eq 0) {
$script:action = $function:SiteRebuild
Terminate
}
})
$rebuildButton.Y = [Terminal.Gui.Pos]::Bottom($buildButton)
$window.Add($rebuildButton)
$updateButton = [Terminal.Gui.Button]::new()
$updateButton.Text = 'Update the site program'
$updateButton.add_Clicked({
$script:action = $function:UpdateGenerator
Terminate
})
$updateButton.Y = [Terminal.Gui.Pos]::Bottom($rebuildButton) + 1
$window.Add($updateButton)
[Terminal.Gui.Application]::Run()
[Terminal.Gui.Application]::Shutdown()
}
MakeUi
if ($action -ne $null) {
& $action
}

14
default.nix Normal file
View File

@@ -0,0 +1,14 @@
# SPDX-FileCopyrightText: 2022 Jan Tojnar
# SPDX-License-Identifier: MIT
let
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
flake-compat = builtins.fetchTarball {
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
sha256 = lock.nodes.flake-compat.locked.narHash;
};
flake = import flake-compat {
src = ./.;
};
in
flake.defaultNix

935
flake.lock generated Normal file
View File

@@ -0,0 +1,935 @@
{
"nodes": {
"HTTP": {
"flake": false,
"locked": {
"lastModified": 1451647621,
"narHash": "sha256-oHIyw3x0iKBexEo49YeUDV1k74ZtyYKGR2gNJXXRxts=",
"owner": "phadej",
"repo": "HTTP",
"rev": "9bc0996d412fef1787449d841277ef663ad9a915",
"type": "github"
},
"original": {
"owner": "phadej",
"repo": "HTTP",
"type": "github"
}
},
"blank": {
"locked": {
"lastModified": 1625557891,
"narHash": "sha256-O8/MWsPBGhhyPoPLHZAuoZiiHo9q6FLlEeIDEXuj6T4=",
"owner": "divnix",
"repo": "blank",
"rev": "5a5d2684073d9f563072ed07c871d577a6c614a8",
"type": "github"
},
"original": {
"owner": "divnix",
"repo": "blank",
"type": "github"
}
},
"cabal-32": {
"flake": false,
"locked": {
"lastModified": 1603716527,
"narHash": "sha256-X0TFfdD4KZpwl0Zr6x+PLxUt/VyKQfX7ylXHdmZIL+w=",
"owner": "haskell",
"repo": "cabal",
"rev": "48bf10787e27364730dd37a42b603cee8d6af7ee",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "3.2",
"repo": "cabal",
"type": "github"
}
},
"cabal-34": {
"flake": false,
"locked": {
"lastModified": 1640353650,
"narHash": "sha256-N1t6M3/wqj90AEdRkeC8i923gQYUpzSr8b40qVOZ1Rk=",
"owner": "haskell",
"repo": "cabal",
"rev": "942639c18c0cd8ec53e0a6f8d120091af35312cd",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "3.4",
"repo": "cabal",
"type": "github"
}
},
"cabal-36": {
"flake": false,
"locked": {
"lastModified": 1641652457,
"narHash": "sha256-BlFPKP4C4HRUJeAbdembX1Rms1LD380q9s0qVDeoAak=",
"owner": "haskell",
"repo": "cabal",
"rev": "f27667f8ec360c475027dcaee0138c937477b070",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "3.6",
"repo": "cabal",
"type": "github"
}
},
"cardano-shell": {
"flake": false,
"locked": {
"lastModified": 1608537748,
"narHash": "sha256-PulY1GfiMgKVnBci3ex4ptk2UNYMXqGjJOxcPy2KYT4=",
"owner": "input-output-hk",
"repo": "cardano-shell",
"rev": "9392c75087cb9a3d453998f4230930dea3a95725",
"type": "github"
},
"original": {
"owner": "input-output-hk",
"repo": "cardano-shell",
"type": "github"
}
},
"devshell": {
"inputs": {
"flake-utils": [
"haskellNix",
"tullia",
"std",
"flake-utils"
],
"nixpkgs": [
"haskellNix",
"tullia",
"std",
"nixpkgs"
]
},
"locked": {
"lastModified": 1663445644,
"narHash": "sha256-+xVlcK60x7VY1vRJbNUEAHi17ZuoQxAIH4S4iUFUGBA=",
"owner": "numtide",
"repo": "devshell",
"rev": "e3dc3e21594fe07bdb24bdf1c8657acaa4cb8f66",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "devshell",
"type": "github"
}
},
"dmerge": {
"inputs": {
"nixlib": [
"haskellNix",
"tullia",
"std",
"nixpkgs"
],
"yants": [
"haskellNix",
"tullia",
"std",
"yants"
]
},
"locked": {
"lastModified": 1659548052,
"narHash": "sha256-fzI2gp1skGA8mQo/FBFrUAtY0GQkAIAaV/V127TJPyY=",
"owner": "divnix",
"repo": "data-merge",
"rev": "d160d18ce7b1a45b88344aa3f13ed1163954b497",
"type": "github"
},
"original": {
"owner": "divnix",
"repo": "data-merge",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1668681692,
"narHash": "sha256-Ht91NGdewz8IQLtWZ9LCeNXMSXHUss+9COoqu6JLmXU=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "009399224d5e398d03b22badca40a37ac85412a1",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_2": {
"flake": false,
"locked": {
"lastModified": 1635892615,
"narHash": "sha256-harGbMZr4hzat2BWBU+Y5OYXlu+fVz7E4WeQzHi5o8A=",
"owner": "input-output-hk",
"repo": "flake-compat",
"rev": "eca47d3377946315596da653862d341ee5341318",
"type": "github"
},
"original": {
"owner": "input-output-hk",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_3": {
"flake": false,
"locked": {
"lastModified": 1650374568,
"narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "b4a34015c698c7793d592d66adbab377907a2be8",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-utils": {
"locked": {
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"locked": {
"lastModified": 1644229661,
"narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_3": {
"locked": {
"lastModified": 1653893745,
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_4": {
"locked": {
"lastModified": 1659877975,
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_5": {
"locked": {
"lastModified": 1653893745,
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"ghc-8.6.5-iohk": {
"flake": false,
"locked": {
"lastModified": 1600920045,
"narHash": "sha256-DO6kxJz248djebZLpSzTGD6s8WRpNI9BTwUeOf5RwY8=",
"owner": "input-output-hk",
"repo": "ghc",
"rev": "95713a6ecce4551240da7c96b6176f980af75cae",
"type": "github"
},
"original": {
"owner": "input-output-hk",
"ref": "release/8.6.5-iohk",
"repo": "ghc",
"type": "github"
}
},
"gomod2nix": {
"inputs": {
"nixpkgs": "nixpkgs_2",
"utils": "utils"
},
"locked": {
"lastModified": 1655245309,
"narHash": "sha256-d/YPoQ/vFn1+GTmSdvbSBSTOai61FONxB4+Lt6w/IVI=",
"owner": "tweag",
"repo": "gomod2nix",
"rev": "40d32f82fc60d66402eb0972e6e368aeab3faf58",
"type": "github"
},
"original": {
"owner": "tweag",
"repo": "gomod2nix",
"type": "github"
}
},
"hackage": {
"flake": false,
"locked": {
"lastModified": 1672446463,
"narHash": "sha256-N5dcK1V+BLQeri5oB0ZSk2ABPs/hTGBC7jZvcY9CVLs=",
"owner": "input-output-hk",
"repo": "hackage.nix",
"rev": "7289869780da23633bc193e11d2da94ecee1489d",
"type": "github"
},
"original": {
"owner": "input-output-hk",
"repo": "hackage.nix",
"type": "github"
}
},
"hakyll-contrib-tojnar": {
"flake": false,
"locked": {
"lastModified": 1676857737,
"narHash": "sha256-g9fLkJM06EKFqsajt0ShQbZZdQd3MiUCeJkdkeVgpY0=",
"owner": "tojnar.cz",
"repo": "hakyll-contrib-tojnar",
"rev": "d82a20509e9bd3705ac1edc07677d68109768a70",
"type": "gitlab"
},
"original": {
"owner": "tojnar.cz",
"ref": "master",
"repo": "hakyll-contrib-tojnar",
"type": "gitlab"
}
},
"haskellNix": {
"inputs": {
"HTTP": "HTTP",
"cabal-32": "cabal-32",
"cabal-34": "cabal-34",
"cabal-36": "cabal-36",
"cardano-shell": "cardano-shell",
"flake-compat": "flake-compat_2",
"flake-utils": "flake-utils_2",
"ghc-8.6.5-iohk": "ghc-8.6.5-iohk",
"hackage": "hackage",
"hpc-coveralls": "hpc-coveralls",
"hydra": "hydra",
"iserv-proxy": "iserv-proxy",
"nixpkgs": [
"haskellNix",
"nixpkgs-unstable"
],
"nixpkgs-2003": "nixpkgs-2003",
"nixpkgs-2105": "nixpkgs-2105",
"nixpkgs-2111": "nixpkgs-2111",
"nixpkgs-2205": "nixpkgs-2205",
"nixpkgs-2211": "nixpkgs-2211",
"nixpkgs-unstable": "nixpkgs-unstable",
"old-ghc-nix": "old-ghc-nix",
"stackage": "stackage",
"tullia": "tullia"
},
"locked": {
"lastModified": 1672447880,
"narHash": "sha256-NB0wAAP7+/DZU4Nlw5yEWP8hcTiLjnMDElJH6K111bQ=",
"owner": "input-output-hk",
"repo": "haskell.nix",
"rev": "70d9708b5c932fbdd5e7e1124704844aeae975c3",
"type": "github"
},
"original": {
"owner": "input-output-hk",
"repo": "haskell.nix",
"type": "github"
}
},
"hpc-coveralls": {
"flake": false,
"locked": {
"lastModified": 1607498076,
"narHash": "sha256-8uqsEtivphgZWYeUo5RDUhp6bO9j2vaaProQxHBltQk=",
"owner": "sevanspowell",
"repo": "hpc-coveralls",
"rev": "14df0f7d229f4cd2e79f8eabb1a740097fdfa430",
"type": "github"
},
"original": {
"owner": "sevanspowell",
"repo": "hpc-coveralls",
"type": "github"
}
},
"hydra": {
"inputs": {
"nix": "nix",
"nixpkgs": [
"haskellNix",
"hydra",
"nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1646878427,
"narHash": "sha256-KtbrofMtN8GlM7D+n90kixr7QpSlVmdN+vK5CA/aRzc=",
"owner": "NixOS",
"repo": "hydra",
"rev": "28b682b85b7efc5cf7974065792a1f22203a5927",
"type": "github"
},
"original": {
"id": "hydra",
"type": "indirect"
}
},
"iserv-proxy": {
"flake": false,
"locked": {
"lastModified": 1639165170,
"narHash": "sha256-QsWL/sBDL5GM8IXd/dE/ORiL4RvteEN+aok23tXgAoc=",
"rev": "6e95df7be6dd29680f983db07a057fc2f34f81f6",
"revCount": 7,
"type": "git",
"url": "https://gitlab.haskell.org/ghc/iserv-proxy.git"
},
"original": {
"rev": "6e95df7be6dd29680f983db07a057fc2f34f81f6",
"type": "git",
"url": "https://gitlab.haskell.org/ghc/iserv-proxy.git"
}
},
"lowdown-src": {
"flake": false,
"locked": {
"lastModified": 1633514407,
"narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=",
"owner": "kristapsdz",
"repo": "lowdown",
"rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8",
"type": "github"
},
"original": {
"owner": "kristapsdz",
"repo": "lowdown",
"type": "github"
}
},
"mdbook-kroki-preprocessor": {
"flake": false,
"locked": {
"lastModified": 1661755005,
"narHash": "sha256-1TJuUzfyMycWlOQH67LR63/ll2GDZz25I3JfScy/Jnw=",
"owner": "JoelCourtney",
"repo": "mdbook-kroki-preprocessor",
"rev": "93adb5716d035829efed27f65f2f0833a7d3e76f",
"type": "github"
},
"original": {
"owner": "JoelCourtney",
"repo": "mdbook-kroki-preprocessor",
"type": "github"
}
},
"n2c": {
"inputs": {
"flake-utils": "flake-utils_5",
"nixpkgs": [
"haskellNix",
"tullia",
"std",
"nixpkgs"
]
},
"locked": {
"lastModified": 1665039323,
"narHash": "sha256-SAh3ZjFGsaCI8FRzXQyp56qcGdAqgKEfJWPCQ0Sr7tQ=",
"owner": "nlewo",
"repo": "nix2container",
"rev": "b008fe329ffb59b67bf9e7b08ede6ee792f2741a",
"type": "github"
},
"original": {
"owner": "nlewo",
"repo": "nix2container",
"type": "github"
}
},
"nix": {
"inputs": {
"lowdown-src": "lowdown-src",
"nixpkgs": "nixpkgs",
"nixpkgs-regression": "nixpkgs-regression"
},
"locked": {
"lastModified": 1643066034,
"narHash": "sha256-xEPeMcNJVOeZtoN+d+aRwolpW8mFSEQx76HTRdlhPhg=",
"owner": "NixOS",
"repo": "nix",
"rev": "a1cd7e58606a41fcf62bf8637804cf8306f17f62",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "2.6.0",
"repo": "nix",
"type": "github"
}
},
"nix-nomad": {
"inputs": {
"flake-compat": "flake-compat_3",
"flake-utils": [
"haskellNix",
"tullia",
"nix2container",
"flake-utils"
],
"gomod2nix": "gomod2nix",
"nixpkgs": [
"haskellNix",
"tullia",
"nixpkgs"
],
"nixpkgs-lib": [
"haskellNix",
"tullia",
"nixpkgs"
]
},
"locked": {
"lastModified": 1658277770,
"narHash": "sha256-T/PgG3wUn8Z2rnzfxf2VqlR1CBjInPE0l1yVzXxPnt0=",
"owner": "tristanpemble",
"repo": "nix-nomad",
"rev": "054adcbdd0a836ae1c20951b67ed549131fd2d70",
"type": "github"
},
"original": {
"owner": "tristanpemble",
"repo": "nix-nomad",
"type": "github"
}
},
"nix2container": {
"inputs": {
"flake-utils": "flake-utils_3",
"nixpkgs": "nixpkgs_3"
},
"locked": {
"lastModified": 1658567952,
"narHash": "sha256-XZ4ETYAMU7XcpEeAFP3NOl9yDXNuZAen/aIJ84G+VgA=",
"owner": "nlewo",
"repo": "nix2container",
"rev": "60bb43d405991c1378baf15a40b5811a53e32ffa",
"type": "github"
},
"original": {
"owner": "nlewo",
"repo": "nix2container",
"type": "github"
}
},
"nixago": {
"inputs": {
"flake-utils": [
"haskellNix",
"tullia",
"std",
"flake-utils"
],
"nixago-exts": [
"haskellNix",
"tullia",
"std",
"blank"
],
"nixpkgs": [
"haskellNix",
"tullia",
"std",
"nixpkgs"
]
},
"locked": {
"lastModified": 1661824785,
"narHash": "sha256-/PnwdWoO/JugJZHtDUioQp3uRiWeXHUdgvoyNbXesz8=",
"owner": "nix-community",
"repo": "nixago",
"rev": "8c1f9e5f1578d4b2ea989f618588d62a335083c3",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixago",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1632864508,
"narHash": "sha256-d127FIvGR41XbVRDPVvozUPQ/uRHbHwvfyKHwEt5xFM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "82891b5e2c2359d7e58d08849e4c89511ab94234",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-21.05-small",
"type": "indirect"
}
},
"nixpkgs-2003": {
"locked": {
"lastModified": 1620055814,
"narHash": "sha256-8LEHoYSJiL901bTMVatq+rf8y7QtWuZhwwpKE2fyaRY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "1db42b7fe3878f3f5f7a4f2dc210772fd080e205",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-20.03-darwin",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-2105": {
"locked": {
"lastModified": 1659914493,
"narHash": "sha256-lkA5X3VNMKirvA+SUzvEhfA7XquWLci+CGi505YFAIs=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "022caabb5f2265ad4006c1fa5b1ebe69fb0c3faf",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-21.05-darwin",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-2111": {
"locked": {
"lastModified": 1659446231,
"narHash": "sha256-hekabNdTdgR/iLsgce5TGWmfIDZ86qjPhxDg/8TlzhE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "eabc38219184cc3e04a974fe31857d8e0eac098d",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-21.11-darwin",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-2205": {
"locked": {
"lastModified": 1663981975,
"narHash": "sha256-TKaxWAVJR+a5JJauKZqibmaM5e/Pi5tBDx9s8fl/kSE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "309faedb8338d3ae8ad8f1043b3ccf48c9cc2970",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-22.05-darwin",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-2211": {
"locked": {
"lastModified": 1669997163,
"narHash": "sha256-vhjC0kZMFoN6jzK0GR+tBzKi5KgBXgehadfidW8+Va4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "6f87491a54d8d64d30af6663cb3bf5d2ee7db958",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-22.11-darwin",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-regression": {
"locked": {
"lastModified": 1643052045,
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
"type": "github"
},
"original": {
"id": "nixpkgs",
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
"type": "indirect"
}
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1663905476,
"narHash": "sha256-0CSwRKaYravh9v6qSlBpM0gNg0UhKT2lL7Yn6Zbx7UM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e14f9fb57315f0d4abde222364f19f88c77d2b79",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1653581809,
"narHash": "sha256-Uvka0V5MTGbeOfWte25+tfRL3moECDh1VwokWSZUdoY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "83658b28fe638a170a19b8933aa008b30640fbd1",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1654807842,
"narHash": "sha256-ADymZpr6LuTEBXcy6RtFHcUZdjKTBRTMYwu19WOx17E=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "fc909087cc3386955f21b4665731dbdaceefb1d8",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_4": {
"locked": {
"lastModified": 1665087388,
"narHash": "sha256-FZFPuW9NWHJteATOf79rZfwfRn5fE0wi9kRzvGfDHPA=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "95fda953f6db2e9496d2682c4fc7b82f959878f7",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"old-ghc-nix": {
"flake": false,
"locked": {
"lastModified": 1631092763,
"narHash": "sha256-sIKgO+z7tj4lw3u6oBZxqIhDrzSkvpHtv0Kki+lh9Fg=",
"owner": "angerman",
"repo": "old-ghc-nix",
"rev": "af48a7a7353e418119b6dfe3cd1463a657f342b8",
"type": "github"
},
"original": {
"owner": "angerman",
"ref": "master",
"repo": "old-ghc-nix",
"type": "github"
}
},
"root": {
"inputs": {
"flake-compat": "flake-compat",
"flake-utils": "flake-utils",
"hakyll-contrib-tojnar": "hakyll-contrib-tojnar",
"haskellNix": "haskellNix",
"nixpkgs": [
"haskellNix",
"nixpkgs-unstable"
]
}
},
"stackage": {
"flake": false,
"locked": {
"lastModified": 1672445456,
"narHash": "sha256-mN7ErqNTaGhxZagKmraHENaGABlkTPvgjmBTqc0T4to=",
"owner": "input-output-hk",
"repo": "stackage.nix",
"rev": "471a9366faa919b285943bf053884cbb026cc284",
"type": "github"
},
"original": {
"owner": "input-output-hk",
"repo": "stackage.nix",
"type": "github"
}
},
"std": {
"inputs": {
"blank": "blank",
"devshell": "devshell",
"dmerge": "dmerge",
"flake-utils": "flake-utils_4",
"makes": [
"haskellNix",
"tullia",
"std",
"blank"
],
"mdbook-kroki-preprocessor": "mdbook-kroki-preprocessor",
"microvm": [
"haskellNix",
"tullia",
"std",
"blank"
],
"n2c": "n2c",
"nixago": "nixago",
"nixpkgs": "nixpkgs_4",
"yants": "yants"
},
"locked": {
"lastModified": 1665513321,
"narHash": "sha256-D6Pacw9yf/HMs84KYuCxHXnNDL7v43gtcka5URagFqE=",
"owner": "divnix",
"repo": "std",
"rev": "94a90eedb9cfc115b12ae8f6622d9904788559e4",
"type": "github"
},
"original": {
"owner": "divnix",
"repo": "std",
"type": "github"
}
},
"tullia": {
"inputs": {
"nix-nomad": "nix-nomad",
"nix2container": "nix2container",
"nixpkgs": [
"haskellNix",
"nixpkgs"
],
"std": "std"
},
"locked": {
"lastModified": 1668711738,
"narHash": "sha256-CBjky16o9pqsGE1bWu6nRlRajgSXMEk+yaFQLibqXcE=",
"owner": "input-output-hk",
"repo": "tullia",
"rev": "ead1f515c251f0e060060ef0e2356a51d3dfe4b0",
"type": "github"
},
"original": {
"owner": "input-output-hk",
"repo": "tullia",
"type": "github"
}
},
"utils": {
"locked": {
"lastModified": 1653893745,
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"yants": {
"inputs": {
"nixpkgs": [
"haskellNix",
"tullia",
"std",
"nixpkgs"
]
},
"locked": {
"lastModified": 1660507851,
"narHash": "sha256-BKjq7JnVuUR/xDtcv6Vm9GYGKAblisXrAgybor9hT/s=",
"owner": "divnix",
"repo": "yants",
"rev": "0b895ca02a8fa72bad50b454cb3e7d8a66407c96",
"type": "github"
},
"original": {
"owner": "divnix",
"repo": "yants",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

104
flake.nix Normal file
View File

@@ -0,0 +1,104 @@
{
description = "Source for mala-zahradka-pro-radost.cz";
inputs = {
flake-compat = {
url = "github:edolstra/flake-compat";
flake = false;
};
haskellNix.url = "github:input-output-hk/haskell.nix";
nixpkgs.follows = "haskellNix/nixpkgs-unstable";
hakyll-contrib-tojnar = {
url = "gitlab:tojnar.cz/hakyll-contrib-tojnar?ref=master";
flake = false;
};
flake-utils.url = "github:numtide/flake-utils";
};
nixConfig = {
extra-substituters = ["https://cache.iog.io"];
extra-trusted-public-keys = ["hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ="];
allow-import-from-derivation = "true";
};
outputs = { self, flake-compat, haskellNix, hakyll-contrib-tojnar, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
compiler = "ghc925";
overlays = [
haskellNix.overlay
(final: prev: {
mala-zahradka-pro-radost-cz =
final.haskell-nix.project' {
src = ./site;
compiler-nix-name = compiler;
shell.tools = {
cabal = {};
};
inputMap = {
"https://gitlab.com/tojnar.cz/hakyll-contrib-tojnar/master" = hakyll-contrib-tojnar;
};
};
})
];
pkgs = import nixpkgs {
inherit system;
inherit overlays;
inherit (haskellNix) config;
};
flake = pkgs.mala-zahradka-pro-radost-cz.flake {
crossPlatforms = p: [
p.mingwW64
];
};
in flake // {
devShells = {
default = pkgs.mkShell {
nativeBuildInputs = [
self.packages.${system}.default
pkgs.vips
];
};
haskell = flake.devShells.default;
};
packages = {
default = flake.packages."mala-zahradka-pro-radost-cz:exe:site";
win = flake.packages."x86_64-w64-mingw32:mala-zahradka-pro-radost-cz:exe:site";
roots = pkgs.haskell-nix.roots compiler;
winCombined =
let
version = "8.14.1";
vips = pkgs.fetchzip {
url = "https://github.com/libvips/build-win64-mxe/releases/download/v${version}/vips-dev-w64-all-${version}.zip";
hash = "sha256-yGAoRwyfeMTiDSSOfWJp32N85Z8Jdyw8wrvEvmx7BWM=";
};
in
pkgs.runCommand
"generator"
{
nativeBuildInputs = [
pkgs.zip
];
}
''
mkdir -p "$out"
mkdir generator
cp -r "${vips}/bin" "vips"
cp -r "${self.packages.${system}.win}/bin" "site"
zip -9 -r -q "$out/site-bundle.zip" vips/ site/
'';
};
legacyPackages = pkgs;
}
);
}

32
readme.md Normal file
View File

@@ -0,0 +1,32 @@
# mala-zahradka-pro-radost.cz
This directory contains the full source code for <https://mala-zahradka-pro-radost.cz>. The content is mostly written in [CommonMark](https://commonmark.org/) and converted into HTML with `site`, a custom [static site generator](https://en.wikipedia.org/wiki/Static_site_generator) based on [hakyll](https://jaspervdj.be/hakyll/).
The project is structured as follows:
- `content/` actual content of the site (articles, news posts, photos and other files for downloading).
- `content/novinky/` news posts.
- `static/` files used as a part of the layout (styles, scripts, images aside from content…), mostly kept as they are.
- `templates/` building blocks for generating the HTML.
- `site/` source code of the `site` program.
The revision history is tracked using [Git](https://git-scm.com/), with up-to-date version available on <https://code.ogion.cz/tojnar.cz/zahradka>. Pushing into the `main` branch of the repository will automatically update the live version of the website.
## Usage
The `site` program needs to be run in this directory. It supports the following subcommands:
- `site build` produces a `public/` directory with the website to be viewed in a web browser or uploaded to the server. If source content changes, only the pages corresponding to changed files will be updated.
- `site rebuild` cleans the `public/` directory and then runs the `build` subcommand.
- `site watch` starts a web server that will serve the built website and automatically rebuild pages corresponding to changed files. While it is running, you can browse the site on <http://localhost:8000>.
- `site check` checks for broken links in the generated website.
### UNIX
The project uses [Nix](https://nixos.org) package manager to build the `site` program. Run `nix-shell` to enter a shell containing `site` program for controlling the website.
If you have [`direnv`](https://direnv.net/) installed, you can instead run `direnv allow` and it will prepare the correct shell environment automatically every time you enter the directory.
### Windows
On Windows, you can right click `00-site.ps1` in the Explorer and click the “Run with PowerShell” context menu item. The script will download the `site` program and allow you to control it using a GUI.

14
shell.nix Normal file
View File

@@ -0,0 +1,14 @@
# SPDX-FileCopyrightText: 2022 Jan Tojnar
# SPDX-License-Identifier: MIT
let
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
flake-compat = builtins.fetchTarball {
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
sha256 = lock.nodes.flake-compat.locked.narHash;
};
flake = import flake-compat {
src = ./.;
};
in
flake.shellNix

9
site/cabal.project Normal file
View File

@@ -0,0 +1,9 @@
packages: .
source-repository-package
type: git
location: https://gitlab.com/tojnar.cz/hakyll-contrib-tojnar
tag: master
package hakyll-contrib-tojnar
flags: -gd

View File

@@ -0,0 +1,24 @@
cabal-version: 3.4
name: mala-zahradka-pro-radost-cz
version: 0.0.1
executable site
main-is: site.hs
hs-source-dirs: src
build-depends:
base >= 4.8 && < 5,
containers >= 0.5 && < 0.7,
directory >= 1.3 && < 1.4,
extra >= 1.7 && < 1.8,
hakyll >= 4.9 && < 4.16,
hakyll-contrib-tojnar >= 0.2.1 && < 0.3.0,
filepath >= 1.4 && < 1.5,
pandoc >= 2.0 && < 2.18,
process >= 1.6 && < 1.7,
time >= 1.9 && < 1.12,
ghc-options:
-- Required for watch on Windows.
-threaded
-Wall
-fno-warn-tabs

218
site/src/site.hs Normal file
View File

@@ -0,0 +1,218 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverloadedLists #-}
import Control.Monad ((<=<))
import Data.Function ((&))
import Data.List.Extra (dropSuffix)
import Data.Maybe (fromMaybe)
import Data.Time.Format (TimeLocale (..), defaultTimeLocale)
import qualified GHC.IO.Encoding as E
import Hakyll
import Hakyll.Contrib.Tojnar.CleanUrls (cleanRoute, cleanUrlField)
import Hakyll.Contrib.Tojnar.ExternalMetadata (externalMetadataField)
import Hakyll.Contrib.Tojnar.Gallery (figureGroups, implicitFigures)
import Hakyll.Contrib.Tojnar.LinkResolver (resolveLinksTargets, saveUrl)
import Hakyll.Contrib.Tojnar.Menu (menuField)
import Hakyll.Contrib.Tojnar.Thumbnail (ThumbnailGenerator, ThumbnailStyle, ThumbSize, makeThumbnails, sizeDims)
import System.Directory (canonicalizePath, createDirectoryIfMissing)
import System.FilePath (splitDirectories, takeDirectory)
import System.Process (callProcess)
import Text.Pandoc.Extensions (Extension (..), disableExtension)
import Text.Pandoc.Options (readerExtensions)
postPattern :: Pattern
postPattern = "content/novinky/*.md"
pagesPattern :: Pattern
pagesPattern = fromRegex "^content/(.+/)?[^@/][^/]+\\.md$"
menuPattern :: Pattern
menuPattern = fromRegex "^content/(.+/)?@menu\\.md$"
contentSnapshot :: Snapshot
contentSnapshot = "content"
config :: Configuration
config = defaultConfiguration {
destinationDirectory = "public",
previewHost = "0.0.0.0"
}
feedConfiguration :: String -> String -> String -> FeedConfiguration
feedConfiguration rootUri title description =
FeedConfiguration {
feedTitle = title,
feedDescription = description,
feedAuthorName = "",
feedAuthorEmail = "",
feedRoot = rootUri
}
main :: IO ()
main = do
E.setLocaleEncoding E.utf8
hakyllWith config $ do
match "static/styles/*" $ do
route stripStaticDirectory
compile compressCssCompiler
match ("static/scripts/*" .||. "static/images/*") $ do
route stripStaticDirectory
compile copyFileCompiler
-- Match pages that are not posts.
match (pagesPattern .&&. complement postPattern) $ do
route $ stripContentDirectory `composeRoutes` cleanRoute
compile $ do
saveUrl pageContext
markdownCompiler
>>= loadAndApplyTemplate "templates/layout.html" pageContext
-- Match news posts.
match postPattern $ do
route $ stripContentDirectory `composeRoutes` cleanRoute `composeRoutes` rmDateRoute
compile $ do
saveUrl postContext
markdownCompiler
>>= saveSnapshot contentSnapshot
>>= loadAndApplyTemplate "templates/post.html" postContext
>>= loadAndApplyTemplate "templates/layout.html" postContext
-- Create news page.
create ["content/novinky/index.html"] $ do
route stripContentDirectory
compile $ do
let metadataFile = fromFilePath "content/metadata.yaml"
newsTitle <- fromMaybe "" <$> getMetadataField metadataFile "newsTitle"
posts <- recentFirst =<< loadAllSnapshots (postPattern .&&. hasNoVersion) contentSnapshot
let indexContext =
listField "posts" postContext (return posts)
<> bodyField "body"
<> metadataField
<> missingField
let context =
constField "title" newsTitle
<> pageContext
makeItem ""
>>= loadAndApplyTemplate "templates/posts.html" indexContext
>>= loadAndApplyTemplate "templates/layout.html" context
-- Create ATOM feed for news.
create ["content/feed.atom"] $ do
route stripContentDirectory
compile $ do
let metadataFile = fromFilePath "content/metadata.yaml"
title <- fromMaybe "" <$> getMetadataField metadataFile "feedTitle"
description <- fromMaybe "" <$> getMetadataField metadataFile "feedDescription"
rootUri <- fromMaybe "" <$> getMetadataField metadataFile "rootUri"
let feedCtx =
postContext
<> bodyField "description"
posts <- fmap (take 10) . recentFirst =<< loadAllSnapshots (postPattern .&&. hasNoVersion) contentSnapshot
renderAtom (feedConfiguration rootUri title description) feedCtx posts
match menuPattern $ do
compile markdownCompiler
match (fromRegex "^content/" .&&. complement (fromRegex "\\.md$")) $ do
route $ stripContentDirectory `composeRoutes` idRoute
compile copyFileCompiler
match "templates/*" $ compile templateCompiler
-- | Take out the yyyy-mm-dd part from the post URL
rmDateRoute :: Routes
-- gsubRoute uses / as directory separator even on Windows.
rmDateRoute = gsubRoute "/[0-9]{4}-[0-9]{2}-[0-9]{2}-" (const "/")
stripContentDirectory :: Routes
-- gsubRoute uses / as directory separator even on Windows.
stripContentDirectory = gsubRoute "content/" (const "")
stripStaticDirectory :: Routes
-- gsubRoute uses / as directory separator even on Windows.
stripStaticDirectory = gsubRoute "static/" (const "")
pageContext :: Context String
pageContext =
cleanUrlField
<> externalMetadataField
<> menuField
<> defaultContext
-- | Defines a context for posts
postContext :: Context String
postContext = do
postSlugField
<> localizedDateField "date"
<> dateField "isodate" "%Y-%m-%d"
<> pageContext
-- | Field extracting a “slug” from post items route.
postSlugField :: Context a
postSlugField = field "slug" $ \item -> do
url <- fromMaybe "" <$> getRoute (itemIdentifier item)
return (routeToSlug url)
where
-- | Extract the posts slug (the directory name).
-- >>> mrouteToSlug "novinky/spusteni-webu/index.html"
-- "spusteni-webu"
routeToSlug :: FilePath -> String
routeToSlug = last . dropSuffix ["index.html"] . splitDirectories
localizedDateField :: String -> Context a
localizedDateField fieldName =
dateFieldWith timeLocaleCs fieldName (dateFmt timeLocaleCs)
timeLocaleCs :: TimeLocale
timeLocaleCs =
defaultTimeLocale {
months = [
("ledna", "led"),
("února", "úno"),
("března", "bře"),
("dubna", "dub"),
("května", "kvě"),
("června", "čer"),
("července", "čec"),
("srpna", "srp"),
("září", "zář"),
("října", "říj"),
("listopadu", "lis"),
("prosince", "pro")
],
dateFmt = "%e. %B %Y"
}
markdownCompiler :: Compiler (Item String)
markdownCompiler = pandocCompilerWithTransformM readOpts writeOpts filters
where
enabledReaderExtensions =
readerExtensions defaultHakyllReaderOptions
& disableExtension Ext_markdown_in_html_blocks
& disableExtension Ext_implicit_figures
readOpts = defaultHakyllReaderOptions { readerExtensions = enabledReaderExtensions }
writeOpts = defaultHakyllWriterOptions
filters = resolveLinksTargets <=< (makeThumbnails thumbnailer . implicitFigures . figureGroups)
thumbnailer :: ThumbnailGenerator
thumbnailer style source destinations =
mapM_ (\(size, destination) -> generateThumbnail style size source destination) destinations
generateThumbnail :: ThumbnailStyle -> ThumbSize -> FilePath -> FilePath -> IO ()
generateThumbnail style size source destination = do
let (width, height) = sizeDims style size
createDirectoryIfMissing True (takeDirectory destination)
destination' <- canonicalizePath destination
callProcess "vipsthumbnail" [source, "--size", show width ++ "x" ++ show height, "-o", destination']
putStrLn $ " generated thumbnail " ++ destination

1
static/images/icon.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.7 KiB

12
static/scripts/jquery.fancybox.min.js vendored Normal file

File diff suppressed because one or more lines are too long

4
static/scripts/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

16
static/scripts/main.js Normal file
View File

@@ -0,0 +1,16 @@
$(document).ready(function() {
$("[data-lightbox]").fancybox({
loop: false,
caption: function(instance, item) {
const img = this.querySelector('img');
let caption = img.getAttribute('alt') ?? '';
if (item.type === 'image') {
const download = this.getAttribute('data-original') ?? item.src;
caption = (caption.length ? caption + '<br />' : '') + '<a href="' + download + '">Stáhnout obrázek</a>' ;
}
return caption;
}
});
});

7
static/styles/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

223
static/styles/default.css Normal file
View File

@@ -0,0 +1,223 @@
/*
* Globals
*/
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
color: #555;
background: #eeeeec;
}
h1, .h1,
h2, .h2,
h3, .h3,
h4, .h4,
h5, .h5,
h6, .h6 {
margin-top: 0;
font-weight: bold;
color: #333;
}
ul + h4 {
margin-top: 1.5em;
}
td {
vertical-align: top;
padding: .75em;
}
td:first-child {
text-align: right;
}
/*
* Override Bootstrap's default container.
*/
@media (min-width: 1200px) {
.container {
width: 970px;
background: white;
margin-top: 2em;
}
}
/* Nav links */
.blog-nav-item {
position: relative;
display: inline-block;
padding: 10px;
font-weight: 500;
color: #cdddeb;
}
.blog-nav-item:hover,
.blog-nav-item:focus {
color: #fff;
text-decoration: none;
}
.embed-responsive {
margin-bottom: 1em;
}
/* Active state gets a caret at the bottom */
.blog-nav .active {
color: #fff;
}
.blog-nav .active:after {
position: absolute;
bottom: 0;
left: 50%;
width: 0;
height: 0;
margin-left: -5px;
vertical-align: middle;
content: " ";
border-right: 5px solid transparent;
border-bottom: 5px solid;
border-left: 5px solid transparent;
}
/*
* Blog name and description
*/
.main {
margin-right: auto;
margin-left: auto;
padding: 15px;
background-color: #fff;
}
header a {
display: block;
position: relative;
padding-top: 25.471%;
background-color: #000000;
background-image: url(/images/header.jpg);
background-repeat: no-repeat;
background-position: center;
background-size: contain;
margin-bottom: 1em;
}
.header-wrapper {
position: absolute;
bottom: 1rem;
left: 1.5rem;
}
.blog-title {
display: inline-block;
color: white;
text-shadow: 1px 1px 3px black;
margin-bottom: 0;
font-size: 60px;
font-weight: bold;
}
.blog-description {
display: inline-block;
margin-bottom: 0;
font-size: 20px;
color: white;
margin-left: 1rem;
text-shadow: 1px 1px 2px black;
font-weight: bold;
}
/*
* Main column and sidebar layout
*/
.blog-main, .blog-masthead, .blog-sidebar {
font-size: 18px;
line-height: 1.5;
}
/* Sidebar modules for boxing content */
.sidebar-module {
padding: 15px;
margin: 0 -15px 15px;
}
.sidebar-module-inset {
padding: 15px;
background-color: #f5f5f5;
border-radius: 4px;
}
.sidebar-module-inset p:last-child,
.sidebar-module-inset ul:last-child,
.sidebar-module-inset ol:last-child {
margin-bottom: 0;
}
/* Pagination */
.pager {
margin-bottom: 60px;
text-align: left;
}
.pager > li > a {
width: 140px;
padding: 10px 20px;
text-align: center;
border-radius: 30px;
}
/*
* Blog posts
*/
.blog-post {
margin-bottom: 60px;
}
.blog-post-title {
margin-bottom: 5px;
font-size: 40px;
}
.blog-post-meta {
margin-bottom: 20px;
color: #999;
}
/*
* Footer
*/
.blog-footer {
padding: 40px 0;
color: #999;
text-align: center;
background-color: #f9f9f9;
border-top: 1px solid #e5e5e5;
}
.blog-footer p:last-child {
margin-bottom: 0;
}
.figuregroup {
margin: 1em auto;
}
.figuregroup > figure {
display: inline-block;
}
.card-sm {
display: inline-block;
width: 300px;
vertical-align: top;
}
.card-sm img {
margin: auto;
display: block;
}
img {
max-width: 100%;
}

748
static/styles/jquery.fancybox.css vendored Normal file
View File

@@ -0,0 +1,748 @@
@charset "UTF-8";
.fancybox-enabled {
overflow: hidden; }
.fancybox-enabled body {
overflow: visible;
height: 100%; }
.fancybox-is-hidden {
position: absolute;
top: -9999px;
left: -9999px;
visibility: hidden; }
.fancybox-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 99993;
-webkit-tap-highlight-color: transparent;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
-webkit-transform: translateZ(0);
transform: translateZ(0); }
/* Make sure that the first one is on the top */
.fancybox-container ~ .fancybox-container {
z-index: 99992; }
.fancybox-outer,
.fancybox-inner,
.fancybox-bg,
.fancybox-stage {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0; }
.fancybox-outer {
overflow-y: auto;
-webkit-overflow-scrolling: touch; }
.fancybox-bg {
background: #1e1e1e;
opacity: 0;
transition-duration: inherit;
transition-property: opacity;
transition-timing-function: cubic-bezier(0.47, 0, 0.74, 0.71); }
.fancybox-is-open .fancybox-bg {
opacity: 0.87;
transition-timing-function: cubic-bezier(0.22, 0.61, 0.36, 1); }
.fancybox-infobar,
.fancybox-toolbar,
.fancybox-caption-wrap {
position: absolute;
direction: ltr;
z-index: 99997;
opacity: 0;
visibility: hidden;
transition: opacity .25s, visibility 0s linear .25s;
box-sizing: border-box; }
.fancybox-show-infobar .fancybox-infobar,
.fancybox-show-toolbar .fancybox-toolbar,
.fancybox-show-caption .fancybox-caption-wrap {
opacity: 1;
visibility: visible;
transition: opacity .25s, visibility 0s; }
.fancybox-infobar {
top: 0;
left: 50%;
margin-left: -79px; }
.fancybox-infobar__body {
display: inline-block;
width: 70px;
line-height: 44px;
font-size: 13px;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
text-align: center;
color: #ddd;
background-color: rgba(30, 30, 30, 0.7);
pointer-events: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-touch-callout: none;
-webkit-tap-highlight-color: transparent;
-webkit-font-smoothing: subpixel-antialiased; }
.fancybox-toolbar {
top: 0;
right: 0; }
.fancybox-stage {
overflow: hidden;
direction: ltr;
z-index: 99994;
-webkit-transform: translate3d(0, 0, 0); }
.fancybox-slide {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: auto;
outline: none;
white-space: normal;
box-sizing: border-box;
text-align: center;
z-index: 99994;
-webkit-overflow-scrolling: touch;
display: none;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
transition-property: opacity, -webkit-transform;
transition-property: transform, opacity;
transition-property: transform, opacity, -webkit-transform;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d; }
.fancybox-slide::before {
content: '';
display: inline-block;
vertical-align: middle;
height: 100%;
width: 0; }
.fancybox-is-sliding .fancybox-slide,
.fancybox-slide--previous,
.fancybox-slide--current,
.fancybox-slide--next {
display: block; }
.fancybox-slide--image {
overflow: visible; }
.fancybox-slide--image::before {
display: none; }
.fancybox-slide--video .fancybox-content,
.fancybox-slide--video iframe {
background: #000; }
.fancybox-slide--map .fancybox-content,
.fancybox-slide--map iframe {
background: #E5E3DF; }
.fancybox-slide--next {
z-index: 99995; }
.fancybox-slide > div {
display: inline-block;
position: relative;
padding: 24px;
margin: 44px 0 44px;
border-width: 0;
vertical-align: middle;
text-align: left;
background-color: #fff;
overflow: auto;
box-sizing: border-box; }
.fancybox-slide .fancybox-image-wrap {
position: absolute;
top: 0;
left: 0;
margin: 0;
padding: 0;
border: 0;
z-index: 99995;
background: transparent;
cursor: default;
overflow: visible;
-webkit-transform-origin: top left;
-ms-transform-origin: top left;
transform-origin: top left;
background-size: 100% 100%;
background-repeat: no-repeat;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none; }
.fancybox-can-zoomOut .fancybox-image-wrap {
cursor: -webkit-zoom-out;
cursor: zoom-out; }
.fancybox-can-zoomIn .fancybox-image-wrap {
cursor: -webkit-zoom-in;
cursor: zoom-in; }
.fancybox-can-drag .fancybox-image-wrap {
cursor: -webkit-grab;
cursor: grab; }
.fancybox-is-dragging .fancybox-image-wrap {
cursor: -webkit-grabbing;
cursor: grabbing; }
.fancybox-image,
.fancybox-spaceball {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
border: 0;
max-width: none;
max-height: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none; }
.fancybox-spaceball {
z-index: 1; }
.fancybox-slide--iframe .fancybox-content {
padding: 0;
width: 80%;
height: 80%;
max-width: calc(100% - 100px);
max-height: calc(100% - 88px);
overflow: visible;
background: #fff; }
.fancybox-iframe {
display: block;
margin: 0;
padding: 0;
border: 0;
width: 100%;
height: 100%;
background: #fff; }
.fancybox-error {
margin: 0;
padding: 40px;
width: 100%;
max-width: 380px;
background: #fff;
cursor: default; }
.fancybox-error p {
margin: 0;
padding: 0;
color: #444;
font: 16px/20px "Helvetica Neue",Helvetica,Arial,sans-serif; }
.fancybox-close-small {
position: absolute;
top: 0;
right: 0;
width: 44px;
height: 44px;
padding: 0;
margin: 0;
border: 0;
border-radius: 0;
outline: none;
background: transparent;
z-index: 10;
cursor: pointer; }
.fancybox-close-small:after {
content: '×';
position: absolute;
top: 5px;
right: 5px;
width: 30px;
height: 30px;
font: 20px/30px Arial,"Helvetica Neue",Helvetica,sans-serif;
color: #888;
font-weight: 300;
text-align: center;
border-radius: 50%;
border-width: 0;
background: #fff;
transition: background .25s;
box-sizing: border-box;
z-index: 2; }
.fancybox-close-small:focus:after {
outline: 1px dotted #888; }
.fancybox-close-small:hover:after {
color: #555;
background: #eee; }
.fancybox-slide--iframe .fancybox-close-small {
top: 0;
right: -44px; }
.fancybox-slide--iframe .fancybox-close-small:after {
background: transparent;
font-size: 35px;
color: #aaa; }
.fancybox-slide--iframe .fancybox-close-small:hover:after {
color: #fff; }
/* Caption */
.fancybox-caption-wrap {
bottom: 0;
left: 0;
right: 0;
padding: 60px 30px 0 30px;
background: linear-gradient(to bottom, transparent 0%, rgba(0, 0, 0, 0.1) 20%, rgba(0, 0, 0, 0.2) 40%, rgba(0, 0, 0, 0.6) 80%, rgba(0, 0, 0, 0.8) 100%);
pointer-events: none; }
.fancybox-caption {
padding: 30px 0;
border-top: 1px solid rgba(255, 255, 255, 0.4);
font-size: 14px;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
color: #fff;
line-height: 20px;
-webkit-text-size-adjust: none; }
.fancybox-caption a,
.fancybox-caption button,
.fancybox-caption select {
pointer-events: all; }
.fancybox-caption a {
color: #fff;
text-decoration: underline; }
/* Buttons */
.fancybox-button {
display: inline-block;
position: relative;
margin: 0;
padding: 0;
border: 0;
width: 44px;
height: 44px;
line-height: 44px;
text-align: center;
background: transparent;
color: #ddd;
border-radius: 0;
cursor: pointer;
vertical-align: top;
outline: none; }
.fancybox-button[disabled] {
cursor: default;
pointer-events: none; }
.fancybox-infobar__body, .fancybox-button {
background: rgba(30, 30, 30, 0.6); }
.fancybox-button:hover:not([disabled]) {
color: #fff;
background: rgba(0, 0, 0, 0.8); }
.fancybox-button::before,
.fancybox-button::after {
content: '';
pointer-events: none;
position: absolute;
background-color: currentColor;
color: currentColor;
opacity: 0.9;
box-sizing: border-box;
display: inline-block; }
.fancybox-button[disabled]::before,
.fancybox-button[disabled]::after {
opacity: 0.3; }
.fancybox-button--left::after,
.fancybox-button--right::after {
top: 18px;
width: 6px;
height: 6px;
background: transparent;
border-top: solid 2px currentColor;
border-right: solid 2px currentColor; }
.fancybox-button--left::after {
left: 20px;
-webkit-transform: rotate(-135deg);
-ms-transform: rotate(-135deg);
transform: rotate(-135deg); }
.fancybox-button--right::after {
right: 20px;
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg); }
.fancybox-button--left {
border-bottom-left-radius: 5px; }
.fancybox-button--right {
border-bottom-right-radius: 5px; }
.fancybox-button--close::before, .fancybox-button--close::after {
content: '';
display: inline-block;
position: absolute;
height: 2px;
width: 16px;
top: calc(50% - 1px);
left: calc(50% - 8px); }
.fancybox-button--close::before {
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg); }
.fancybox-button--close::after {
-webkit-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
transform: rotate(-45deg); }
/* Navigation arrows */
.fancybox-arrow {
position: absolute;
top: 50%;
margin: -50px 0 0 0;
height: 100px;
width: 54px;
padding: 0;
border: 0;
outline: none;
background: none;
cursor: pointer;
z-index: 99995;
opacity: 0;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
transition: opacity .25s; }
.fancybox-arrow::after {
content: '';
position: absolute;
top: 28px;
width: 44px;
height: 44px;
background-color: rgba(30, 30, 30, 0.8);
background-image: url(data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjRkZGRkZGIiBoZWlnaHQ9IjQ4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSI0OCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4gICAgPHBhdGggZD0iTTAgMGgyNHYyNEgweiIgZmlsbD0ibm9uZSIvPiAgICA8cGF0aCBkPSJNMTIgNGwtMS40MSAxLjQxTDE2LjE3IDExSDR2MmgxMi4xN2wtNS41OCA1LjU5TDEyIDIwbDgtOHoiLz48L3N2Zz4=);
background-repeat: no-repeat;
background-position: center center;
background-size: 24px 24px; }
.fancybox-arrow--right {
right: 0; }
.fancybox-arrow--left {
left: 0;
-webkit-transform: scaleX(-1);
-ms-transform: scaleX(-1);
transform: scaleX(-1); }
.fancybox-arrow--right::after,
.fancybox-arrow--left::after {
left: 0; }
.fancybox-show-nav .fancybox-arrow {
opacity: 0.6; }
.fancybox-show-nav .fancybox-arrow[disabled] {
opacity: 0.3; }
/* Loading indicator */
.fancybox-slide > .fancybox-loading {
border: 6px solid rgba(100, 100, 100, 0.4);
border-top: 6px solid rgba(255, 255, 255, 0.6);
border-radius: 100%;
height: 50px;
width: 50px;
-webkit-animation: fancybox-rotate .8s infinite linear;
animation: fancybox-rotate .8s infinite linear;
background: transparent;
position: absolute;
top: 50%;
left: 50%;
margin-top: -25px;
margin-left: -25px;
z-index: 99999; }
@-webkit-keyframes fancybox-rotate {
from {
-webkit-transform: rotate(0deg);
transform: rotate(0deg); }
to {
-webkit-transform: rotate(359deg);
transform: rotate(359deg); } }
@keyframes fancybox-rotate {
from {
-webkit-transform: rotate(0deg);
transform: rotate(0deg); }
to {
-webkit-transform: rotate(359deg);
transform: rotate(359deg); } }
/* Transition effects */
.fancybox-animated {
transition-timing-function: cubic-bezier(0, 0, 0.25, 1); }
/* transitionEffect: slide */
.fancybox-fx-slide.fancybox-slide--previous {
-webkit-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
opacity: 0; }
.fancybox-fx-slide.fancybox-slide--next {
-webkit-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
opacity: 0; }
.fancybox-fx-slide.fancybox-slide--current {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
opacity: 1; }
/* transitionEffect: fade */
.fancybox-fx-fade.fancybox-slide--previous,
.fancybox-fx-fade.fancybox-slide--next {
opacity: 0;
transition-timing-function: cubic-bezier(0.19, 1, 0.22, 1); }
.fancybox-fx-fade.fancybox-slide--current {
opacity: 1; }
/* transitionEffect: zoom-in-out */
.fancybox-fx-zoom-in-out.fancybox-slide--previous {
-webkit-transform: scale3d(1.5, 1.5, 1.5);
transform: scale3d(1.5, 1.5, 1.5);
opacity: 0; }
.fancybox-fx-zoom-in-out.fancybox-slide--next {
-webkit-transform: scale3d(0.5, 0.5, 0.5);
transform: scale3d(0.5, 0.5, 0.5);
opacity: 0; }
.fancybox-fx-zoom-in-out.fancybox-slide--current {
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
opacity: 1; }
/* transitionEffect: rotate */
.fancybox-fx-rotate.fancybox-slide--previous {
-webkit-transform: rotate(-360deg);
-ms-transform: rotate(-360deg);
transform: rotate(-360deg);
opacity: 0; }
.fancybox-fx-rotate.fancybox-slide--next {
-webkit-transform: rotate(360deg);
-ms-transform: rotate(360deg);
transform: rotate(360deg);
opacity: 0; }
.fancybox-fx-rotate.fancybox-slide--current {
-webkit-transform: rotate(0deg);
-ms-transform: rotate(0deg);
transform: rotate(0deg);
opacity: 1; }
/* transitionEffect: circular */
.fancybox-fx-circular.fancybox-slide--previous {
-webkit-transform: scale3d(0, 0, 0) translate3d(-100%, 0, 0);
transform: scale3d(0, 0, 0) translate3d(-100%, 0, 0);
opacity: 0; }
.fancybox-fx-circular.fancybox-slide--next {
-webkit-transform: scale3d(0, 0, 0) translate3d(100%, 0, 0);
transform: scale3d(0, 0, 0) translate3d(100%, 0, 0);
opacity: 0; }
.fancybox-fx-circular.fancybox-slide--current {
-webkit-transform: scale3d(1, 1, 1) translate3d(0, 0, 0);
transform: scale3d(1, 1, 1) translate3d(0, 0, 0);
opacity: 1; }
/* transitionEffect: tube */
.fancybox-fx-tube.fancybox-slide--previous {
-webkit-transform: translate3d(-100%, 0, 0) scale(0.1) skew(-10deg);
transform: translate3d(-100%, 0, 0) scale(0.1) skew(-10deg); }
.fancybox-fx-tube.fancybox-slide--next {
-webkit-transform: translate3d(100%, 0, 0) scale(0.1) skew(10deg);
transform: translate3d(100%, 0, 0) scale(0.1) skew(10deg); }
.fancybox-fx-tube.fancybox-slide--current {
-webkit-transform: translate3d(0, 0, 0) scale(1);
transform: translate3d(0, 0, 0) scale(1); }
/* Styling for Small-Screen Devices */
@media all and (max-width: 800px) {
.fancybox-infobar {
left: 0;
margin-left: 0; }
.fancybox-button--left,
.fancybox-button--right {
display: none !important; }
.fancybox-caption {
padding: 20px 0;
margin: 0; } }
/* Fullscreen */
.fancybox-button--fullscreen::before {
width: 15px;
height: 11px;
left: calc(50% - 7px);
top: calc(50% - 6px);
border: 2px solid;
background: none; }
/* Slideshow button */
.fancybox-button--play::before,
.fancybox-button--pause::before {
top: calc(50% - 6px);
left: calc(50% - 4px);
background: transparent; }
.fancybox-button--play::before {
width: 0;
height: 0;
border-top: 6px inset transparent;
border-bottom: 6px inset transparent;
border-left: 10px solid;
border-radius: 1px; }
.fancybox-button--pause::before {
width: 7px;
height: 11px;
border-style: solid;
border-width: 0 2px 0 2px; }
/* Thumbs */
.fancybox-thumbs {
display: none; }
.fancybox-button--thumbs {
display: none; }
@media all and (min-width: 800px) {
.fancybox-button--thumbs {
display: inline-block; }
.fancybox-button--thumbs span {
font-size: 23px; }
.fancybox-button--thumbs::before {
width: 3px;
height: 3px;
top: calc(50% - 2px);
left: calc(50% - 2px);
box-shadow: 0 -4px 0, -4px -4px 0, 4px -4px 0, 0 0 0 32px inset, -4px 0 0, 4px 0 0, 0 4px 0, -4px 4px 0, 4px 4px 0; }
.fancybox-thumbs {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: auto;
width: 220px;
margin: 0;
padding: 5px 5px 0 0;
background: #fff;
word-break: normal;
-webkit-tap-highlight-color: transparent;
-webkit-overflow-scrolling: touch;
-ms-overflow-style: -ms-autohiding-scrollbar;
box-sizing: border-box;
z-index: 99995; }
.fancybox-show-thumbs .fancybox-thumbs {
display: block; }
.fancybox-show-thumbs .fancybox-inner {
right: 220px; }
.fancybox-thumbs > ul {
list-style: none;
position: absolute;
position: relative;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow-x: hidden;
overflow-y: auto;
font-size: 0; }
.fancybox-thumbs > ul > li {
float: left;
overflow: hidden;
max-width: 50%;
padding: 0;
margin: 0;
width: 105px;
height: 75px;
position: relative;
cursor: pointer;
outline: none;
border: 5px solid transparent;
border-top-width: 0;
border-right-width: 0;
-webkit-tap-highlight-color: transparent;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
box-sizing: border-box; }
li.fancybox-thumbs-loading {
background: rgba(0, 0, 0, 0.1); }
.fancybox-thumbs > ul > li > img {
position: absolute;
top: 0;
left: 0;
min-width: 100%;
min-height: 100%;
max-width: none;
max-height: none;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none; }
.fancybox-thumbs > ul > li:before {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
border-radius: 2px;
border: 4px solid #4ea7f9;
z-index: 99991;
opacity: 0;
transition: all 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94); }
.fancybox-thumbs > ul > li.fancybox-thumbs-active:before {
opacity: 1; } }

52
templates/layout.html Normal file
View File

@@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
$if(robots)$<meta name="robots" content="$robots$">$endif$
<link rel="icon" href="/images/icon.svg" type="image/svg+xml">
<title>$siteTitle$ ⬩ $title$</title>
<link href="/styles/bootstrap.min.css" rel="stylesheet">
<link href="/styles/default.css" rel="stylesheet">
<link href="/styles/jquery.fancybox.css" rel="stylesheet">
<link href="/feed.atom" rel="alternate" type="application/atom+xml">
</head>
<body>
<div class="container main">
<header>
<a href="/">
<div class="header-wrapper">
<h1 class="blog-title">$siteTitle$</h1>
<p class="lead blog-description">$siteDescription$</p>
</div>
</a>
</header>
<div class="row">
<div class="col-sm-8 blog-main">
<h2>$title$</h2>
$body$
</div>
<div class="col-sm-4 col-sm-offset-1 blog-sidebar">
<div class="sidebar-module">
$menu$
</div>
</div>
</div>
</div>
<script src="/scripts/jquery.min.js"></script>
<script src="/scripts/jquery.fancybox.min.js"></script>
<script src="/scripts/main.js"></script>
</body>
</html>

4
templates/post.html Normal file
View File

@@ -0,0 +1,4 @@
<article class="blog-post">
<p class="blog-post-meta">$date$</p>
$body$
</article>

9
templates/posts.html Normal file
View File

@@ -0,0 +1,9 @@
<div class="news">
$for(posts)$
<article class="blog-post">
<h3 class="blog-post-title" id="post-$slug$"><a href="$url$">$title$</a></h3>
<p class="blog-post-meta">$date$</p>
$body$
</article>
$endfor$
</div>