summaryrefslogtreecommitdiff
path: root/layouts/_default
diff options
context:
space:
mode:
authorleiyu3 <s444814187@gmail.com>2025-07-17 11:47:55 -0400
committerleiyu3 <s444814187@gmail.com>2025-07-17 11:47:55 -0400
commit6758a1a26de82a6dc3661db880513cba75f01110 (patch)
treecaf67546bd0113f434ca3ae65b4bc9b854b2878e /layouts/_default
downloadletsworship-6758a1a26de82a6dc3661db880513cba75f01110.tar.gz
letsworship-6758a1a26de82a6dc3661db880513cba75f01110.zip
init commit
Diffstat (limited to 'layouts/_default')
-rw-r--r--layouts/_default/baseof.html138
-rw-r--r--layouts/_default/home.html71
-rw-r--r--layouts/_default/single.html74
3 files changed, 283 insertions, 0 deletions
diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html
new file mode 100644
index 0000000..d8fafb6
--- /dev/null
+++ b/layouts/_default/baseof.html
@@ -0,0 +1,138 @@
1<!DOCTYPE html>
2<html lang="{{ or site.Language.LanguageCode site.Language.Lang }}"
3 dir="{{ or site.Language.LanguageDirection `ltr` }}">
4
5 <head>
6 {{ partial "head.html" . }}
7 </head>
8
9 {{ $theme := "auto"}}
10
11 {{ with .Param "theme" }}
12 {{ $theme = .}}
13 {{ end }}
14
15 <body class="{{ $theme }}">
16
17 <div class="content">
18 <header>
19 <h1 class="center">
20 <a class="hover-underline" href="/">{{ .Site.Title }}</a>
21 </h1>
22 <hr>
23 </header>
24
25 <main class="main">
26
27 {{ block "main" . }}{{ end }}
28 </main>
29 </div>
30
31 </body>
32
33 <script>
34
35 function isAuto() {
36 return document.body.classList.contains("auto");
37 }
38
39 function setTheme() {
40 if (!isAuto()) {
41 return
42 }
43
44 document.body.classList.remove("auto");
45 let cls = "light";
46 if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
47 cls = "dark";
48 }
49
50 document.body.classList.add(cls);
51 }
52
53 function invertBody() {
54 document.body.classList.toggle("dark");
55 document.body.classList.toggle("light");
56 }
57
58 if (isAuto()) {
59 window.matchMedia('(prefers-color-scheme: dark)').addListener(invertBody);
60 }
61
62 setTheme();
63
64
65</script>
66
67
68{{ if .HasShortcode "chords" }}
69<script>
70document.addEventListener("DOMContentLoaded", () => {
71 const semitones = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
72 const flatToSharp = { 'Db': 'C#', 'Eb': 'D#', 'Gb': 'F#', 'Ab': 'G#', 'Bb': 'A#' };
73
74 function normalize(note) {
75 return flatToSharp[note] || note;
76 }
77
78 function transposeNote(note, shift) {
79 note = normalize(note);
80 const i = semitones.indexOf(note);
81 return i === -1 ? note : semitones[(i + shift + 12) % 12];
82 }
83
84 function transposeChord(fullChord, shift) {
85 const match = fullChord.match(/^([A-G][#b]?)([^\/]*)(?:\/([A-G][#b]?))?$/);
86 if (!match) return fullChord;
87 let [, root, suffix, bass] = match;
88 const transposedRoot = transposeNote(root, shift);
89 const transposedBass = bass ? transposeNote(bass, shift) : null;
90 return transposedRoot + suffix + (transposedBass ? `/${transposedBass}` : '');
91 }
92
93 function renderChords() {
94 const pattern = /\[([A-G][#b]?[^ \[\]]*)\]/g;
95 document.querySelectorAll('.chord-line').forEach(line => {
96 line.innerHTML = line.innerHTML.replace(pattern, (_, chord) => {
97 return `<span class="chord-anchor"><span class="chord" data-original="${chord}">${chord}</span></span>`;
98 });
99 });
100 }
101
102 function transposeToKey(fromKey, toKey) {
103 const fromIndex = semitones.indexOf(normalize(fromKey));
104 const toIndex = semitones.indexOf(normalize(toKey));
105 const shift = fromIndex === -1 || toIndex === -1 ? 0 : (toIndex - fromIndex + 12) % 12;
106
107 document.querySelectorAll('.chord').forEach(el => {
108 const original = el.dataset.original;
109 el.textContent = transposeChord(original, shift);
110 });
111 }
112
113 // Init
114 renderChords();
115
116 const selector = document.getElementById('key-selector');
117 const originalKey = selector?.dataset.originalKey || 'C';
118
119 // Trigger initial transpose to match the default selected key
120 transposeToKey(originalKey, selector.value);
121
122 selector?.addEventListener("change", () => {
123 transposeToKey(originalKey, selector.value);
124 });
125});
126
127document.addEventListener("DOMContentLoaded", () => {
128 const toggle = document.getElementById("toggle-chords");
129
130 toggle?.addEventListener("change", () => {
131 document.body.classList.toggle("hide-chords", !toggle.checked);
132 });
133});
134</script>
135{{ end }}
136
137
138</html> \ No newline at end of file
diff --git a/layouts/_default/home.html b/layouts/_default/home.html
new file mode 100644
index 0000000..17f4249
--- /dev/null
+++ b/layouts/_default/home.html
@@ -0,0 +1,71 @@
1{{ define "main" }}
2<script>
3 document.addEventListener("DOMContentLoaded", () => {
4 for (const e of document.getElementsByClassName("js-only")) {
5 e.classList.remove("js-only");
6 }
7
8 const songs = document.querySelectorAll("li");
9 const search = document.getElementById("search");
10 const songlist = document.getElementById("song-list");
11
12 const normalize = str => str.normalize('NFD').replace(/\p{Diacritic}/gu, "");
13
14 search.addEventListener("input", () => {
15 const searchText = search.value.toLowerCase().trim();
16 const searchTerms = normalize(searchText).split(" ");
17 const hasFilter = searchText.length > 0;
18 songlist.classList.toggle("list-searched", hasFilter);
19
20 songs.forEach(song => {
21 const songText = normalize(`${song.textContent} ${song.dataset.alias}`).toLowerCase();
22 const isMatch = searchTerms.every(term => songText.includes(term));
23 song.hidden = !isMatch;
24 });
25 });
26
27 const clearSearch = document.getElementById("clear-search");
28 clearSearch.addEventListener("click", () => {
29 search.value = "";
30 songs.forEach(song => {
31 song.hidden = false;
32 });
33 songlist.classList.remove("list-searched");
34 });
35 });
36</script>
37
38<div class="list-container">
39 {{ .Content }}
40
41 {{ $tagsPage := eq .Title "Tags"}}
42
43 <h2 class="center">What do you want to sing?</h2>
44 <div class="search-bar-container">
45 <div class="search-wrapper">
46 <input type="text" id="search" class="search-bar" placeholder="Search ALL Songs...">
47 <button id="clear-search" class="js-only">
48 <svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512">
49 <title>Backspace</title>
50 <path
51 d="M135.19 390.14a28.79 28.79 0 0021.68 9.86h246.26A29 29 0 00432 371.13V140.87A29 29 0 00403.13 112H156.87a28.84 28.84 0 00-21.67 9.84v0L46.33 256l88.86 134.11z"
52 fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"></path>
53 <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"
54 d="M336.67 192.33L206.66 322.34M336.67 322.34L206.66 192.33M336.67 192.33L206.66 322.34M336.67 322.34L206.66 192.33">
55 </path>
56 </svg></button>
57 </div>
58 </div>
59
60 <ul id="song-list">
61 {{ range .Pages }}
62 <li data-alias={{ if .Params.alias }}{{ .Params.alias }}{{ else }}{{ .Params.title }}{{ end }}>
63 <a href="{{ .RelPermalink }}">
64 {{ .Title }}
65 </a>
66 </li>
67 {{ end }}
68 </ul>
69
70</div>
71{{ end }} \ No newline at end of file
diff --git a/layouts/_default/single.html b/layouts/_default/single.html
new file mode 100644
index 0000000..38cf763
--- /dev/null
+++ b/layouts/_default/single.html
@@ -0,0 +1,74 @@
1{{ define "main" }}
2
3{{/* Breadcrumbs */}}
4
5<div {{ if .Param "autonumber" }} class="autonumber" {{ end }}>
6
7 <div class="single-intro-container">
8
9 {{/* Title and Summary */}}
10
11 <h2 class="single-title">{{ .Title }}</h2>
12 {{ if .Param "author" }}
13 <p>By: {{ .Param "author" }}</p>
14 {{ end }}
15
16 <div class="controls">
17 <div>
18 <label class="chord-toggle">
19 <input type="checkbox" id="toggle-chords" checked>
20 <span class="slider"></span>
21 <span class="label-text">Show Chords</span>
22 </label>
23 </div>
24
25 <div >
26 <label for="key-selector">Key:</label>
27 <select id="key-selector" data-original-key="{{ with .Params.key }}{{ . }}{{ else }}C{{ end }}">
28 {{ $allKeys := slice "C" "C#/Db" "D" "D#/Eb" "E" "F" "F#/Gb" "G" "G#/Ab" "A" "A#/Bb" "B" }}
29 {{ $currentKey := .Params.key | default "C" }}
30 {{ range $k := $allKeys }}
31 {{ $cleanKey := (index (split $k "/") 0) }}
32 <option value="{{ $cleanKey }}" {{ if in $currentKey $k }}selected{{ end }}>
33 {{ $k }}
34 </option>
35 {{ end }}
36 </select>
37 </div>
38 </div>
39
40 </div>
41
42 {{ if .Param "showTags" }}
43
44 {{ $taxonomy := "tags" }}
45 {{ with .Param $taxonomy }}
46
47 <div class="single-tags">
48 {{ range $index, $tag := . }}
49 {{ with $.Site.GetPage (printf "/%s/%s" $taxonomy $tag) -}}
50 <span>
51 <a href="{{ .Permalink }}">#{{ .LinkTitle }}</a>
52 </span>
53 {{ end }}
54 {{ end }}
55 </div>
56
57 {{ end }}
58 {{ end }}
59
60 {{/* Page content */}}
61
62 <div class="single-content">
63 {{ .Content }}
64 </div>
65
66 {{/* Back to top */}}
67 <div class="back-to-top">
68 <a href="#top">
69 back to top
70 </a>
71 </div>
72</div>
73
74{{ end }} \ No newline at end of file