diff options
Diffstat (limited to 'site/themes/sine')
21 files changed, 788 insertions, 0 deletions
diff --git a/site/themes/sine/README.md b/site/themes/sine/README.md new file mode 100644 index 0000000..12cbe06 --- /dev/null +++ b/site/themes/sine/README.md @@ -0,0 +1,4 @@ +# Hugo starter +Note: this is a fork of https://github.com/ericmurphyxyz/hugo-starter-theme. + +This is a barebones theme template to get you up and running really fast. If you're interested in creating your own hugo theme, I wrote something about that [here.](https://dev.to/vinliao/create-your-own-hugo-theme-from-scratch-5df9) diff --git a/site/themes/sine/archetypes/default.md b/site/themes/sine/archetypes/default.md new file mode 100644 index 0000000..fdccff8 --- /dev/null +++ b/site/themes/sine/archetypes/default.md @@ -0,0 +1,4 @@ +--- +title: "{{ replace .Name "-" " " | title }}" +date: {{ .Date }} +--- diff --git a/site/themes/sine/config.toml b/site/themes/sine/config.toml new file mode 100644 index 0000000..70ffb67 --- /dev/null +++ b/site/themes/sine/config.toml @@ -0,0 +1,17 @@ +[params.background] + spacing = 24 # distance between dots + maxRadius = 10 # max dot radius + baseOffset = 120 # baseline from bottom + freq = 0.008 # wave frequency (lower = wider waves) + speed = 0.01 # wave speed (lower = slower movement) + + # envelope controls (controls variance) + baseAmp = 100 + envelope1Freq = 0.002 + envelope1Amp = 120 + envelope2Freq = 0.0005 + envelope2Amp = 200 + +# Required for Chroma and the custom syntax highlighting. +[markup.highlight] + noClasses = false diff --git a/site/themes/sine/config/_default/hugo.toml b/site/themes/sine/config/_default/hugo.toml new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/site/themes/sine/config/_default/hugo.toml diff --git a/site/themes/sine/exampleSite/config.toml b/site/themes/sine/exampleSite/config.toml new file mode 100644 index 0000000..ff46f8e --- /dev/null +++ b/site/themes/sine/exampleSite/config.toml @@ -0,0 +1,15 @@ +baseURL = "https://example.com" +title = "Hugo template" + +[menu] + [[menu.main]] + identifier = "posts" + name = "Posts" + url = "/posts" + weight = 10 + + [[menu.main]] + identifier = "about" + name = "About" + url = "/about" + weight = 20 diff --git a/site/themes/sine/layouts/404.html b/site/themes/sine/layouts/404.html new file mode 100644 index 0000000..12883f1 --- /dev/null +++ b/site/themes/sine/layouts/404.html @@ -0,0 +1,5 @@ +{{ define "main" }} +<h1>Page Not Found</h1> + +<p>Sorry, this page doesn't exist.</p> +{{ end }} diff --git a/site/themes/sine/layouts/_default/baseof.html b/site/themes/sine/layouts/_default/baseof.html new file mode 100644 index 0000000..89f10a8 --- /dev/null +++ b/site/themes/sine/layouts/_default/baseof.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html data-theme="dark"> + <head> + {{- partial "head.html" . -}} + </head> + <body> + + <canvas id="background"></canvas> + + <div id="main"> + {{- partial "nav.html" . -}} + <div id="content"> + {{- block "main" . }}{{- end }} + <footer> + {{- partial "footer.html" . -}} + </footer> + </div> + </div> + + <!-- Background --> + <script id="background-config" type="application/json"> + {{ site.Params.background | jsonify | safeJS }} + </script> + <script src="{{ "/js/background.js" | relURL }}"></script> + + <!-- Theme Switcher --> + <script src="{{ "/js/switch-theme.js" | relURL }}"></script> + + <body> +</html> diff --git a/site/themes/sine/layouts/_default/list.html b/site/themes/sine/layouts/_default/list.html new file mode 100644 index 0000000..c51e7d6 --- /dev/null +++ b/site/themes/sine/layouts/_default/list.html @@ -0,0 +1,16 @@ +{{ define "main" }} +<h1>{{ .Title }}</h1> + +{{- .Content -}} + +{{ range.Data.Pages }} +<article class="post-snippet"> + <h3> + <a href="{{ .RelPermalink }}">{{ .Title }}</a> + </h3> + <time datetime="{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}"> + {{ .Date.Format "January 2, 2006" }} + </time> +</article> +{{ end }} +{{ end }} diff --git a/site/themes/sine/layouts/_default/single.html b/site/themes/sine/layouts/_default/single.html new file mode 100644 index 0000000..3ba2777 --- /dev/null +++ b/site/themes/sine/layouts/_default/single.html @@ -0,0 +1,7 @@ +{{ define "main" }} + +<h1>{{ .Title }}</h1> + +{{- .Content -}} + +{{ end }} diff --git a/site/themes/sine/layouts/index.html b/site/themes/sine/layouts/index.html new file mode 100644 index 0000000..2acde8d --- /dev/null +++ b/site/themes/sine/layouts/index.html @@ -0,0 +1,4 @@ +{{ define "main" }} + {{- .Content -}} + <p>{{ .Site.Params.description }}</p> +{{ end }} diff --git a/site/themes/sine/layouts/partials/footer.html b/site/themes/sine/layouts/partials/footer.html new file mode 100644 index 0000000..24373ca --- /dev/null +++ b/site/themes/sine/layouts/partials/footer.html @@ -0,0 +1 @@ +<p>©{{ dateFormat "2006" now }} {{ .Site.Title }}</p> diff --git a/site/themes/sine/layouts/partials/head.html b/site/themes/sine/layouts/partials/head.html new file mode 100644 index 0000000..e7c23e5 --- /dev/null +++ b/site/themes/sine/layouts/partials/head.html @@ -0,0 +1,36 @@ +<meta charset="UTF-8" /> +<meta name="viewport" content="width=device-width, initial-scale=1.0" /> + +<title>{{ if not .IsHome }}{{ .Title }} | {{ end }}{{ .Site.Title }}</title> + +<!-- Scuffed fix for theme change flash --> +<script> + // Run as early as possible + (function() { + const theme = localStorage.getItem("theme"); + const preloadClass = theme === "dark" ? "preload-dark" : "preload-light"; + + // Add preload class to <html> + document.documentElement.classList.add(preloadClass); + + // Wait for stylesheet(s) to load, then remove class + window.addEventListener("load", function() { + document.documentElement.classList.remove(preloadClass); + }); + })(); +</script> +<style> + /* Temporary background colors before stylesheet is fully loaded */ + .preload-light * { + background: #ffffff !important; + } + .preload-dark * { + background: #161616 !important; + } +</style> + +<link rel="stylesheet" href="/css/style.css" type="text/css" media="all" /> + +{{ with .OutputFormats.Get "rss" -}} + {{ printf `<link rel="%s" type="%s" href="%s" title="%s" />` .Rel .MediaType.Type .Permalink $.Site.Title | safeHTML }} +{{ end -}} diff --git a/site/themes/sine/layouts/partials/header.html b/site/themes/sine/layouts/partials/header.html new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/site/themes/sine/layouts/partials/header.html diff --git a/site/themes/sine/layouts/partials/nav.html b/site/themes/sine/layouts/partials/nav.html new file mode 100644 index 0000000..efd7e5b --- /dev/null +++ b/site/themes/sine/layouts/partials/nav.html @@ -0,0 +1,15 @@ +<header class="site-header"> + <nav class="navbar"> + <div id="logoContainer"> + <a class="logo" href="{{ .Site.BaseURL }}">{{- .Site.Title -}}</a> + <button type="button" id="toggleTheme" data-theme-toggle aria-label="switch theme"></button> + </div> + <ul class="nav-links"> + {{ range.Site.Menus.main }} + <li> + <a href="{{ .URL }}">{{ .Name }}</a> + </li> + {{ end }} + </ul> + </nav> +</header> diff --git a/site/themes/sine/static/css/style.css b/site/themes/sine/static/css/style.css new file mode 100644 index 0000000..c14e227 --- /dev/null +++ b/site/themes/sine/static/css/style.css @@ -0,0 +1,186 @@ +/* COLORS */ +@import url('themes/oxocarbon-light.css'); +@import url('themes/oxocarbon-dark.css'); + +#toggleTheme { + font-family: "kirsch"; + font-size: 2rem; + color: var(--fg); + border: none; + background: none; + cursor: pointer; + position: relative; + top: 2px; + margin: -4px 2px; +} + +#logoContainer { + padding-right: 4px; +} + +/* FONT */ + +@font-face { + font-family: "kirsch"; + src: + local("kirsch"), + url("https://cdn.jsdelivr.net/npm/kirsch@latest/out/kirsch.woff2") format("woff2"), + url("https://cdn.jsdelivr.net/npm/kirsch@latest/out/kirsch.ttf") format("truetype"); + font-display: block; +} + +/* LAYOUT */ + +body { + color: var(--fg); + background-color: transparent; + font-size: 175%; + line-height: 1.2; + max-width: 45rem; + padding: 1rem; + margin: 0 auto; + font-family: "kirsch"; + font-display: block; +} + +#main { + margin: 2% auto; + display: flex; + flex-direction: column; + justify-content: center; +} + +#content { + border-style: solid; + border-color: var(--fg); + background-color: var(--bg); + + padding: 3% 5%; + overflow: auto; +} + +/* NAVIGATION */ + +.navbar { + background-color: var(--bg); + border-style: dashed; + border-color: var(--fg); + + font-size: 110%; + + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + max-width: 1200px; + margin: 0 auto; + padding: 10px 20px; + box-sizing: border-box; + + margin-bottom: 2%; +} + +.logo { + flex-shrink: 0; + /* margin: 0 0%; */ +} + +.nav-links { + list-style-type: none; + display: flex; + gap: 20px; + flex-shrink: 0; + /* overflow-x: auto; */ + overflow: visible; + margin: 0; + padding: 0; +} + +.navbar a { + display: inline-block; + white-space: nowrap; + flex-shrink: 0; + + color: var(--fg); + font-weight: bold; + text-decoration: none; +} + +@media (max-width: 768px) { + .nav-links { + gap: 10px; + } +} + +@media (max-width: 480px) { + .nav-links a { + font-size: 14px; + } +} +.main-menu { + display: flex; + list-style: none; + margin: 0; + padding: 0; +} + +@media screen and (max-width: 48rem) { + .site-nav, + .main-menu { + flex-direction: column; + } + + .site-nav a { + padding: 0.5rem; + padding-left: 0; + } +} + +/* Canvas Background */ +#background { + position: fixed; + inset: 0; /* stretch full screen */ + z-index: -1; /* behind content */ + pointer-events: none; /* don’t block clicks */ + display: block; /* remove inline-gap issues */ + + background-color: var(--bg); +} + +/* SINGLES */ +#content * { + margin: 14px 0; +} + +#content h1 { + margin: 0; + text-align: center; +} + +#content ul { + list-style-type: square; +} + +#content li { + margin: 0; +} + +#content a { + color: var(--base0B); +} + +#content a:visited { + color: var(--base0E); +} + +#content footer { + margin-bottom: 0; + text-align: center; +} + +#content footer p { + margin-bottom: 0; +} + +/* SYNTAX HIGHLIGHTING */ +@import url('syntax.css'); diff --git a/site/themes/sine/static/css/syntax-old.css b/site/themes/sine/static/css/syntax-old.css new file mode 100644 index 0000000..5f5478f --- /dev/null +++ b/site/themes/sine/static/css/syntax-old.css @@ -0,0 +1,88 @@ +/* Generated using: hugo gen chromastyles --style=monokai */ + +/* Background */ .bg { color:#f8f8f2;background-color:#272822; } +/* PreWrapper */ .chroma { color:#f8f8f2;background-color:#272822; } +/* Other */ .chroma .x { } +/* Error */ .chroma .err { color:#960050;background-color:#1e0010 } +/* CodeLine */ .chroma .cl { } +/* LineLink */ .chroma .lnlinks { outline:none;text-decoration:none;color:inherit } +/* LineTableTD */ .chroma .lntd { vertical-align:top;padding:0;margin:0;border:0; } +/* LineTable */ .chroma .lntable { border-spacing:0;padding:0;margin:0;border:0; } +/* LineHighlight */ .chroma .hl { background-color:#3c3d38 } +/* LineNumbersTable */ .chroma .lnt { white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f } +/* LineNumbers */ .chroma .ln { white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f } +/* Line */ .chroma .line { display:flex; } +/* Keyword */ .chroma .k { color:#66d9ef } +/* KeywordConstant */ .chroma .kc { color:#66d9ef } +/* KeywordDeclaration */ .chroma .kd { color:#66d9ef } +/* KeywordNamespace */ .chroma .kn { color:#f92672 } +/* KeywordPseudo */ .chroma .kp { color:#66d9ef } +/* KeywordReserved */ .chroma .kr { color:#66d9ef } +/* KeywordType */ .chroma .kt { color:#66d9ef } +/* Name */ .chroma .n { } +/* NameAttribute */ .chroma .na { color:#a6e22e } +/* NameClass */ .chroma .nc { color:#a6e22e } +/* NameConstant */ .chroma .no { color:#66d9ef } +/* NameDecorator */ .chroma .nd { color:#a6e22e } +/* NameEntity */ .chroma .ni { } +/* NameException */ .chroma .ne { color:#a6e22e } +/* NameLabel */ .chroma .nl { } +/* NameNamespace */ .chroma .nn { } +/* NameOther */ .chroma .nx { color:#a6e22e } +/* NameProperty */ .chroma .py { } +/* NameTag */ .chroma .nt { color:#f92672 } +/* NameBuiltin */ .chroma .nb { } +/* NameBuiltinPseudo */ .chroma .bp { } +/* NameVariable */ .chroma .nv { } +/* NameVariableClass */ .chroma .vc { } +/* NameVariableGlobal */ .chroma .vg { } +/* NameVariableInstance */ .chroma .vi { } +/* NameVariableMagic */ .chroma .vm { } +/* NameFunction */ .chroma .nf { color:#a6e22e } +/* NameFunctionMagic */ .chroma .fm { color:#a6e22e } +/* Literal */ .chroma .l { color:#ae81ff } +/* LiteralDate */ .chroma .ld { color:#e6db74 } +/* LiteralString */ .chroma .s { color:#e6db74 } +/* LiteralStringAffix */ .chroma .sa { color:#e6db74 } +/* LiteralStringBacktick */ .chroma .sb { color:#e6db74 } +/* LiteralStringChar */ .chroma .sc { color:#e6db74 } +/* LiteralStringDelimiter */ .chroma .dl { color:#e6db74 } +/* LiteralStringDoc */ .chroma .sd { color:#e6db74 } +/* LiteralStringDouble */ .chroma .s2 { color:#e6db74 } +/* LiteralStringEscape */ .chroma .se { color:#ae81ff } +/* LiteralStringHeredoc */ .chroma .sh { color:#e6db74 } +/* LiteralStringInterpol */ .chroma .si { color:#e6db74 } +/* LiteralStringOther */ .chroma .sx { color:#e6db74 } +/* LiteralStringRegex */ .chroma .sr { color:#e6db74 } +/* LiteralStringSingle */ .chroma .s1 { color:#e6db74 } +/* LiteralStringSymbol */ .chroma .ss { color:#e6db74 } +/* LiteralNumber */ .chroma .m { color:#ae81ff } +/* LiteralNumberBin */ .chroma .mb { color:#ae81ff } +/* LiteralNumberFloat */ .chroma .mf { color:#ae81ff } +/* LiteralNumberHex */ .chroma .mh { color:#ae81ff } +/* LiteralNumberInteger */ .chroma .mi { color:#ae81ff } +/* LiteralNumberIntegerLong */ .chroma .il { color:#ae81ff } +/* LiteralNumberOct */ .chroma .mo { color:#ae81ff } +/* Operator */ .chroma .o { color:#f92672 } +/* OperatorWord */ .chroma .ow { color:#f92672 } +/* Punctuation */ .chroma .p { } +/* Comment */ .chroma .c { color:#75715e } +/* CommentHashbang */ .chroma .ch { color:#75715e } +/* CommentMultiline */ .chroma .cm { color:#75715e } +/* CommentSingle */ .chroma .c1 { color:#75715e } +/* CommentSpecial */ .chroma .cs { color:#75715e } +/* CommentPreproc */ .chroma .cp { color:#75715e } +/* CommentPreprocFile */ .chroma .cpf { color:#75715e } +/* Generic */ .chroma .g { } +/* GenericDeleted */ .chroma .gd { color:#f92672 } +/* GenericEmph */ .chroma .ge { font-style:italic } +/* GenericError */ .chroma .gr { } +/* GenericHeading */ .chroma .gh { } +/* GenericInserted */ .chroma .gi { color:#a6e22e } +/* GenericOutput */ .chroma .go { } +/* GenericPrompt */ .chroma .gp { } +/* GenericStrong */ .chroma .gs { font-weight:bold } +/* GenericSubheading */ .chroma .gu { color:#75715e } +/* GenericTraceback */ .chroma .gt { } +/* GenericUnderline */ .chroma .gl { } +/* TextWhitespace */ .chroma .w { } diff --git a/site/themes/sine/static/css/syntax.css b/site/themes/sine/static/css/syntax.css new file mode 100644 index 0000000..ceb4317 --- /dev/null +++ b/site/themes/sine/static/css/syntax.css @@ -0,0 +1,146 @@ +/* Converted to Base16 variables */ + +/* Background */ +.bg { color: var(--base05); background-color: var(--base00); } + +/* PreWrapper */ +.chroma { color: var(--base05); background-color: var(--base00); } + +/* Other */ +.chroma .x { } + +/* Error */ +.chroma .err { color: var(--base08); background-color: var(--base0F); } + +/* CodeLine */ +.chroma .cl { } + +/* LineLink */ +.chroma .lnlinks { outline:none; text-decoration:none; color:inherit } + +/* LineTableTD */ +.chroma .lntd { vertical-align:top; padding:0; margin:0; border:0; } + +/* LineTable */ +.chroma .lntable { border-spacing:0; padding:0; margin:0; border:0; } + +/* LineHighlight */ +.chroma .hl { background-color: var(--base02); } + +/* LineNumbersTable */ +.chroma .lnt { + white-space:pre; + -webkit-user-select:none; + user-select:none; + margin-right:0.4em; + padding:0 0.4em 0 0.4em; + color: var(--base03); +} + +/* LineNumbers */ +.chroma .ln { + white-space:pre; + -webkit-user-select:none; + user-select:none; + margin-right:0.4em; + padding:0 0.4em 0 0.4em; + color: var(--base03); +} + +/* Line */ +.chroma .line { display:flex; } + +/* Keyword */ +.chroma .k, +.chroma .kc, +.chroma .kd, +.chroma .kp, +.chroma .kr, +.chroma .kt { color: var(--base0E); } + +/* KeywordNamespace */ +.chroma .kn { color: var(--base08); } + +/* Name */ +.chroma .n { } + +/* NameAttribute */ +.chroma .na, +.chroma .nc, +.chroma .nd, +.chroma .ne, +.chroma .nx, +.chroma .nf, +.chroma .fm { color: var(--base0D); } + +/* NameConstant */ +.chroma .no { color: var(--base09); } + +/* NameTag */ +.chroma .nt { color: var(--base08); } + +/* Literal */ +.chroma .l, +.chroma .m, +.chroma .mb, +.chroma .mf, +.chroma .mh, +.chroma .mi, +.chroma .il, +.chroma .mo { color: var(--base09); } + +/* LiteralDate */ +.chroma .ld, +.chroma .s, +.chroma .sa, +.chroma .sb, +.chroma .sc, +.chroma .dl, +.chroma .sd, +.chroma .s2, +.chroma .sh, +.chroma .si, +.chroma .sx, +.chroma .sr, +.chroma .s1, +.chroma .ss { color: var(--base0B); } + +/* LiteralStringEscape */ +.chroma .se { color: var(--base0C); } + +/* Operator */ +.chroma .o, +.chroma .ow { color: var(--base08); } + +/* Comment */ +.chroma .c, +.chroma .ch, +.chroma .cm, +.chroma .c1, +.chroma .cs, +.chroma .cp, +.chroma .cpf { color: var(--base03); } + +/* GenericDeleted */ +.chroma .gd { color: var(--base08); } + +/* GenericEmph */ +.chroma .ge { font-style:italic } + +/* GenericInserted */ +.chroma .gi { color: var(--base0B); } + +/* GenericStrong */ +.chroma .gs { font-weight:bold } + +/* GenericSubheading */ +.chroma .gu { color: var(--base03); } + +/* GenericHeading, Output, Prompt, Traceback, etc. left unstyled */ +.chroma .gr, +.chroma .gh, +.chroma .go, +.chroma .gp, +.chroma .gt, +.chroma .gl, +.chroma .w { } diff --git a/site/themes/sine/static/css/themes/oxocarbon-dark.css b/site/themes/sine/static/css/themes/oxocarbon-dark.css new file mode 100644 index 0000000..3283009 --- /dev/null +++ b/site/themes/sine/static/css/themes/oxocarbon-dark.css @@ -0,0 +1,22 @@ +/* COLORS */ +[data-theme="dark"] { + --base00: #161616; + --base01: #262626; + --base02: #393939; + --base03: #525252; + --base04: #dde1e6; + --base05: #f2f4f8; + --base06: #ffffff; + --base07: #08bdba; + --base08: #3ddbd9; + --base09: #78a9ff; + --base0A: #ee5396; + --base0B: #33b1ff; + --base0C: #ff7eb6; + --base0D: #42be65; + --base0E: #be95ff; + --base0F: #82cfff; + + --fg: var(--base06); + --bg: var(--base00); +} diff --git a/site/themes/sine/static/css/themes/oxocarbon-light.css b/site/themes/sine/static/css/themes/oxocarbon-light.css new file mode 100644 index 0000000..7cd48ee --- /dev/null +++ b/site/themes/sine/static/css/themes/oxocarbon-light.css @@ -0,0 +1,22 @@ +/* COLORS */ +[data-theme="light"] { + --base00: #ffffff; + --base01: #f2f2f2; + --base02: #d0d0d0; + --base03: #161616; + --base04: #37474f; + --base05: #90a4ae; + --base06: #525252; + --base07: #08bdba; + --base08: #ff7eb6; + --base09: #ee5396; + --base0A: #FF6F00; + --base0B: #0f62fe; + --base0C: #673ab7; + --base0D: #42be65; + --base0E: #be95ff; + --base0F: #ffab91; + + --fg: var(--base03); + --bg: var(--base00); +} diff --git a/site/themes/sine/static/js/background.js b/site/themes/sine/static/js/background.js new file mode 100644 index 0000000..e9b61a2 --- /dev/null +++ b/site/themes/sine/static/js/background.js @@ -0,0 +1,82 @@ +document.addEventListener("DOMContentLoaded", () => { + const canvas = document.getElementById("background"); + if (!canvas) return; + const ctx = canvas.getContext("2d"); + + // Grab config from the embedded <script> + const configEl = document.getElementById("background-config"); + const config = configEl ? JSON.parse(configEl.textContent) : {}; + + // Use config values with defaults as fallback + const spacing = config.spacing ?? 24; + const maxRadius = config.maxRadius ?? 8; + const baseOffset = config.baseOffset ?? 120; + const freq = config.freq ?? 0.008; + const speed = config.speed ?? 0.02; + + const baseAmp = config.baseAmp ?? 100; + const env1Freq = config.envelope1Freq ?? 0.002; + const env1Amp = config.envelope1Amp ?? 120; + const env2Freq = config.envelope2Freq ?? 0.0005; + const env2Amp = config.envelope2Amp ?? 200; + + let t = parseFloat(localStorage.getItem("waveProgress")) || 0; + let widthCss = window.innerWidth; + let heightCss = window.innerHeight; + let pixelRatio = window.devicePixelRatio || 1; + + function resize() { + widthCss = window.innerWidth; + heightCss = window.innerHeight; + pixelRatio = window.devicePixelRatio || 1; + + canvas.width = Math.floor(widthCss * pixelRatio); + canvas.height = Math.floor(heightCss * pixelRatio); + canvas.style.width = widthCss + "px"; + canvas.style.height = heightCss + "px"; + ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); + } + window.addEventListener("resize", resize); + resize(); + + function draw() { + const styles = getComputedStyle(document.documentElement); + const fg = styles.getPropertyValue("--fg").trim(); + + ctx.clearRect(0, 0, widthCss, heightCss); + ctx.fillStyle = fg; + + for (let x = 0; x <= widthCss + spacing; x += spacing) { + // envelope: controls crest variance + const envelope = + baseAmp + + Math.sin(x * env1Freq + t * 0.1) * env1Amp + + Math.sin(x * env2Freq + t * 0.05) * env2Amp; + + const waveY = heightCss - (Math.sin(x * freq + t) * envelope + baseOffset); + // const waveY = Math.max(heightCss - 50, heightCss - (Math.sin(x * freq + t) * envelope + baseOffset)); + + for (let y = heightCss; y >= 0; y -= spacing) { + const dist = Math.max(0, y - waveY); + const radius = Math.min(maxRadius, dist / 40); + if (radius > 0.2) { + ctx.beginPath(); + // ctx.arc(x + spacing / 2, y - spacing / 2, radius, 0, Math.PI * 2); + ctx.fillRect( + x + spacing / 2 - radius, + y - spacing / 2 - radius, + radius * 2, + radius * 2 + ); + ctx.fill(); + } + } + } + + t += speed; + localStorage.setItem("waveProgress", t); + requestAnimationFrame(draw); + } + + draw(); +}); diff --git a/site/themes/sine/static/js/switch-theme.js b/site/themes/sine/static/js/switch-theme.js new file mode 100644 index 0000000..5052f39 --- /dev/null +++ b/site/themes/sine/static/js/switch-theme.js @@ -0,0 +1,88 @@ +// const root = document.documentElement; // <html>, not <body> +// const btn = document.getElementById("toggleTheme"); +// +// const savedTheme = localStorage.getItem("theme") || "light"; +// root.className = savedTheme; +// btn.innerHTML = savedTheme === "dark" ? "✧" : "☾"; +// +// btn.addEventListener("click", () => { +// const newTheme = root.classList.contains("light") ? "dark" : "light"; +// root.className = newTheme; +// localStorage.setItem("theme", newTheme); +// btn.innerHTML = newTheme === "dark" ? "✧" : "☾"; +// }); + +/** +* Utility function to calculate the current theme setting. +* Look for a local storage value. +* Fall back to system setting. +* Fall back to light mode. +*/ +function calculateSettingAsThemeString({ localStorageTheme, systemSettingDark }) { + if (localStorageTheme !== null) { + return localStorageTheme; + } + + if (systemSettingDark.matches) { + return "dark"; + } + + return "light"; +} + +/** +* Utility function to update the button text and aria-label. +*/ +function updateButton({ buttonEl, isDark }) { + const newCta = isDark ? "Change to light theme" : "Change to dark theme"; + + const newInnerText = isDark ? "✧" : "☾"; + // use an aria-label if you are omitting text on the button + // and using a sun/moon icon, for example + buttonEl.setAttribute("aria-label", newCta); + buttonEl.innerText = newInnerText; +} + +/** +* Utility function to update the theme setting on the html tag +*/ +function updateThemeOnHtmlEl({ theme }) { + document.querySelector("html").setAttribute("data-theme", theme); +} + + +/** +* On page load: +*/ + +/** +* 1. Grab what we need from the DOM and system settings on page load +*/ +const button = document.querySelector("[data-theme-toggle]"); +const localStorageTheme = localStorage.getItem("theme"); +const systemSettingDark = window.matchMedia("(prefers-color-scheme: dark)"); + +/** +* 2. Work out the current site settings +*/ +let currentThemeSetting = calculateSettingAsThemeString({ localStorageTheme, systemSettingDark }); + +/** +* 3. Update the theme setting and button text accoridng to current settings +*/ +updateButton({ buttonEl: button, isDark: currentThemeSetting === "dark" }); +updateThemeOnHtmlEl({ theme: currentThemeSetting }); + +/** +* 4. Add an event listener to toggle the theme +*/ +button.addEventListener("click", (event) => { + const newTheme = currentThemeSetting === "dark" ? "light" : "dark"; + + localStorage.setItem("theme", newTheme); + updateButton({ buttonEl: button, isDark: newTheme === "dark" }); + updateThemeOnHtmlEl({ theme: newTheme }); + + currentThemeSetting = newTheme; +}); + |
