mirror of
https://gitlab.com/upRootNutrition/dotfiles.git
synced 2025-12-06 21:17:14 -06:00
chore: init
This commit is contained in:
commit
1b2c1ea359
891 changed files with 37053 additions and 0 deletions
1
templates/haskell/.envrc
Executable file
1
templates/haskell/.envrc
Executable file
|
|
@ -0,0 +1 @@
|
|||
use flake
|
||||
4
templates/haskell/.gitignore
vendored
Executable file
4
templates/haskell/.gitignore
vendored
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
.direnv
|
||||
.pre-commit-config.yaml
|
||||
.vscode
|
||||
dist-newstyle
|
||||
57
templates/haskell/flake.nix
Executable file
57
templates/haskell/flake.nix
Executable file
|
|
@ -0,0 +1,57 @@
|
|||
{
|
||||
description = "Haskell Environment";
|
||||
|
||||
inputs = {
|
||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
treefmt-nix.url = "github:numtide/treefmt-nix";
|
||||
};
|
||||
|
||||
outputs =
|
||||
inputs:
|
||||
inputs.flake-parts.lib.mkFlake { inherit inputs; } {
|
||||
imports = [ inputs.treefmt-nix.flakeModule ];
|
||||
|
||||
perSystem =
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
hp = pkgs.haskellPackages;
|
||||
project = hp.callCabal2nix "project" ./. { };
|
||||
in
|
||||
{
|
||||
devShells.default = hp.shellFor {
|
||||
nativeBuildInputs = builtins.attrValues {
|
||||
inherit (pkgs)
|
||||
nil
|
||||
stylish-haskell
|
||||
ghc
|
||||
;
|
||||
inherit (hp)
|
||||
cabal-install
|
||||
cabal-gild
|
||||
haskell-language-server
|
||||
;
|
||||
};
|
||||
packages = _: [ project ];
|
||||
};
|
||||
|
||||
packages.default = project;
|
||||
|
||||
treefmt = {
|
||||
programs = {
|
||||
cabal-fmt.enable = true;
|
||||
deadnix.enable = true;
|
||||
hlint.enable = true;
|
||||
nixfmt.enable = true;
|
||||
ormolu.enable = true;
|
||||
statix.enable = true;
|
||||
typstyle.enable = true;
|
||||
yamlfmt.enable = true;
|
||||
};
|
||||
projectRootFile = "flake.nix";
|
||||
};
|
||||
};
|
||||
|
||||
systems = [ "x86_64-linux" ];
|
||||
};
|
||||
}
|
||||
12
templates/haskell/fourmolu.yaml
Executable file
12
templates/haskell/fourmolu.yaml
Executable file
|
|
@ -0,0 +1,12 @@
|
|||
indentation: 2
|
||||
comma-style: trailing
|
||||
import-export-style: diff-friendly
|
||||
respectful: false
|
||||
column-limit: 80
|
||||
function-arrows: trailing
|
||||
haddock-style: single-line
|
||||
let-style: inline
|
||||
in-style: right-align
|
||||
unicode: never
|
||||
pragma-style: leading
|
||||
newlines-between-decls: 1
|
||||
2
templates/haskell/justfile
Executable file
2
templates/haskell/justfile
Executable file
|
|
@ -0,0 +1,2 @@
|
|||
cabal:
|
||||
cabal clean ; cabal run
|
||||
10
templates/haskell/project.cabal
Executable file
10
templates/haskell/project.cabal
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
cabal-version: 3.0
|
||||
name: project
|
||||
version: 0.1.0.0
|
||||
|
||||
executable main
|
||||
main-is: Main.hs
|
||||
build-depends:
|
||||
, base
|
||||
default-language: Haskell2010
|
||||
hs-source-dirs: src
|
||||
4
templates/haskell/src/Main.hs
Executable file
4
templates/haskell/src/Main.hs
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
module Main where
|
||||
|
||||
main :: IO ()
|
||||
main = putStrLn "Hello, World!"
|
||||
1
templates/typst/.envrc
Executable file
1
templates/typst/.envrc
Executable file
|
|
@ -0,0 +1 @@
|
|||
use flake
|
||||
4
templates/typst/.gitignore
vendored
Executable file
4
templates/typst/.gitignore
vendored
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
.direnv
|
||||
.pre-commit-config.yaml
|
||||
.vscode
|
||||
*.pdf
|
||||
27
templates/typst/flake.nix
Executable file
27
templates/typst/flake.nix
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
description = "Typst Environment";
|
||||
|
||||
inputs = {
|
||||
devshell.url = "github:numtide/devshell";
|
||||
flake-root.url = "github:srid/flake-root";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
pre-commit-hooks-nix.url = "github:cachix/pre-commit-hooks.nix";
|
||||
};
|
||||
|
||||
outputs =
|
||||
inputs@{
|
||||
nixpkgs,
|
||||
flake-parts,
|
||||
...
|
||||
}:
|
||||
flake-parts.lib.mkFlake { inherit inputs; } {
|
||||
imports = [
|
||||
inputs.devshell.flakeModule
|
||||
inputs.flake-root.flakeModule
|
||||
inputs.pre-commit-hooks-nix.flakeModule
|
||||
./parts
|
||||
];
|
||||
|
||||
systems = nixpkgs.lib.systems.flakeExposed;
|
||||
};
|
||||
}
|
||||
26
templates/typst/parts/config/devshells.nix
Executable file
26
templates/typst/parts/config/devshells.nix
Executable file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
{
|
||||
devShells = {
|
||||
default = pkgs.mkShell {
|
||||
packages = builtins.attrValues {
|
||||
inherit (pkgs)
|
||||
just
|
||||
nil
|
||||
typst
|
||||
tinymist
|
||||
typstyle
|
||||
yamlfmt
|
||||
nixfmt-rfc-style
|
||||
;
|
||||
# inherit (pkgs.nodePackages)
|
||||
# "@commitlint/config-conventional"
|
||||
# ;
|
||||
};
|
||||
};
|
||||
shellHook = "${config.pre-commit.installationScript}";
|
||||
};
|
||||
}
|
||||
7
templates/typst/parts/config/pre-commit.nix
Executable file
7
templates/typst/parts/config/pre-commit.nix
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
pre-commit.settings.hooks = {
|
||||
nixfmt.enable = true;
|
||||
commitizen.enable = true;
|
||||
statix.enable = true;
|
||||
};
|
||||
}
|
||||
15
templates/typst/parts/default.nix
Executable file
15
templates/typst/parts/default.nix
Executable file
|
|
@ -0,0 +1,15 @@
|
|||
let
|
||||
configPath = ./config;
|
||||
|
||||
devshellImports =
|
||||
let
|
||||
files = builtins.attrNames (builtins.readDir configPath);
|
||||
in
|
||||
map (name: configPath + "/${name}") (
|
||||
builtins.filter (name: builtins.match ".*\\.nix$" name != null) files
|
||||
);
|
||||
in
|
||||
{
|
||||
imports = devshellImports;
|
||||
|
||||
}
|
||||
8
templates/typst/src/refs.yml
Executable file
8
templates/typst/src/refs.yml
Executable file
|
|
@ -0,0 +1,8 @@
|
|||
citizen:
|
||||
author: John Zerilli
|
||||
chapter: 3
|
||||
date: 2021
|
||||
isbn: 9780262044813
|
||||
publisher: The MIT Press
|
||||
title: A Citizen's Guide To Artificial Intelligence
|
||||
type: Book
|
||||
63
templates/typst/src/template.typ
Executable file
63
templates/typst/src/template.typ
Executable file
|
|
@ -0,0 +1,63 @@
|
|||
// Catppuccin Latte
|
||||
|
||||
#let catppuccinLatteRosewater = rgb("#dc8a78")
|
||||
#let catppuccinLatteFlamingo = rgb("#dd7878")
|
||||
#let catppuccinLattePink = rgb("#ea76cb")
|
||||
#let catppuccinLatteMauve = rgb("#8839ef")
|
||||
#let catppuccinLatteRed = rgb("#d20f39")
|
||||
#let catppuccinLatteMaroon = rgb("#e64553")
|
||||
#let catppuccinLattePeach = rgb("#fe640b")
|
||||
#let catppuccinLatteYellow = rgb("#df8e1d")
|
||||
#let catppuccinLatteGreen = rgb("#40a02b")
|
||||
#let catppuccinLatteTeal = rgb("#179299")
|
||||
#let catppuccinLatteSky = rgb("#04a5e5")
|
||||
#let catppuccinLatteSapphire = rgb("#209fb5")
|
||||
#let catppuccinLatteBlue = rgb("#1e66f5")
|
||||
#let catppuccinLatteLavender = rgb("#7287fd")
|
||||
#let catppuccinLatteText = rgb("#4c4f69")
|
||||
#let catppuccinLatteSubtext1 = rgb("#5c5f77")
|
||||
#let catppuccinLatteSubtext0 = rgb("#6c6f85")
|
||||
#let catppuccinLatteOverlay2 = rgb("#7c7f93")
|
||||
#let catppuccinLatteOverlay1 = rgb("#8c8fa1")
|
||||
#let catppuccinLatteOverlay0 = rgb("#9ca0b0")
|
||||
#let catppuccinLatteSurface2 = rgb("#acb0be")
|
||||
#let catppuccinLatteSurface1 = rgb("#bcc0cc")
|
||||
#let catppuccinLatteSurface0 = rgb("#ccd0da")
|
||||
#let catppuccinLatteBase = rgb("#eff1f5")
|
||||
#let catppuccinLatteMantle = rgb("#e6e9ef")
|
||||
#let catppuccinLatteCrust = rgb("#dce0e8")
|
||||
|
||||
// General:
|
||||
|
||||
#let project(author: (:), title: (), body) = {
|
||||
show figure.caption: it => it.body
|
||||
|
||||
set quote(attribution: "content", block: true)
|
||||
|
||||
set document(author: author.firstName + " " + author.lastName, title: title)
|
||||
|
||||
set text(fill: catppuccinLatteText, font: ("New Computer Modern"), lang: "en")
|
||||
|
||||
let title = {
|
||||
align(center)[
|
||||
#block[
|
||||
#text(size: 25pt, weight: "medium")[#title]
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
let name = {
|
||||
align(
|
||||
center,
|
||||
)[
|
||||
#block[
|
||||
#text(size: 12pt, weight: "regular")[#author.firstName #author.lastName]
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
title
|
||||
name
|
||||
body
|
||||
}
|
||||
|
||||
12
templates/typst/src/typst.typ
Executable file
12
templates/typst/src/typst.typ
Executable file
|
|
@ -0,0 +1,12 @@
|
|||
#import "template.typ": *
|
||||
|
||||
#show: project.with(author: (firstName: "First", lastName: "Last"), title: "Title")
|
||||
|
||||
Test
|
||||
|
||||
#quote(
|
||||
attribution: <citizen>,
|
||||
)[ Fact is, you can't satisfy both calibration and error rate balance if the base
|
||||
rates differ... ]
|
||||
|
||||
#bibliography("refs.yml", style: "ieee")
|
||||
1
templates/website/.envrc
Executable file
1
templates/website/.envrc
Executable file
|
|
@ -0,0 +1 @@
|
|||
use flake
|
||||
1
templates/website/.gitignore
vendored
Executable file
1
templates/website/.gitignore
vendored
Executable file
|
|
@ -0,0 +1 @@
|
|||
.direnv
|
||||
1
templates/website/backend/.gitignore
vendored
Executable file
1
templates/website/backend/.gitignore
vendored
Executable file
|
|
@ -0,0 +1 @@
|
|||
/dist-newstyle
|
||||
12
templates/website/backend/backend.cabal
Executable file
12
templates/website/backend/backend.cabal
Executable file
|
|
@ -0,0 +1,12 @@
|
|||
cabal-version: 3.0
|
||||
name: backend
|
||||
version: 0.1.0.0
|
||||
|
||||
executable main
|
||||
main-is: Main.hs
|
||||
build-depends:
|
||||
, base
|
||||
, scotty
|
||||
, wai-cors
|
||||
default-language: Haskell2010
|
||||
hs-source-dirs: src
|
||||
4
templates/website/backend/src/Main.hs
Executable file
4
templates/website/backend/src/Main.hs
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
module Main where
|
||||
|
||||
main :: IO ()
|
||||
main = putStrLn "Hello, World!"
|
||||
147
templates/website/flake.lock
generated
Executable file
147
templates/website/flake.lock
generated
Executable file
|
|
@ -0,0 +1,147 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1730504689,
|
||||
"narHash": "sha256-hgmguH29K2fvs9szpq2r3pz2/8cJd2LPS+b4tfNFCwE=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "506278e768c2a08bec68eb62932193e341f55c90",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "flake-parts",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"pre-commit-hooks-nix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"haskell-flake": {
|
||||
"locked": {
|
||||
"lastModified": 1749105244,
|
||||
"narHash": "sha256-gV/B1PWOwpLjy2OCHMS/fJ8GItMRoflW/g3kXB8/skg=",
|
||||
"owner": "srid",
|
||||
"repo": "haskell-flake",
|
||||
"rev": "af2ba40f23824556b12d1cdfdf392e263876d644",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "srid",
|
||||
"repo": "haskell-flake",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1750386251,
|
||||
"narHash": "sha256-1ovgdmuDYVo5OUC5NzdF+V4zx2uT8RtsgZahxidBTyw=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "076e8c6678d8c54204abcb4b1b14c366835a58bb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1730504152,
|
||||
"narHash": "sha256-lXvH/vOfb4aGYyvFmZK/HlsNsr/0CVWlwYvo2rxJk3s=",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/cc2f28000298e1269cea6612cd06ec9979dd5d7f.tar.gz"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/cc2f28000298e1269cea6612cd06ec9979dd5d7f.tar.gz"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1730768919,
|
||||
"narHash": "sha256-8AKquNnnSaJRXZxc5YmF/WfmxiHX6MMZZasRP6RRQkE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "a04d33c0c3f1a59a2c1cb0c6e34cd24500e5a1dc",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks-nix": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1749636823,
|
||||
"narHash": "sha256-WUaIlOlPLyPgz9be7fqWJA5iG6rHcGRtLERSCfUDne4=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "623c56286de5a3193aa38891a6991b28f9bab056",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-parts": "flake-parts",
|
||||
"haskell-flake": "haskell-flake",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"pre-commit-hooks-nix": "pre-commit-hooks-nix"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
97
templates/website/flake.nix
Executable file
97
templates/website/flake.nix
Executable file
|
|
@ -0,0 +1,97 @@
|
|||
{
|
||||
description = "Website Environment";
|
||||
|
||||
inputs = {
|
||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.05";
|
||||
treefmt-nix.url = "github:numtide/treefmt-nix";
|
||||
mkElmDerivation.url = "github:jeslie0/mkElmDerivation";
|
||||
};
|
||||
|
||||
outputs =
|
||||
inputs:
|
||||
inputs.flake-parts.lib.mkFlake { inherit inputs; } {
|
||||
imports = [ inputs.treefmt-nix.flakeModule ];
|
||||
|
||||
perSystem =
|
||||
{ pkgs, lib, ... }:
|
||||
let
|
||||
hp = pkgs.haskellPackages;
|
||||
backend = hp.callCabal2nix "backend" ./backend { };
|
||||
in
|
||||
{
|
||||
devShells.default = hp.shellFor {
|
||||
nativeBuildInputs = builtins.attrValues {
|
||||
inherit (pkgs)
|
||||
nil
|
||||
stylish-haskell
|
||||
ghc
|
||||
vscode-langservers-extracted
|
||||
nixfmt
|
||||
;
|
||||
inherit (hp)
|
||||
cabal-install
|
||||
cabal-gild
|
||||
haskell-language-server
|
||||
hlint
|
||||
fourmolu
|
||||
;
|
||||
inherit (inputs.nixpkgs-stable.legacyPackages.${pkgs.system}.elmPackages)
|
||||
elm
|
||||
elm-format
|
||||
elm-land
|
||||
elm-language-server
|
||||
elm-review
|
||||
elm-test
|
||||
;
|
||||
};
|
||||
packages = _: [ backend ];
|
||||
};
|
||||
|
||||
packages =
|
||||
let
|
||||
pkgs' = pkgs.extend inputs.mkElmDerivation.overlays.mkElmDerivation;
|
||||
in
|
||||
{
|
||||
websiteBackend = backend;
|
||||
|
||||
websiteFrontend = pkgs'.mkElmDerivation {
|
||||
name = "website";
|
||||
src = ./frontend;
|
||||
nativeBuildInputs = builtins.attrValues {
|
||||
inherit (inputs.nixpkgs-stable.legacyPackages.${pkgs.system}.elmPackages)
|
||||
elm
|
||||
elm-land
|
||||
;
|
||||
};
|
||||
|
||||
buildPhase = ''
|
||||
${lib.getExe pkgs'.elm-land} build
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p "$out"
|
||||
cp -r dist/* "$out/"
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
treefmt = {
|
||||
programs = {
|
||||
cabal-fmt.enable = true;
|
||||
deadnix.enable = true;
|
||||
hlint.enable = true;
|
||||
nixfmt.enable = true;
|
||||
fourmolu.enable = true;
|
||||
statix.enable = true;
|
||||
typstyle.enable = true;
|
||||
yamlfmt.enable = true;
|
||||
};
|
||||
backendRootFile = "flake.nix";
|
||||
};
|
||||
};
|
||||
|
||||
systems = [ "x86_64-linux" ];
|
||||
};
|
||||
}
|
||||
7
templates/website/frontend/.gitignore
vendored
Executable file
7
templates/website/frontend/.gitignore
vendored
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
/dist
|
||||
/.elm-land
|
||||
/.env
|
||||
/elm-stuff
|
||||
/node_modules
|
||||
.DS_Store
|
||||
*.pem
|
||||
96
templates/website/frontend/elm-land.json
Executable file
96
templates/website/frontend/elm-land.json
Executable file
|
|
@ -0,0 +1,96 @@
|
|||
{
|
||||
"app": {
|
||||
"elm": {
|
||||
"development": { "debugger": false },
|
||||
"production": { "debugger": false }
|
||||
},
|
||||
"env": [],
|
||||
"html": {
|
||||
"attributes": {
|
||||
"html": { "lang": "en" },
|
||||
"head": {}
|
||||
},
|
||||
"title": "website",
|
||||
"meta": [
|
||||
{ "charset": "UTF-8" },
|
||||
{ "http-equiv": "X-UA-Compatible", "content": "IE=edge" },
|
||||
{
|
||||
"name": "viewport",
|
||||
"content": "width=device-width, initial-scale=1.0"
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"content": "website description"
|
||||
},
|
||||
{
|
||||
"property": "og:title",
|
||||
"content": "website title"
|
||||
},
|
||||
{
|
||||
"property": "og:description",
|
||||
"content": "website description"
|
||||
},
|
||||
{
|
||||
"property": "og:image",
|
||||
"content": "card path"
|
||||
},
|
||||
{
|
||||
"property": "og:image:alt",
|
||||
"content": ""
|
||||
},
|
||||
{
|
||||
"property": "og:image:type",
|
||||
"content": "image/png"
|
||||
},
|
||||
{
|
||||
"property": "og:url",
|
||||
"content": "card path"
|
||||
},
|
||||
{
|
||||
"property": "og:type",
|
||||
"content": "website"
|
||||
},
|
||||
{
|
||||
"property": "og:site_name",
|
||||
"content": "website name"
|
||||
},
|
||||
{
|
||||
"name": "twitter:card",
|
||||
"content": "summary_large_image"
|
||||
},
|
||||
{
|
||||
"name": "twitter:title",
|
||||
"content": "website name"
|
||||
},
|
||||
{
|
||||
"name": "twitter:description",
|
||||
"content": "website description"
|
||||
},
|
||||
{
|
||||
"name": "twitter:image",
|
||||
"content": "card path"
|
||||
},
|
||||
{
|
||||
"name": "twitter:site",
|
||||
"content": "twitter @"
|
||||
},
|
||||
{
|
||||
"name": "twitter:creator",
|
||||
"content": "twitter @"
|
||||
}
|
||||
],
|
||||
"link": [
|
||||
{ "rel": "icon", "type": "png", "href": "/assets/favicon.png" },
|
||||
{ "rel": "stylesheet", "href": "/styles.css" },
|
||||
{
|
||||
"rel": "stylesheet",
|
||||
"href": "https://fonts.googleapis.com/css2?family=Montez&display=swap"
|
||||
}
|
||||
],
|
||||
"script": []
|
||||
},
|
||||
"router": {
|
||||
"useHashRouting": false
|
||||
}
|
||||
}
|
||||
}
|
||||
53
templates/website/frontend/elm.json
Executable file
53
templates/website/frontend/elm.json
Executable file
|
|
@ -0,0 +1,53 @@
|
|||
{
|
||||
"type": "application",
|
||||
"source-directories": [
|
||||
"src",
|
||||
".elm-land/src"
|
||||
],
|
||||
"elm-version": "0.19.1",
|
||||
"dependencies": {
|
||||
"direct": {
|
||||
"dillonkearns/elm-markdown": "7.0.1",
|
||||
"elm/browser": "1.0.2",
|
||||
"elm/core": "1.0.5",
|
||||
"elm/html": "1.0.0",
|
||||
"elm/json": "1.1.3",
|
||||
"elm/svg": "1.0.1",
|
||||
"elm/url": "1.0.0",
|
||||
"elm-community/list-extra": "8.7.0",
|
||||
"elm-community/maybe-extra": "5.3.0",
|
||||
"gampleman/elm-visualization": "2.4.2",
|
||||
"hecrj/html-parser": "2.4.0",
|
||||
"mdgriffith/elm-ui": "1.1.8"
|
||||
},
|
||||
"indirect": {
|
||||
"avh4/elm-color": "1.0.0",
|
||||
"elm/parser": "1.1.0",
|
||||
"elm/random": "1.0.0",
|
||||
"elm/regex": "1.0.0",
|
||||
"elm/time": "1.0.0",
|
||||
"elm/virtual-dom": "1.0.3",
|
||||
"elmcraft/core-extra": "2.2.0",
|
||||
"folkertdev/elm-deque": "3.0.1",
|
||||
"folkertdev/one-true-path-experiment": "6.0.1",
|
||||
"folkertdev/svg-path-lowlevel": "4.0.1",
|
||||
"gampleman/elm-rosetree": "1.1.0",
|
||||
"ianmackenzie/elm-1d-parameter": "1.0.1",
|
||||
"ianmackenzie/elm-float-extra": "1.1.0",
|
||||
"ianmackenzie/elm-geometry": "3.11.0",
|
||||
"ianmackenzie/elm-interval": "3.1.0",
|
||||
"ianmackenzie/elm-triangular-mesh": "1.1.0",
|
||||
"ianmackenzie/elm-units": "2.10.0",
|
||||
"ianmackenzie/elm-units-interval": "3.2.0",
|
||||
"ianmackenzie/elm-units-prefixed": "2.8.0",
|
||||
"justinmimbs/date": "4.1.0",
|
||||
"justinmimbs/time-extra": "1.2.0",
|
||||
"rtfeldman/elm-hex": "1.0.0",
|
||||
"ryan-haskell/date-format": "1.0.0"
|
||||
}
|
||||
},
|
||||
"test-dependencies": {
|
||||
"direct": {},
|
||||
"indirect": {}
|
||||
}
|
||||
}
|
||||
10
templates/website/frontend/src/Config/Helpers/Response.elm
Executable file
10
templates/website/frontend/src/Config/Helpers/Response.elm
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
module Config.Helpers.Response exposing (..)
|
||||
|
||||
import Config.Style.Colour.Helpers exposing (..)
|
||||
import Element as E exposing (..)
|
||||
import Element.Background as B exposing (color)
|
||||
import Html.Attributes exposing (style)
|
||||
|
||||
|
||||
dummy =
|
||||
[]
|
||||
16
templates/website/frontend/src/Config/Helpers/Viewport.elm
Executable file
16
templates/website/frontend/src/Config/Helpers/Viewport.elm
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
module Config.Helpers.Viewport exposing
|
||||
( Msg
|
||||
, resetViewport
|
||||
)
|
||||
|
||||
import Browser.Dom as Dom exposing (setViewport)
|
||||
import Task exposing (attempt)
|
||||
|
||||
|
||||
type Msg
|
||||
= NoOp
|
||||
|
||||
|
||||
resetViewport : Cmd Msg
|
||||
resetViewport =
|
||||
Task.attempt (\_ -> NoOp) (Dom.setViewportOf "scroll-container" 0 0)
|
||||
88
templates/website/frontend/src/Config/Style/Colour/Helpers.elm
Executable file
88
templates/website/frontend/src/Config/Style/Colour/Helpers.elm
Executable file
|
|
@ -0,0 +1,88 @@
|
|||
module Config.Style.Colour.Helpers exposing
|
||||
( darkColourTheme
|
||||
, getColour
|
||||
, getColourScheme
|
||||
, getScheme
|
||||
, lightColourTheme
|
||||
)
|
||||
|
||||
import Config.Style.Colour.Types
|
||||
exposing
|
||||
( ColourScheme
|
||||
, Theme(..)
|
||||
)
|
||||
import Element as E exposing (..)
|
||||
import Element.Font as F exposing (color)
|
||||
import Shared
|
||||
|
||||
|
||||
lightColourTheme : ColourScheme
|
||||
lightColourTheme =
|
||||
{ -- Core brand colors
|
||||
primary = rgb255 92 128 105 -- ll green
|
||||
, secondary = rgb255 92 128 105 -- ll green
|
||||
|
||||
-- Surface colorsc
|
||||
, background = rgb255 192 228 205 --3lite green--
|
||||
, surface = rgb255 239 255 252 -- white green
|
||||
, surfaceVariant = rgb255 229 255 242 -- dwhite green
|
||||
|
||||
-- Text colors
|
||||
, onPrimary = rgb255 255 255 255
|
||||
, onSecondary = rgb255 255 255 255
|
||||
, onBackground = rgb255 72 108 85 -- l green
|
||||
, onSurface = rgb255 32 68 45 -- m green
|
||||
|
||||
-- Special purpose
|
||||
, shadow = rgba 34 139 34 0.15
|
||||
, overlay = rgba 27 94 27 0.6
|
||||
, border = rgb255 200 230 201
|
||||
, focus = rgb255 102 187 106
|
||||
, transparent = rgba 0 0 0 0
|
||||
}
|
||||
|
||||
|
||||
darkColourTheme : ColourScheme
|
||||
darkColourTheme =
|
||||
{ -- Core brand colors
|
||||
primary = rgb255 92 128 105 -- ll green (unchanged)
|
||||
, secondary = rgb255 32 68 45 -- g green (slightly deeper)
|
||||
|
||||
-- Surface colors
|
||||
, background = rgb255 2 38 15 -- darker dk dk green
|
||||
, surface = rgb255 18 50 28 -- dk green (slightly lighter than background)
|
||||
, surfaceVariant = rgb255 38 78 50 -- mm green (lighter for contrast)
|
||||
|
||||
-- Text colors
|
||||
, onPrimary = rgb255 92 128 105 -- ll green (unchanged)
|
||||
, onSecondary = rgb255 122 168 145 -- lll green (slightly lighter for contrast)
|
||||
, onBackground = rgb255 152 188 165 -- dlite green (brighter for clarity)
|
||||
, onSurface = rgb255 102 138 115 -- medium green (brighter than before)
|
||||
|
||||
-- Special purpose
|
||||
, shadow = rgba 0 0 0 0.4
|
||||
, overlay = rgba 0 0 0 0.7
|
||||
, border = rgb255 66 90 66 -- slightly darker than before
|
||||
, focus = rgb255 129 199 132 -- unchanged
|
||||
, transparent = rgba 0 0 0 0
|
||||
}
|
||||
|
||||
|
||||
getColourScheme : Theme -> ColourScheme
|
||||
getColourScheme theme =
|
||||
case theme of
|
||||
Light ->
|
||||
lightColourTheme
|
||||
|
||||
Dark ->
|
||||
darkColourTheme
|
||||
|
||||
|
||||
getColour : Theme -> (ColourScheme -> Color) -> Color
|
||||
getColour theme colourAccessor =
|
||||
colourAccessor (getColourScheme theme)
|
||||
|
||||
|
||||
getScheme : Shared.Model -> ColourScheme
|
||||
getScheme shared =
|
||||
getColourScheme shared.theme
|
||||
60
templates/website/frontend/src/Config/Style/Colour/Types.elm
Executable file
60
templates/website/frontend/src/Config/Style/Colour/Types.elm
Executable file
|
|
@ -0,0 +1,60 @@
|
|||
module Config.Style.Colour.Types exposing
|
||||
( ColourScheme
|
||||
, Theme(..)
|
||||
, themeFromString
|
||||
, themeToString
|
||||
)
|
||||
|
||||
import Element exposing (Color)
|
||||
import Json.Decode as D
|
||||
import Json.Encode as E
|
||||
|
||||
|
||||
type alias ColourScheme =
|
||||
{ -- Core brand colors
|
||||
primary : Color
|
||||
, secondary : Color
|
||||
|
||||
-- Surface colors
|
||||
, background : Color
|
||||
, surface : Color
|
||||
, surfaceVariant : Color
|
||||
|
||||
-- Text colors
|
||||
, onPrimary : Color
|
||||
, onSecondary : Color
|
||||
, onBackground : Color
|
||||
, onSurface : Color
|
||||
|
||||
-- Special purpose
|
||||
, shadow : Color
|
||||
, overlay : Color
|
||||
, border : Color
|
||||
, focus : Color
|
||||
, transparent : Color
|
||||
}
|
||||
|
||||
|
||||
type Theme
|
||||
= Light
|
||||
| Dark
|
||||
|
||||
|
||||
themeToString : Theme -> String
|
||||
themeToString theme =
|
||||
case theme of
|
||||
Light ->
|
||||
"light"
|
||||
|
||||
Dark ->
|
||||
"dark"
|
||||
|
||||
|
||||
themeFromString : String -> Theme
|
||||
themeFromString str =
|
||||
case str of
|
||||
"dark" ->
|
||||
Dark
|
||||
|
||||
_ ->
|
||||
Light
|
||||
79
templates/website/frontend/src/Config/Style/Fonts.elm
Executable file
79
templates/website/frontend/src/Config/Style/Fonts.elm
Executable file
|
|
@ -0,0 +1,79 @@
|
|||
module Config.Style.Fonts exposing
|
||||
( FontScale
|
||||
, FontSizes
|
||||
, bodyFont
|
||||
, createFontScale
|
||||
, createFontSizes
|
||||
, defaultFontScale
|
||||
, headerFont
|
||||
, paragraphSpacing
|
||||
)
|
||||
|
||||
import Element
|
||||
exposing
|
||||
( Attr
|
||||
, Attribute
|
||||
, spacing
|
||||
)
|
||||
import Element.Font as F
|
||||
exposing
|
||||
( size
|
||||
, typeface
|
||||
)
|
||||
|
||||
|
||||
headerFont : F.Font
|
||||
headerFont =
|
||||
F.typeface "Montez"
|
||||
|
||||
|
||||
bodyFont : F.Font
|
||||
bodyFont =
|
||||
F.typeface "Playpen Sans"
|
||||
|
||||
|
||||
paragraphSpacing : Attribute msg
|
||||
paragraphSpacing =
|
||||
spacing 0
|
||||
|
||||
|
||||
type FontScale
|
||||
= FontScale Float
|
||||
|
||||
|
||||
createFontScale : Float -> FontScale
|
||||
createFontScale baseFontSize =
|
||||
FontScale baseFontSize
|
||||
|
||||
|
||||
defaultFontScale : FontScale
|
||||
defaultFontScale =
|
||||
FontScale 16.0
|
||||
|
||||
|
||||
type alias FontSizes msg =
|
||||
{ verySmall : Attribute msg
|
||||
, small : Attribute msg
|
||||
, normal : Attribute msg
|
||||
, medium : Attribute msg
|
||||
, large : Attribute msg
|
||||
, extraLarge : Attribute msg
|
||||
, huge : Attribute msg
|
||||
}
|
||||
|
||||
|
||||
createFontSizes : FontScale -> FontSizes msg
|
||||
createFontSizes (FontScale base) =
|
||||
let
|
||||
scaled multiplier =
|
||||
F.size (round (base * multiplier))
|
||||
in
|
||||
{ -- assuming a 16px base:
|
||||
verySmall = scaled 0.75 -- 12px
|
||||
, small = scaled 0.875 -- 14px
|
||||
, normal = scaled 1.0 -- 16px
|
||||
, medium = scaled 1.125 -- 18px
|
||||
, large = scaled 1.25 -- 20px
|
||||
, extraLarge = scaled 1.5 -- 24px
|
||||
, huge = scaled 2.0 -- 32px at
|
||||
}
|
||||
18
templates/website/frontend/src/Config/Style/Glow.elm
Executable file
18
templates/website/frontend/src/Config/Style/Glow.elm
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
module Config.Style.Glow exposing (..)
|
||||
|
||||
import Config.Style.Colour.Helpers exposing (..)
|
||||
import Element exposing (Attr)
|
||||
import Element.Border as D exposing (glow)
|
||||
import Html
|
||||
import Html.Attributes as H
|
||||
import Shared
|
||||
|
||||
|
||||
hoverGlow : Shared.Model -> Attr decorative msg
|
||||
hoverGlow shared =
|
||||
D.glow (getScheme shared).onBackground 4
|
||||
|
||||
|
||||
itemShadow : Html.Attribute msg
|
||||
itemShadow =
|
||||
H.style "filter" "drop-shadow(0px 0px 4px rgba(0,0,0,1))"
|
||||
33
templates/website/frontend/src/Config/Style/Icons/Helpers.elm
Executable file
33
templates/website/frontend/src/Config/Style/Icons/Helpers.elm
Executable file
|
|
@ -0,0 +1,33 @@
|
|||
module Config.Style.Icons.Helpers exposing (buildSvg)
|
||||
|
||||
import Config.Style.Icons.Types as SvgTypes
|
||||
exposing
|
||||
( InnerPart
|
||||
, OuterPart
|
||||
)
|
||||
import Element as E
|
||||
exposing
|
||||
( Element
|
||||
, el
|
||||
, html
|
||||
)
|
||||
import Svg exposing (svg)
|
||||
|
||||
|
||||
|
||||
-- , E.explain <| Debug.todo
|
||||
{- buildSvg consumes an inner record to construct most of an SVG, and an outer record to supply
|
||||
any potentially varying TypedSvg.Core.Attribute msgs and wrap it in an Element.el so it can be
|
||||
used by elm-ui. It provides a consistent interface for inserting SVGs into elm-ui code.
|
||||
-}
|
||||
|
||||
|
||||
buildSvg : SvgTypes.OuterPart msg -> SvgTypes.InnerPart msg -> Element msg
|
||||
buildSvg outer inner =
|
||||
el
|
||||
outer.elementAttributes
|
||||
<|
|
||||
html <|
|
||||
Svg.svg
|
||||
(outer.svgAttributes ++ inner.svgAttributes)
|
||||
inner.svg
|
||||
176
templates/website/frontend/src/Config/Style/Icons/Icons.elm
Executable file
176
templates/website/frontend/src/Config/Style/Icons/Icons.elm
Executable file
|
|
@ -0,0 +1,176 @@
|
|||
module Config.Style.Icons.Icons exposing (..)
|
||||
|
||||
import Config.Style.Icons.Helpers as HeSvg exposing (buildSvg)
|
||||
import Config.Style.Icons.Types as SvgTypes
|
||||
exposing
|
||||
( InnerPart
|
||||
, OuterPart
|
||||
)
|
||||
import Element as E exposing (Element)
|
||||
import Html exposing (Html)
|
||||
import Svg
|
||||
exposing
|
||||
( path
|
||||
, svg
|
||||
)
|
||||
import Svg.Attributes as SvgAttr
|
||||
|
||||
|
||||
discord : SvgTypes.OuterPart msg -> Element msg
|
||||
discord inner =
|
||||
HeSvg.buildSvg inner
|
||||
{ svgAttributes =
|
||||
[ SvgAttr.viewBox "0 0 640 512"
|
||||
, SvgAttr.fill "currentColor"
|
||||
]
|
||||
, svg =
|
||||
[ path
|
||||
[ SvgAttr.d "M524.5 69.8a1.5 1.5 0 0 0 -.8-.7A485.1 485.1 0 0 0 404.1 32a1.8 1.8 0 0 0 -1.9 .9 337.5 337.5 0 0 0 -14.9 30.6 447.8 447.8 0 0 0 -134.4 0 309.5 309.5 0 0 0 -15.1-30.6 1.9 1.9 0 0 0 -1.9-.9A483.7 483.7 0 0 0 116.1 69.1a1.7 1.7 0 0 0 -.8 .7C39.1 183.7 18.2 294.7 28.4 404.4a2 2 0 0 0 .8 1.4A487.7 487.7 0 0 0 176 479.9a1.9 1.9 0 0 0 2.1-.7A348.2 348.2 0 0 0 208.1 430.4a1.9 1.9 0 0 0 -1-2.6 321.2 321.2 0 0 1 -45.9-21.9 1.9 1.9 0 0 1 -.2-3.1c3.1-2.3 6.2-4.7 9.1-7.1a1.8 1.8 0 0 1 1.9-.3c96.2 43.9 200.4 43.9 295.5 0a1.8 1.8 0 0 1 1.9 .2c2.9 2.4 6 4.9 9.1 7.2a1.9 1.9 0 0 1 -.2 3.1 301.4 301.4 0 0 1 -45.9 21.8 1.9 1.9 0 0 0 -1 2.6 391.1 391.1 0 0 0 30 48.8 1.9 1.9 0 0 0 2.1 .7A486 486 0 0 0 610.7 405.7a1.9 1.9 0 0 0 .8-1.4C623.7 277.6 590.9 167.5 524.5 69.8zM222.5 337.6c-29 0-52.8-26.6-52.8-59.2S193.1 219.1 222.5 219.1c29.7 0 53.3 26.8 52.8 59.2C275.3 311 251.9 337.6 222.5 337.6zm195.4 0c-29 0-52.8-26.6-52.8-59.2S388.4 219.1 417.9 219.1c29.7 0 53.3 26.8 52.8 59.2C470.7 311 447.5 337.6 417.9 337.6z"
|
||||
]
|
||||
[]
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
twitter : SvgTypes.OuterPart msg -> Element msg
|
||||
twitter inner =
|
||||
HeSvg.buildSvg inner
|
||||
{ svgAttributes =
|
||||
[ SvgAttr.viewBox "0 0 512 512"
|
||||
, SvgAttr.fill "currentColor"
|
||||
]
|
||||
, svg =
|
||||
[ path
|
||||
[ SvgAttr.d "M389.2 48h70.6L305.6 224.2 487 464H345L233.7 318.6 106.5 464H35.8L200.7 275.5 26.8 48H172.4L272.9 180.9 389.2 48zM364.4 421.8h39.1L151.1 88h-42L364.4 421.8z"
|
||||
]
|
||||
[]
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
facebook : SvgTypes.OuterPart msg -> Element msg
|
||||
facebook inner =
|
||||
HeSvg.buildSvg inner
|
||||
{ svgAttributes =
|
||||
[ SvgAttr.viewBox "0 0 640 640"
|
||||
, SvgAttr.fill "currentColor"
|
||||
]
|
||||
, svg =
|
||||
[ path
|
||||
[ SvgAttr.d "M240 363.3L240 576L356 576L356 363.3L442.5 363.3L460.5 265.5L356 265.5L356 230.9C356 179.2 376.3 159.4 428.7 159.4C445 159.4 458.1 159.8 465.7 160.6L465.7 71.9C451.4 68 416.4 64 396.2 64C289.3 64 240 114.5 240 223.4L240 265.5L174 265.5L174 363.3L240 363.3z"
|
||||
]
|
||||
[]
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
tiktok : SvgTypes.OuterPart msg -> Element msg
|
||||
tiktok inner =
|
||||
HeSvg.buildSvg inner
|
||||
{ svgAttributes =
|
||||
[ SvgAttr.viewBox "0 0 640 640"
|
||||
, SvgAttr.fill "currentColor"
|
||||
]
|
||||
, svg =
|
||||
[ path
|
||||
[ SvgAttr.d "M544.5 273.9C500.5 274 457.5 260.3 421.7 234.7L421.7 413.4C421.7 446.5 411.6 478.8 392.7 506C373.8 533.2 347.1 554 316.1 565.6C285.1 577.2 251.3 579.1 219.2 570.9C187.1 562.7 158.3 545 136.5 520.1C114.7 495.2 101.2 464.1 97.5 431.2C93.8 398.3 100.4 365.1 116.1 336C131.8 306.9 156.1 283.3 185.7 268.3C215.3 253.3 248.6 247.8 281.4 252.3L281.4 342.2C266.4 337.5 250.3 337.6 235.4 342.6C220.5 347.6 207.5 357.2 198.4 369.9C189.3 382.6 184.4 398 184.5 413.8C184.6 429.6 189.7 444.8 199 457.5C208.3 470.2 221.4 479.6 236.4 484.4C251.4 489.2 267.5 489.2 282.4 484.3C297.3 479.4 310.4 469.9 319.6 457.2C328.8 444.5 333.8 429.1 333.8 413.4L333.8 64L421.8 64C421.7 71.4 422.4 78.9 423.7 86.2C426.8 102.5 433.1 118.1 442.4 131.9C451.7 145.7 463.7 157.5 477.6 166.5C497.5 179.6 520.8 186.6 544.6 186.6L544.6 274z"
|
||||
]
|
||||
[]
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
instagram : SvgTypes.OuterPart msg -> Element msg
|
||||
instagram inner =
|
||||
HeSvg.buildSvg inner
|
||||
{ svgAttributes =
|
||||
[ SvgAttr.viewBox "0 0 640 640"
|
||||
, SvgAttr.fill "currentColor"
|
||||
]
|
||||
, svg =
|
||||
[ path
|
||||
[ SvgAttr.d "M320.3 205C256.8 204.8 205.2 256.2 205 319.7C204.8 383.2 256.2 434.8 319.7 435C383.2 435.2 434.8 383.8 435 320.3C435.2 256.8 383.8 205.2 320.3 205zM319.7 245.4C360.9 245.2 394.4 278.5 394.6 319.7C394.8 360.9 361.5 394.4 320.3 394.6C279.1 394.8 245.6 361.5 245.4 320.3C245.2 279.1 278.5 245.6 319.7 245.4zM413.1 200.3C413.1 185.5 425.1 173.5 439.9 173.5C454.7 173.5 466.7 185.5 466.7 200.3C466.7 215.1 454.7 227.1 439.9 227.1C425.1 227.1 413.1 215.1 413.1 200.3zM542.8 227.5C541.1 191.6 532.9 159.8 506.6 133.6C480.4 107.4 448.6 99.2 412.7 97.4C375.7 95.3 264.8 95.3 227.8 97.4C192 99.1 160.2 107.3 133.9 133.5C107.6 159.7 99.5 191.5 97.7 227.4C95.6 264.4 95.6 375.3 97.7 412.3C99.4 448.2 107.6 480 133.9 506.2C160.2 532.4 191.9 540.6 227.8 542.4C264.8 544.5 375.7 544.5 412.7 542.4C448.6 540.7 480.4 532.5 506.6 506.2C532.8 480 541 448.2 542.8 412.3C544.9 375.3 544.9 264.5 542.8 227.5zM495 452C487.2 471.6 472.1 486.7 452.4 494.6C422.9 506.3 352.9 503.6 320.3 503.6C287.7 503.6 217.6 506.2 188.2 494.6C168.6 486.8 153.5 471.7 145.6 452C133.9 422.5 136.6 352.5 136.6 319.9C136.6 287.3 134 217.2 145.6 187.8C153.4 168.2 168.5 153.1 188.2 145.2C217.7 133.5 287.7 136.2 320.3 136.2C352.9 136.2 423 133.6 452.4 145.2C472 153 487.1 168.1 495 187.8C506.7 217.3 504 287.3 504 319.9C504 352.5 506.7 422.6 495 452z"
|
||||
]
|
||||
[]
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
patreon : SvgTypes.OuterPart msg -> Element msg
|
||||
patreon inner =
|
||||
HeSvg.buildSvg inner
|
||||
{ svgAttributes =
|
||||
[ SvgAttr.viewBox "0 0 640 640"
|
||||
, SvgAttr.fill "currentColor"
|
||||
]
|
||||
, svg =
|
||||
[ path
|
||||
[ SvgAttr.d "M554 217.8C553.9 152.4 503 98.8 443.3 79.5C369.1 55.5 271.3 59 200.4 92.4C114.6 132.9 87.6 221.7 86.6 310.2C85.8 383 93 574.6 201.2 576C281.5 577 293.5 473.5 330.7 423.7C357.1 388.2 391.2 378.2 433.1 367.8C505.1 350 554.2 293.1 554.1 217.8L554 217.8z"
|
||||
]
|
||||
[]
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
reddit : SvgTypes.OuterPart msg -> Element msg
|
||||
reddit inner =
|
||||
HeSvg.buildSvg inner
|
||||
{ svgAttributes =
|
||||
[ SvgAttr.viewBox "0 0 640 640"
|
||||
, SvgAttr.fill "currentColor"
|
||||
]
|
||||
, svg =
|
||||
[ path
|
||||
[ SvgAttr.d "M437 202.6C411.8 202.6 390.7 185.1 385.1 161.6C354.5 165.9 330.9 192.3 330.9 224L330.9 224.2C378.3 226 421.5 239.3 455.8 260.5C468.4 250.8 484.2 245 501.3 245C542.6 245 576 278.4 576 319.7C576 349.5 558.6 375.2 533.3 387.2C530.9 474 436.3 543.8 320.1 543.8C203.9 543.8 109.5 474.1 107 387.4C81.6 375.5 64 349.7 64 319.7C64 278.4 97.4 245 138.7 245C155.9 245 171.7 250.8 184.4 260.6C218.4 239.5 261.2 226.2 308.1 224.2L308.1 223.9C308.1 179.6 341.8 143 384.9 138.4C389.8 114.2 411.2 96 437 96C466.4 96 490.3 119.9 490.3 149.3C490.3 178.7 466.4 202.6 437 202.6zM221.5 319.3C200.6 319.3 182.6 340.1 181.3 367.2C180 394.3 198.4 405.3 219.3 405.3C240.2 405.3 255.9 395.5 257.1 368.4C258.3 341.3 242.4 319.3 221.4 319.3L221.5 319.3zM459 367.1C457.8 340 439.8 319.2 418.8 319.2C397.8 319.2 381.9 341.2 383.1 368.3C384.3 395.4 400 405.2 420.9 405.2C441.8 405.2 460.2 394.2 458.9 367.1L459 367.1zM398.9 437.9C400.4 434.3 397.9 430.2 394 429.8C371 427.5 346.1 426.2 320.2 426.2C294.3 426.2 269.4 427.5 246.4 429.8C242.5 430.2 240 434.3 241.5 437.9C254.4 468.7 284.8 490.3 320.2 490.3C355.6 490.3 386 468.7 398.9 437.9z"
|
||||
]
|
||||
[]
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
copyLink : SvgTypes.OuterPart msg -> Element msg
|
||||
copyLink inner =
|
||||
HeSvg.buildSvg inner
|
||||
{ svgAttributes =
|
||||
[ SvgAttr.viewBox "0 0 640 512"
|
||||
, SvgAttr.fill "currentColor"
|
||||
]
|
||||
, svg =
|
||||
[ path
|
||||
[ SvgAttr.d "M579.8 267.7c56.5-56.5 56.5-148 0-204.5c-50-50-128.8-56.5-186.3-15.4l-1.6 1.1c-14.4 10.3-17.7 30.3-7.4 44.6s30.3 17.7 44.6 7.4l1.6-1.1c32.1-22.9 76-19.3 103.8 8.6c31.5 31.5 31.5 82.5 0 114L422.3 334.8c-31.5 31.5-82.5 31.5-114 0c-27.9-27.9-31.5-71.8-8.6-103.8l1.1-1.6c10.3-14.4 6.9-34.4-7.4-44.6s-34.4-6.9-44.6 7.4l-1.1 1.6C206.5 251.2 213 330 263 380c56.5 56.5 148 56.5 204.5 0L579.8 267.7zM60.2 244.3c-56.5 56.5-56.5 148 0 204.5c50 50 128.8 56.5 186.3 15.4l1.6-1.1c14.4-10.3 17.7-30.3 7.4-44.6s-30.3-17.7-44.6-7.4l-1.6 1.1c-32.1 22.9-76 19.3-103.8-8.6C74 372 74 321 105.5 289.5L217.7 177.2c31.5-31.5 82.5-31.5 114 0c27.9 27.9 31.5 71.8 8.6 103.9l-1.1 1.6c-10.3 14.4-6.9 34.4 7.4 44.6s34.4 6.9 44.6-7.4l1.1-1.6C433.5 260.8 427 182 377 132c-56.5-56.5-148-56.5-204.5 0L60.2 244.3z"
|
||||
]
|
||||
[]
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
sun : SvgTypes.OuterPart msg -> Element msg
|
||||
sun inner =
|
||||
HeSvg.buildSvg inner
|
||||
{ svgAttributes =
|
||||
[ SvgAttr.viewBox "0 0 512 512"
|
||||
, SvgAttr.fill "currentColor"
|
||||
]
|
||||
, svg =
|
||||
[ path
|
||||
[ SvgAttr.d "M361.5 1.2c5 2.1 8.6 6.6 9.6 11.9L391 121l107.9 19.8c5.3 1 9.8 4.6 11.9 9.6s1.5 10.7-1.6 15.2L446.9 256l62.3 90.3c3.1 4.5 3.7 10.2 1.6 15.2s-6.6 8.6-11.9 9.6L391 391 371.1 498.9c-1 5.3-4.6 9.8-9.6 11.9s-10.7 1.5-15.2-1.6L256 446.9l-90.3 62.3c-4.5 3.1-10.2 3.7-15.2 1.6s-8.6-6.6-9.6-11.9L121 391 13.1 371.1c-5.3-1-9.8-4.6-11.9-9.6s-1.5-10.7 1.6-15.2L65.1 256 2.8 165.7c-3.1-4.5-3.7-10.2-1.6-15.2s6.6-8.6 11.9-9.6L121 121 140.9 13.1c1-5.3 4.6-9.8 9.6-11.9s10.7-1.5 15.2 1.6L256 65.1 346.3 2.8c4.5-3.1 10.2-3.7 15.2-1.6zM160 256a96 96 0 1 1 192 0 96 96 0 1 1 -192 0zm224 0a128 128 0 1 0 -256 0 128 128 0 1 0 256 0z"
|
||||
]
|
||||
[]
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
moon : SvgTypes.OuterPart msg -> Element msg
|
||||
moon inner =
|
||||
HeSvg.buildSvg inner
|
||||
{ svgAttributes =
|
||||
[ SvgAttr.viewBox "0 0 384 512"
|
||||
, SvgAttr.fill "currentColor"
|
||||
]
|
||||
, svg =
|
||||
[ path
|
||||
[ SvgAttr.d "M223.5 32C100 32 0 132.3 0 256S100 480 223.5 480c60.6 0 115.5-24.2 155.8-63.4c5-4.9 6.3-12.5 3.1-18.7s-10.1-9.7-17-8.5c-9.8 1.7-19.8 2.6-30.1 2.6c-96.9 0-175.5-78.8-175.5-176 0-65.8 36-123.1 89.3-153.3c6.1-3.5 9.2-10.5 7.7-17.3s-7.3-11.9-14.3-12.5c-6.3-.5-12.6-.8-19-.8z"
|
||||
]
|
||||
[]
|
||||
]
|
||||
}
|
||||
28
templates/website/frontend/src/Config/Style/Icons/Types.elm
Executable file
28
templates/website/frontend/src/Config/Style/Icons/Types.elm
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
module Config.Style.Icons.Types exposing
|
||||
( InnerPart
|
||||
, OuterPart
|
||||
)
|
||||
|
||||
{-| The types used for SVG management.
|
||||
-}
|
||||
|
||||
import Element exposing (Attribute)
|
||||
import Shared exposing (Model)
|
||||
import Svg exposing (svg)
|
||||
|
||||
|
||||
{-| The outer record for the SVG builder. This is explained in ../Helpers/Svg.elm.
|
||||
-}
|
||||
type alias OuterPart msg =
|
||||
{ elementAttributes : List (Element.Attribute msg)
|
||||
, sharedModel : Shared.Model
|
||||
, svgAttributes : List (Svg.Attribute msg)
|
||||
}
|
||||
|
||||
|
||||
{-| The inner record for the SVG builder. This is explained in ../Helpers/Svg.elm.
|
||||
-}
|
||||
type alias InnerPart msg =
|
||||
{ svgAttributes : List (Svg.Attribute msg)
|
||||
, svg : List (Svg.Svg msg)
|
||||
}
|
||||
69
templates/website/frontend/src/Config/Style/Transitions.elm
Executable file
69
templates/website/frontend/src/Config/Style/Transitions.elm
Executable file
|
|
@ -0,0 +1,69 @@
|
|||
module Config.Style.Transitions exposing (..)
|
||||
|
||||
import Config.Style.Colour.Helpers exposing (..)
|
||||
import Config.Style.Glow exposing (..)
|
||||
import Element
|
||||
exposing
|
||||
( Attribute
|
||||
, htmlAttribute
|
||||
, mouseOver
|
||||
)
|
||||
import Element.Background as B exposing (color)
|
||||
import Element.Border as D exposing (color)
|
||||
import Element.Font as F exposing (color)
|
||||
import Html.Attributes as H exposing (style)
|
||||
import Shared
|
||||
|
||||
|
||||
slowTime : String
|
||||
slowTime =
|
||||
"0.5s"
|
||||
|
||||
|
||||
fastTime : String
|
||||
fastTime =
|
||||
"0.1s"
|
||||
|
||||
|
||||
transition : String -> Attribute msg
|
||||
transition time =
|
||||
htmlAttribute <| style "transition" ("all " ++ time ++ " ease-in-out")
|
||||
|
||||
|
||||
|
||||
-- Specific transition functions for separating fast and slow properties
|
||||
|
||||
|
||||
cardTransitions : Attribute msg
|
||||
cardTransitions =
|
||||
htmlAttribute <|
|
||||
style "transition"
|
||||
("background-color "
|
||||
++ slowTime
|
||||
++ " ease-in-out, "
|
||||
++ "color "
|
||||
++ slowTime
|
||||
++ " ease-in-out, "
|
||||
++ "border-color "
|
||||
++ slowTime
|
||||
++ " ease-in-out, "
|
||||
++ "box-shadow "
|
||||
++ fastTime
|
||||
++ " ease-in-out, "
|
||||
++ "transform "
|
||||
++ fastTime
|
||||
++ " ease-in-out"
|
||||
)
|
||||
|
||||
|
||||
hoverButton : Shared.Model -> Attribute msg
|
||||
hoverButton shared =
|
||||
mouseOver
|
||||
[ B.color (getScheme shared).secondary
|
||||
, F.color (getScheme shared).primary
|
||||
]
|
||||
|
||||
|
||||
imageFadeTransition : String -> Attribute msg
|
||||
imageFadeTransition time =
|
||||
htmlAttribute <| style "transition" ("opacity " ++ time ++ " ease-in-out")
|
||||
205
templates/website/frontend/src/Effect.elm
Executable file
205
templates/website/frontend/src/Effect.elm
Executable file
|
|
@ -0,0 +1,205 @@
|
|||
module Effect exposing
|
||||
( Effect
|
||||
, none, batch
|
||||
, sendCmd, sendMsg, sendSharedMsg
|
||||
, pushRoute, replaceRoute, loadExternalUrl
|
||||
, map, toCmd
|
||||
)
|
||||
|
||||
{-|
|
||||
|
||||
@docs Effect
|
||||
@docs none, batch
|
||||
@docs sendCmd, sendMsg, sendSharedMsg
|
||||
@docs pushRoute, replaceRoute, loadExternalUrl
|
||||
|
||||
@docs map, toCmd
|
||||
|
||||
-}
|
||||
|
||||
import Browser.Navigation
|
||||
import Dict exposing (Dict)
|
||||
import Route exposing (Route)
|
||||
import Route.Path
|
||||
import Shared.Model
|
||||
import Shared.Msg
|
||||
import Task
|
||||
import Url exposing (Url)
|
||||
|
||||
|
||||
type Effect msg
|
||||
= -- BASICS
|
||||
None
|
||||
| Batch (List (Effect msg))
|
||||
| SendCmd (Cmd msg)
|
||||
-- ROUTING
|
||||
| PushUrl String
|
||||
| ReplaceUrl String
|
||||
| LoadExternalUrl String
|
||||
-- SHARED
|
||||
| SendSharedMsg Shared.Msg.Msg
|
||||
|
||||
|
||||
|
||||
-- BASICS
|
||||
|
||||
|
||||
{-| Don't send any effect.
|
||||
-}
|
||||
none : Effect msg
|
||||
none =
|
||||
None
|
||||
|
||||
|
||||
{-| Send multiple effects at once.
|
||||
-}
|
||||
batch : List (Effect msg) -> Effect msg
|
||||
batch =
|
||||
Batch
|
||||
|
||||
|
||||
{-| Send a normal `Cmd msg` as an effect, something like `Http.get` or `Random.generate`.
|
||||
-}
|
||||
sendCmd : Cmd msg -> Effect msg
|
||||
sendCmd =
|
||||
SendCmd
|
||||
|
||||
|
||||
{-| Send a message as an effect. Useful when emitting events from UI components.
|
||||
-}
|
||||
sendMsg : msg -> Effect msg
|
||||
sendMsg msg =
|
||||
Task.succeed msg
|
||||
|> Task.perform identity
|
||||
|> SendCmd
|
||||
|
||||
|
||||
{-| Send a shared message as an effect. Useful for communicating between pages and shared state.
|
||||
-}
|
||||
sendSharedMsg : Shared.Msg.Msg -> Effect msg
|
||||
sendSharedMsg sharedMsg =
|
||||
SendSharedMsg sharedMsg
|
||||
|
||||
|
||||
|
||||
-- ROUTING
|
||||
|
||||
|
||||
{-| Set the new route, and make the back button go back to the current route.
|
||||
-}
|
||||
pushRoute :
|
||||
{ path : Route.Path.Path
|
||||
, query : Dict String String
|
||||
, hash : Maybe String
|
||||
}
|
||||
-> Effect msg
|
||||
pushRoute route =
|
||||
PushUrl (Route.toString route)
|
||||
|
||||
|
||||
{-| Set given path as route (without any query params or hash), and make the back button go back to the current route.
|
||||
-}
|
||||
pushPath :
|
||||
Route.Path.Path
|
||||
-> Effect msg
|
||||
pushPath path =
|
||||
PushUrl (Route.toString { path = path, query = Dict.empty, hash = Nothing })
|
||||
|
||||
|
||||
{-| Set the new route, but replace the previous one, so clicking the back
|
||||
button **won't** go back to the previous route.
|
||||
-}
|
||||
replaceRoute :
|
||||
{ path : Route.Path.Path
|
||||
, query : Dict String String
|
||||
, hash : Maybe String
|
||||
}
|
||||
-> Effect msg
|
||||
replaceRoute route =
|
||||
ReplaceUrl (Route.toString route)
|
||||
|
||||
|
||||
{-| Set given path as route (without any query params or hash), but replace the previous route,
|
||||
so clicking the back button **won't** go back to the previous route
|
||||
-}
|
||||
replacePath :
|
||||
Route.Path.Path
|
||||
-> Effect msg
|
||||
replacePath path =
|
||||
ReplaceUrl (Route.toString { path = path, query = Dict.empty, hash = Nothing })
|
||||
|
||||
|
||||
{-| Redirect users to a new URL, somewhere external your web application.
|
||||
-}
|
||||
loadExternalUrl : String -> Effect msg
|
||||
loadExternalUrl =
|
||||
LoadExternalUrl
|
||||
|
||||
|
||||
|
||||
-- INTERNALS
|
||||
|
||||
|
||||
{-| Elm Land depends on this function to connect pages and layouts
|
||||
together into the overall app.
|
||||
-}
|
||||
map : (msg1 -> msg2) -> Effect msg1 -> Effect msg2
|
||||
map fn effect =
|
||||
case effect of
|
||||
None ->
|
||||
None
|
||||
|
||||
Batch list ->
|
||||
Batch (List.map (map fn) list)
|
||||
|
||||
SendCmd cmd ->
|
||||
SendCmd (Cmd.map fn cmd)
|
||||
|
||||
PushUrl url ->
|
||||
PushUrl url
|
||||
|
||||
ReplaceUrl url ->
|
||||
ReplaceUrl url
|
||||
|
||||
LoadExternalUrl url ->
|
||||
LoadExternalUrl url
|
||||
|
||||
SendSharedMsg sharedMsg ->
|
||||
SendSharedMsg sharedMsg
|
||||
|
||||
|
||||
{-| Elm Land depends on this function to perform your effects.
|
||||
-}
|
||||
toCmd :
|
||||
{ key : Browser.Navigation.Key
|
||||
, url : Url
|
||||
, shared : Shared.Model.Model
|
||||
, fromSharedMsg : Shared.Msg.Msg -> msg
|
||||
, batch : List msg -> msg
|
||||
, toCmd : msg -> Cmd msg
|
||||
}
|
||||
-> Effect msg
|
||||
-> Cmd msg
|
||||
toCmd options effect =
|
||||
case effect of
|
||||
None ->
|
||||
Cmd.none
|
||||
|
||||
Batch list ->
|
||||
Cmd.batch (List.map (toCmd options) list)
|
||||
|
||||
SendCmd cmd ->
|
||||
cmd
|
||||
|
||||
PushUrl url ->
|
||||
Browser.Navigation.pushUrl options.key url
|
||||
|
||||
ReplaceUrl url ->
|
||||
Browser.Navigation.replaceUrl options.key url
|
||||
|
||||
LoadExternalUrl url ->
|
||||
Browser.Navigation.load url
|
||||
|
||||
SendSharedMsg sharedMsg ->
|
||||
Task.succeed sharedMsg
|
||||
|> Task.perform options.fromSharedMsg
|
||||
112
templates/website/frontend/src/Pages/Home_.elm
Executable file
112
templates/website/frontend/src/Pages/Home_.elm
Executable file
|
|
@ -0,0 +1,112 @@
|
|||
module Pages.Home_ exposing (Model, Msg, page)
|
||||
|
||||
import Config.Helpers.Response exposing (..)
|
||||
import Config.Helpers.Viewport exposing (resetViewport)
|
||||
import Config.Pages.Home.Background exposing (..)
|
||||
import Config.Pages.Home.CardMaker.Helpers.Icon exposing (..)
|
||||
import Config.Pages.Home.CardMaker.Helpers.Image exposing (..)
|
||||
import Config.Pages.Home.CardMaker.Records exposing (..)
|
||||
import Config.Pages.Home.CardMaker.Types exposing (..)
|
||||
import Config.Pages.Home.Helpers exposing (..)
|
||||
import Config.Style.Colour.Helpers exposing (..)
|
||||
import Config.Style.Colour.Types exposing (Theme(..))
|
||||
import Config.Style.Fonts exposing (..)
|
||||
import Config.Style.Glow exposing (..)
|
||||
import Config.Style.Icons.Icons exposing (..)
|
||||
import Config.Style.Transitions exposing (..)
|
||||
import Effect exposing (Effect)
|
||||
import Element as E exposing (..)
|
||||
import Element.Background as B exposing (..)
|
||||
import Element.Border as D exposing (..)
|
||||
import Element.Events as V
|
||||
import Element.Font as F exposing (..)
|
||||
import Html exposing (Html)
|
||||
import Html.Attributes as Attr
|
||||
import Page exposing (Page)
|
||||
import Ports
|
||||
import Route exposing (Route)
|
||||
import Shared exposing (Model)
|
||||
import Shared.Msg
|
||||
import Svg.Attributes as SvgAttr exposing (clip)
|
||||
import View exposing (View)
|
||||
|
||||
|
||||
page : Shared.Model -> Route () -> Page Model Msg
|
||||
page shared route =
|
||||
Page.new
|
||||
{ init = init
|
||||
, update = update
|
||||
, subscriptions = subscriptions
|
||||
, view = view shared
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- INIT
|
||||
|
||||
|
||||
type alias Model =
|
||||
{}
|
||||
|
||||
|
||||
init : () -> ( Model, Effect Msg )
|
||||
init () =
|
||||
( {}
|
||||
, Effect.map
|
||||
(\_ -> NoOp)
|
||||
(Effect.sendCmd resetViewport)
|
||||
)
|
||||
|
||||
|
||||
|
||||
-- UPDATE
|
||||
|
||||
|
||||
type Msg
|
||||
= NoOp
|
||||
| ToggleTheme
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Effect Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
NoOp ->
|
||||
( model
|
||||
, Effect.none
|
||||
)
|
||||
|
||||
ToggleTheme ->
|
||||
( model
|
||||
, Effect.sendSharedMsg Shared.Msg.ToggleTheme
|
||||
)
|
||||
|
||||
|
||||
|
||||
-- SUBSCRIPTIONS
|
||||
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions model =
|
||||
Sub.none
|
||||
|
||||
|
||||
|
||||
-- VIEW
|
||||
|
||||
|
||||
view : Shared.Model -> Model -> View Msg
|
||||
view shared model =
|
||||
{ title = ""
|
||||
, attributes = [ F.family [ headerFont ] ]
|
||||
, element = homePage shared (createFontSizes shared.fontScale)
|
||||
}
|
||||
|
||||
|
||||
paddingHelper : Attribute msg
|
||||
paddingHelper =
|
||||
padding 10
|
||||
|
||||
|
||||
homePage : Shared.Model -> FontSizes Msg -> Element Msg
|
||||
homePage shared fontSizes =
|
||||
E.el [] <| text "Hello world!"
|
||||
76
templates/website/frontend/src/Pages/NotFound_.elm
Executable file
76
templates/website/frontend/src/Pages/NotFound_.elm
Executable file
|
|
@ -0,0 +1,76 @@
|
|||
module Pages.NotFound_ exposing (Model, Msg, page)
|
||||
|
||||
import Config.Helpers.Viewport exposing (resetViewport)
|
||||
import Effect exposing (Effect)
|
||||
import Element as E exposing (..)
|
||||
import Html exposing (..)
|
||||
import Page exposing (Page)
|
||||
import Route exposing (Route)
|
||||
import Route.Path
|
||||
import Shared
|
||||
import View exposing (View)
|
||||
|
||||
|
||||
page : Shared.Model -> Route () -> Page Model Msg
|
||||
page shared route =
|
||||
Page.new
|
||||
{ init = init
|
||||
, update = update
|
||||
, subscriptions = subscriptions
|
||||
, view = view shared
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- INIT
|
||||
|
||||
|
||||
type alias Model =
|
||||
{}
|
||||
|
||||
|
||||
init : () -> ( Model, Effect Msg )
|
||||
init () =
|
||||
( {}
|
||||
, Effect.map
|
||||
(\_ -> NoOp)
|
||||
(Effect.sendCmd resetViewport)
|
||||
)
|
||||
|
||||
|
||||
|
||||
-- UPDATE
|
||||
|
||||
|
||||
type Msg
|
||||
= NoOp
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Effect Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
NoOp ->
|
||||
( model
|
||||
, Effect.none
|
||||
)
|
||||
|
||||
|
||||
|
||||
-- SUBSCRIPTIONS
|
||||
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions model =
|
||||
Sub.none
|
||||
|
||||
|
||||
|
||||
-- VIEW
|
||||
|
||||
|
||||
view : Shared.Model -> Model -> View Msg
|
||||
view shared model =
|
||||
{ title = ""
|
||||
, attributes = []
|
||||
, element = E.row [] [ E.text "Page not found" ]
|
||||
}
|
||||
28
templates/website/frontend/src/Ports.elm
Executable file
28
templates/website/frontend/src/Ports.elm
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
port module Ports exposing
|
||||
( assetsLoaded
|
||||
, checkAssetsLoaded
|
||||
, copyToClipboard
|
||||
, loadTheme
|
||||
, saveTheme
|
||||
, sendToLocalStorage
|
||||
)
|
||||
|
||||
import Json.Encode as Encode
|
||||
|
||||
|
||||
port sendToLocalStorage : { key : String, value : Encode.Value } -> Cmd msg
|
||||
|
||||
|
||||
port copyToClipboard : String -> Cmd msg
|
||||
|
||||
|
||||
port saveTheme : String -> Cmd msg
|
||||
|
||||
|
||||
port loadTheme : (String -> msg) -> Sub msg
|
||||
|
||||
|
||||
port checkAssetsLoaded : () -> Cmd msg
|
||||
|
||||
|
||||
port assetsLoaded : (() -> msg) -> Sub msg
|
||||
159
templates/website/frontend/src/Shared.elm
Executable file
159
templates/website/frontend/src/Shared.elm
Executable file
|
|
@ -0,0 +1,159 @@
|
|||
module Shared exposing
|
||||
( Flags, decoder
|
||||
, Model, Msg
|
||||
, init, update, subscriptions
|
||||
)
|
||||
|
||||
{-|
|
||||
|
||||
@docs Flags, decoder
|
||||
@docs Model, Msg
|
||||
@docs init, update, subscriptions
|
||||
|
||||
-}
|
||||
|
||||
import Browser.Events as BR exposing (..)
|
||||
import Config.Style.Colour.Types
|
||||
exposing
|
||||
( Theme(..)
|
||||
, themeFromString
|
||||
, themeToString
|
||||
)
|
||||
import Config.Style.Fonts exposing (FontScale, createFontScale)
|
||||
import Dict
|
||||
import Effect exposing (Effect, none)
|
||||
import Element as E exposing (..)
|
||||
import Json.Decode exposing (..)
|
||||
import Ports
|
||||
import Process
|
||||
import Route exposing (Route)
|
||||
import Route.Path
|
||||
import Shared.Model exposing (..)
|
||||
import Shared.Msg
|
||||
import Task
|
||||
|
||||
|
||||
|
||||
-- FLAGS
|
||||
|
||||
|
||||
type alias Flags =
|
||||
{ height : Int
|
||||
, width : Int
|
||||
, baseFontSize : Float
|
||||
}
|
||||
|
||||
|
||||
decoder : Json.Decode.Decoder Flags
|
||||
decoder =
|
||||
Json.Decode.map3
|
||||
(\height width baseFontSize ->
|
||||
{ height = height
|
||||
, width = width
|
||||
, baseFontSize = baseFontSize
|
||||
}
|
||||
)
|
||||
(field "height" int)
|
||||
(field "width" int)
|
||||
(field "baseFontSize" float)
|
||||
|
||||
|
||||
|
||||
-- INIT
|
||||
|
||||
|
||||
type alias Model =
|
||||
Shared.Model.Model
|
||||
|
||||
|
||||
init : Result Json.Decode.Error Flags -> Route () -> ( Model, Effect Msg )
|
||||
init flagsResult route =
|
||||
( modelFromFlagsResult flagsResult
|
||||
, Effect.sendCmd (Ports.checkAssetsLoaded ())
|
||||
)
|
||||
|
||||
|
||||
modelFromFlagsResult : Result Error Flags -> Model
|
||||
modelFromFlagsResult f =
|
||||
case f of
|
||||
Ok flags ->
|
||||
{ device = classifyDevice flags
|
||||
, height = flags.height
|
||||
, width = flags.width
|
||||
, theme = Dark
|
||||
, fontScale = createFontScale flags.baseFontSize
|
||||
, isLoading = True
|
||||
, isFadingOut = False
|
||||
}
|
||||
|
||||
Err e ->
|
||||
{ device =
|
||||
classifyDevice
|
||||
{ height = 0
|
||||
, width = 0
|
||||
}
|
||||
, height = 10
|
||||
, width = 10
|
||||
, theme = Dark
|
||||
, fontScale = createFontScale 16.0
|
||||
, isLoading = True
|
||||
, isFadingOut = False
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- UPDATE
|
||||
|
||||
|
||||
type alias Msg =
|
||||
Shared.Msg.Msg
|
||||
|
||||
|
||||
update : Route () -> Msg -> Model -> ( Model, Effect Msg )
|
||||
update route msg model =
|
||||
case msg of
|
||||
Shared.Msg.LoadTheme themeString ->
|
||||
( { model | theme = themeFromString themeString }
|
||||
, Effect.none
|
||||
)
|
||||
|
||||
Shared.Msg.ToggleTheme ->
|
||||
( model
|
||||
, Effect.sendCmd (Ports.saveTheme "toggle")
|
||||
)
|
||||
|
||||
Shared.Msg.Resize width height ->
|
||||
( { model
|
||||
| device =
|
||||
{ height = height
|
||||
, width = width
|
||||
}
|
||||
|> E.classifyDevice
|
||||
, height = height
|
||||
, width = width
|
||||
}
|
||||
, Effect.none
|
||||
)
|
||||
|
||||
Shared.Msg.LoadingComplete ->
|
||||
( { model | isFadingOut = True }
|
||||
, Effect.sendCmd (Process.sleep 600 |> Task.perform (\_ -> Shared.Msg.StartFadeOut))
|
||||
)
|
||||
|
||||
Shared.Msg.StartFadeOut ->
|
||||
( { model | isLoading = False, isFadingOut = False }
|
||||
, Effect.none
|
||||
)
|
||||
|
||||
|
||||
|
||||
-- SUBSCRIPTIONS
|
||||
|
||||
|
||||
subscriptions : Route () -> Model -> Sub Msg
|
||||
subscriptions route model =
|
||||
Sub.batch
|
||||
[ BR.onResize Shared.Msg.Resize
|
||||
, Ports.loadTheme Shared.Msg.LoadTheme
|
||||
, Ports.assetsLoaded (\_ -> Shared.Msg.LoadingComplete)
|
||||
]
|
||||
23
templates/website/frontend/src/Shared/Model.elm
Executable file
23
templates/website/frontend/src/Shared/Model.elm
Executable file
|
|
@ -0,0 +1,23 @@
|
|||
module Shared.Model exposing (Model)
|
||||
|
||||
import Config.Style.Colour.Types exposing (Theme(..))
|
||||
import Config.Style.Fonts exposing (FontScale)
|
||||
import Element exposing (Device)
|
||||
|
||||
|
||||
{-| Normally, this value would live in "Shared.elm"
|
||||
but that would lead to a circular dependency import cycle.
|
||||
|
||||
For that reason, both `Shared.Model` and `Shared.Msg` are in their
|
||||
own file, so they can be imported by `Effect.elm`
|
||||
|
||||
-}
|
||||
type alias Model =
|
||||
{ height : Int
|
||||
, width : Int
|
||||
, device : Device
|
||||
, theme : Theme
|
||||
, fontScale : FontScale
|
||||
, isLoading : Bool
|
||||
, isFadingOut : Bool
|
||||
}
|
||||
18
templates/website/frontend/src/Shared/Msg.elm
Executable file
18
templates/website/frontend/src/Shared/Msg.elm
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
module Shared.Msg exposing (Msg(..))
|
||||
|
||||
{-| -}
|
||||
|
||||
|
||||
{-| Normally, this value would live in "Shared.elm"
|
||||
but that would lead to a circular dependency import cycle.
|
||||
|
||||
For that reason, both `Shared.Model` and `Shared.Msg` are in their
|
||||
own file, so they can be imported by `Effect.elm`
|
||||
|
||||
-}
|
||||
type Msg
|
||||
= Resize Int Int
|
||||
| LoadTheme String
|
||||
| ToggleTheme
|
||||
| LoadingComplete
|
||||
| StartFadeOut
|
||||
100
templates/website/frontend/src/View.elm
Executable file
100
templates/website/frontend/src/View.elm
Executable file
|
|
@ -0,0 +1,100 @@
|
|||
module View exposing
|
||||
( View, map
|
||||
, none, fromString
|
||||
, toBrowserDocument
|
||||
)
|
||||
|
||||
{-|
|
||||
|
||||
@docs View, map
|
||||
@docs none, fromString
|
||||
@docs toBrowserDocument
|
||||
|
||||
-}
|
||||
|
||||
import Browser
|
||||
import Config.Style.LoadingScreen exposing (loadingScreen)
|
||||
import Element exposing (Attribute, Element, layout, mapAttribute, text)
|
||||
import Html
|
||||
import Route exposing (Route)
|
||||
import Shared.Model
|
||||
|
||||
|
||||
type alias View msg =
|
||||
{ title : String
|
||||
, attributes : List (Attribute msg)
|
||||
, element : Element msg
|
||||
}
|
||||
|
||||
|
||||
{-| Used internally by Elm Land to create your application
|
||||
so it works with Elm's expected `Browser.Document msg` type.
|
||||
-}
|
||||
toBrowserDocument :
|
||||
{ shared : Shared.Model.Model
|
||||
, route : Route ()
|
||||
, view : View msg
|
||||
}
|
||||
-> Browser.Document msg
|
||||
toBrowserDocument { shared, view } =
|
||||
{ title = view.title
|
||||
, body =
|
||||
[ layout
|
||||
(if shared.isLoading || shared.isFadingOut then
|
||||
Element.inFront (loadingScreen shared shared.isLoading) :: view.attributes
|
||||
|
||||
else
|
||||
view.attributes
|
||||
)
|
||||
view.element
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- toBrowserDocument :
|
||||
-- { shared : Shared.Model.Model
|
||||
-- , route : Route ()
|
||||
-- , view : View msg
|
||||
-- }
|
||||
-- -> Browser.Document msg
|
||||
-- toBrowserDocument { view } =
|
||||
-- { title = view.title
|
||||
-- , body = view.body
|
||||
-- }
|
||||
|
||||
|
||||
{-| Used internally by Elm Land to connect your pages together.
|
||||
-}
|
||||
map : (msg1 -> msg2) -> View msg1 -> View msg2
|
||||
map fn view =
|
||||
{ title = view.title
|
||||
, attributes = List.map (mapAttribute fn) view.attributes
|
||||
, element = Element.map fn view.element
|
||||
}
|
||||
|
||||
|
||||
{-| Used internally by Elm Land whenever transitioning between
|
||||
authenticated pages.
|
||||
-}
|
||||
none : View msg
|
||||
none =
|
||||
{ title = ""
|
||||
, attributes = []
|
||||
, element = Element.none
|
||||
}
|
||||
|
||||
|
||||
{-| If you customize the `View` module, anytime you run `elm-land add page`,
|
||||
the generated page will use this when adding your `view` function.
|
||||
|
||||
That way your app will compile after adding new pages, and you can see
|
||||
the new page working in the web browser!
|
||||
|
||||
-}
|
||||
fromString : String -> View msg
|
||||
fromString moduleName =
|
||||
{ title = moduleName
|
||||
, attributes = []
|
||||
, element = text moduleName
|
||||
}
|
||||
134
templates/website/frontend/src/interop.ts
Executable file
134
templates/website/frontend/src/interop.ts
Executable file
|
|
@ -0,0 +1,134 @@
|
|||
// This returns the flags passed into your Elm application
|
||||
export const flags = async ({ env }: ElmLand.FlagsArgs) => {
|
||||
// Get user's preferred font size by creating a temporary element
|
||||
const tempDiv = document.createElement("div");
|
||||
tempDiv.style.fontSize = "1rem";
|
||||
tempDiv.style.position = "absolute";
|
||||
tempDiv.style.visibility = "hidden";
|
||||
document.body.appendChild(tempDiv);
|
||||
const baseFontSize = parseFloat(window.getComputedStyle(tempDiv).fontSize);
|
||||
document.body.removeChild(tempDiv);
|
||||
|
||||
return {
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
baseFontSize: baseFontSize,
|
||||
};
|
||||
};
|
||||
|
||||
// This function is called after your Elm app starts
|
||||
export const onReady = ({ app, env }: ElmLand.OnReadyArgs) => {
|
||||
console.log("Elm is ready", app);
|
||||
|
||||
// Simple loading screen with minimum display time
|
||||
let loadingComplete = false;
|
||||
|
||||
function completeLoading() {
|
||||
if (!loadingComplete && app.ports?.assetsLoaded?.send) {
|
||||
loadingComplete = true;
|
||||
console.log("Loading complete - starting fade out sequence");
|
||||
app.ports.assetsLoaded.send(null);
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the loading completion trigger
|
||||
if (app.ports?.checkAssetsLoaded?.subscribe) {
|
||||
app.ports.checkAssetsLoaded.subscribe(() => {
|
||||
console.log("Elm app ready - starting loading timer");
|
||||
|
||||
// Minimum display time for loading screen (so users can see it)
|
||||
const minDisplayTime = 1200; // 1.2 seconds
|
||||
|
||||
// Check if fonts are loaded, then wait for minimum time
|
||||
if (document.fonts) {
|
||||
document.fonts.ready.then(() => {
|
||||
console.log(
|
||||
"Fonts loaded, waiting for minimum display time of",
|
||||
minDisplayTime,
|
||||
"ms",
|
||||
);
|
||||
setTimeout(() => {
|
||||
console.log("Minimum display time elapsed, triggering fade out");
|
||||
completeLoading();
|
||||
}, minDisplayTime);
|
||||
});
|
||||
} else {
|
||||
// Fallback if fonts API not supported
|
||||
console.log("Fonts API not supported, using fallback timing");
|
||||
setTimeout(completeLoading, minDisplayTime + 300);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Determine initial theme first
|
||||
let initialTheme = "dark"; // Match Elm's hardcoded default
|
||||
const savedTheme = localStorage.getItem("app-theme");
|
||||
if (savedTheme) {
|
||||
initialTheme = savedTheme;
|
||||
} else if (window.matchMedia) {
|
||||
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
initialTheme = mediaQuery.matches ? "dark" : "light";
|
||||
}
|
||||
|
||||
// Store the determined initial theme
|
||||
localStorage.setItem("app-theme", initialTheme);
|
||||
|
||||
// Handle saving theme to localStorage AND toggle requests
|
||||
if (app.ports?.saveTheme?.subscribe) {
|
||||
app.ports.saveTheme.subscribe((themeOrSignal: unknown) => {
|
||||
if (themeOrSignal === "toggle") {
|
||||
// Handle toggle request - now we know localStorage has the current theme
|
||||
const currentTheme = localStorage.getItem("app-theme") || initialTheme;
|
||||
const newTheme = currentTheme === "light" ? "dark" : "light";
|
||||
console.log("Toggling theme from", currentTheme, "to", newTheme);
|
||||
localStorage.setItem("app-theme", newTheme);
|
||||
|
||||
// Send new theme back to Elm
|
||||
if (app.ports?.loadTheme?.send) {
|
||||
app.ports.loadTheme.send(newTheme);
|
||||
}
|
||||
} else {
|
||||
// Handle normal theme saving (when theme is set directly)
|
||||
console.log("Saving theme:", themeOrSignal);
|
||||
localStorage.setItem("app-theme", themeOrSignal as string);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Load theme from localStorage on startup
|
||||
if (app.ports?.loadTheme?.send) {
|
||||
console.log("Loading initial theme:", initialTheme);
|
||||
app.ports.loadTheme.send(initialTheme);
|
||||
}
|
||||
|
||||
// Optional: Listen for system theme changes
|
||||
if (window.matchMedia) {
|
||||
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
mediaQuery.addEventListener("change", (e) => {
|
||||
// Only apply if user hasn't manually saved a theme preference
|
||||
if (!savedTheme) {
|
||||
const systemTheme = e.matches ? "dark" : "light";
|
||||
console.log("System theme changed:", systemTheme);
|
||||
localStorage.setItem("app-theme", systemTheme);
|
||||
if (app.ports?.loadTheme?.send) {
|
||||
app.ports.loadTheme.send(systemTheme);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Type definitions for Elm Land
|
||||
namespace ElmLand {
|
||||
export type FlagsArgs = {
|
||||
env: Record<string, string>;
|
||||
};
|
||||
export type OnReadyArgs = {
|
||||
env: Record<string, string>;
|
||||
app: { ports?: Record<string, Port> };
|
||||
};
|
||||
export type Port = {
|
||||
send?: (data: unknown) => void;
|
||||
subscribe?: (callback: (data: unknown) => unknown) => void;
|
||||
};
|
||||
}
|
||||
3
templates/website/frontend/static/styles.css
Normal file
3
templates/website/frontend/static/styles.css
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
html {
|
||||
font-size: 100%;
|
||||
}
|
||||
52
templates/website/parts/config/devshells.nix
Executable file
52
templates/website/parts/config/devshells.nix
Executable file
|
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
{
|
||||
haskellProjects.default = {
|
||||
devShell = {
|
||||
enable = true;
|
||||
|
||||
tools = hp: {
|
||||
inherit (hp)
|
||||
cabal-fmt
|
||||
haskell-language-server
|
||||
;
|
||||
|
||||
inherit (pkgs)
|
||||
dhall
|
||||
dhall-json
|
||||
dhall-lsp-server
|
||||
helix-gpt
|
||||
age
|
||||
just
|
||||
nil
|
||||
nixd
|
||||
sops
|
||||
ssh-to-age
|
||||
nixfmt-rfc-style
|
||||
libz
|
||||
ngrep
|
||||
stripe-cli
|
||||
vscode-langservers-extracted
|
||||
zlib
|
||||
;
|
||||
inherit (pkgs.elmPackages)
|
||||
elm
|
||||
elm-format
|
||||
elm-land
|
||||
elm-language-server
|
||||
elm-review
|
||||
elm-test
|
||||
;
|
||||
inherit (pkgs.haskellPackages)
|
||||
nixfmt
|
||||
;
|
||||
};
|
||||
|
||||
hlsCheck.enable = true;
|
||||
mkShellArgs.shellHook = "${config.pre-commit.installationScript}";
|
||||
};
|
||||
};
|
||||
}
|
||||
4
templates/website/parts/config/packages.nix
Executable file
4
templates/website/parts/config/packages.nix
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
{ self, ... }:
|
||||
{
|
||||
packages.default = self.packages.example;
|
||||
}
|
||||
7
templates/website/parts/config/pre-commit.nix
Executable file
7
templates/website/parts/config/pre-commit.nix
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
pre-commit.settings.hooks = {
|
||||
nixfmt-rfc-style.enable = true;
|
||||
# commitizen.enable = true;
|
||||
statix.enable = true;
|
||||
};
|
||||
}
|
||||
14
templates/website/parts/default.nix
Executable file
14
templates/website/parts/default.nix
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
let
|
||||
configPath = ./config;
|
||||
|
||||
devshellImports =
|
||||
let
|
||||
files = builtins.attrNames (builtins.readDir configPath);
|
||||
in
|
||||
map (name: configPath + "/${name}") (
|
||||
builtins.filter (name: builtins.match ".*\\.nix$" name != null) files
|
||||
);
|
||||
in
|
||||
{
|
||||
imports = devshellImports;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue