Settings refactor / add birb

This commit is contained in:
2026-05-13 12:30:45 -05:00
parent e728ddac2c
commit 82f47093a7
13 changed files with 192 additions and 74 deletions

17
_includes/birb.njk Normal file
View File

@@ -0,0 +1,17 @@
<!-- Birb -->
<script>
const showBirb = () => {
script = document.createElement('script');
script.setAttribute("src", "https://cdn.jsdelivr.net/gh/IdreesInc/Pocket-Bird@main/dist/web/birb.embed.js");
document.body.appendChild(script);
};
const hideBirb = () => {
window.location.reload();
};
const noBirb = () => {
console.info("Settings: Not showing birb :[");
}
</script>
<!-- /Birb -->

View File

@@ -17,6 +17,6 @@
<a href="https://notbyai.fyi/"> <a href="https://notbyai.fyi/">
<img src="/img/written-by-human-not-by-ai-white.svg" alt="Written by humans, not by AI."> <img src="/img/written-by-human-not-by-ai-white.svg" alt="Written by humans, not by AI.">
</a> </a>
{% include "siteSettings.njk" %} {% include "settings/siteSettings.njk" %}
</div> </div>
</footer> </footer>

View File

@@ -52,6 +52,7 @@
<link rel="stylesheet" href="/pagefind/pagefind-ui.css"> <link rel="stylesheet" href="/pagefind/pagefind-ui.css">
<link rel="stylesheet" type="text/css" href="/css/search.css" /> <link rel="stylesheet" type="text/css" href="/css/search.css" />
{% endif %} {% endif %}
<script src="/js/main.js"></script>
<!-- Mochi webmentions --> <!-- Mochi webmentions -->
<link rel="webmention" href="https://mochi-webmentions.meadow.cafe/webmention/mochi@upchur.ch/1/receive" /> <link rel="webmention" href="https://mochi-webmentions.meadow.cafe/webmention/mochi@upchur.ch/1/receive" />
<!-- Indieweb profile links --> <!-- Indieweb profile links -->
@@ -85,8 +86,10 @@
</section> </section>
{% endif %} {% endif %}
</main> </main>
{% include "birb.njk" %}
{% include "footer.njk" %} {% include "footer.njk" %}
{% include "weather.njk" %} {% include "weather.njk" %}
{% include "wooMode.njk" %} {% include "wooMode.njk" %}
{% include "settings/settingsConfig.njk" %}
</body> </body>
</html> </html>

View File

@@ -4,7 +4,7 @@ layout: layouts/linksPage.njk
<div class="links-container h-card" data-pagefind-body> <div class="links-container h-card" data-pagefind-body>
<img class="profilePic u-photo" src="{{ metadata.author.profilePic }}"> <img class="profilePic u-photo" src="{{ metadata.author.profilePic }}">
<h1 class="socialTitle p-name">Nathan Upchurch</h1> <h1 class="socialTitle p-name">Nathan Upchurch</h1>
<p class="page-block nodropcap">Beside what I do to earn a crust, among other things, Im an incense maker and enthusiast, a classical trombonist, vegan cook, writer, mediocre photographer, and a fan of, advocate for, and occasional contributor to free and open source software. Heres where you can find me on the internet:</p> <p class="page-block nodropcap">Heres where you can find me on the internet:</p>
<div class="socialLinks"> <div class="socialLinks">
{% for link in metadata.socialLinks %} {% for link in metadata.socialLinks %}
<a class="link-button u-url" {% if link.customAttribute %} {{ link.customAttribute | safe }} {% endif %} href="{{ link.linkURL }}"> <a class="link-button u-url" {% if link.customAttribute %} {{ link.customAttribute | safe }} {% endif %} href="{{ link.linkURL }}">

View File

@@ -0,0 +1,4 @@
<form class="siteSettingsToggle" id="birbController">
<input type="checkbox" id="birbToggle" {% if metadata.weatherOnByDefault %}checked{% endif %} />
<label for="birbToggle">Pet bird (Will refresh page when turned off)</label>
</form>

View File

@@ -1,4 +1,4 @@
<form class="siteSettingsToggle" id="weatherController"> <form class="siteSettingsToggle" id="weatherController">
<input type="checkbox" id="weatherToggle" {% if metadata.weatherOnByDefault %}checked{% endif %} /> <input type="checkbox" id="weatherToggle" {% if metadata.weatherOnByDefault %}checked{% endif %} />
<label for="weatherToggle">Show weather?</label> <label for="weatherToggle">Weather</label>
</form> </form>

View File

@@ -1,4 +1,4 @@
<form class="siteSettingsToggle" id="wooModeController"> <form class="siteSettingsToggle" id="wooModeController">
<input type="checkbox" id="wooToggle" {% if metadata.wooModeOnByDefault %}checked{% endif %} /> <input type="checkbox" id="wooToggle" {% if metadata.wooModeOnByDefault %}checked{% endif %} />
<label for="wooToggle">Woo mode?</label> <label for="wooToggle">Woo mode</label>
</form> </form>

View File

@@ -0,0 +1,37 @@
<!-- Site Settings -->
<script>
const weatherSettings = {
handleOnToggle: turnOnWeather,
handleOnDefault: turnOnWeather,
handleOffToggle: turnOffWeather,
handleOffDefault: turnOffWeather,
settingToggle: "weatherToggle",
preferenceName: "weather",
defaultSetting: {{ metadata.weatherOnByDefault }},
forcedOn: false,
};
const wooModeSettings = {
handleOnToggle: deployWoo,
handleOnDefault: wooSensibleDefault,
handleOffToggle: withdrawWoo,
handleOffDefault: withdrawWoo,
settingToggle: "wooToggle",
preferenceName: "wooMode",
defaultSetting: {% if forcedWoo %}true{% else %}false{% endif %},
forcedOn: {% if forcedWoo %}true{% else %}false{% endif %},
};
const petBirbSettings = {
handleOnToggle: showBirb,
handleOnDefault: showBirb,
handleOffToggle: hideBirb,
handleOffDefault: noBirb,
settingToggle: "birbToggle",
preferenceName: "petBirb",
defaultSetting: false,
forcedOn: false,
};
settingHandler(weatherSettings);
settingHandler(wooModeSettings);
settingHandler(petBirbSettings);
</script>
<!-- /Site Settings -->

View File

@@ -2,8 +2,9 @@
<button onclick="siteSettings.showModal();">Site Settings</button> <button onclick="siteSettings.showModal();">Site Settings</button>
<dialog id="siteSettings"> <dialog id="siteSettings">
<h2>Site Settings</h2> <h2>Site Settings</h2>
{% include "weatherController.njk" %} {% include "settings/controllers/birbController.njk" %}
{% include "wooModeController.njk" %} {% include "settings/controllers/weatherController.njk" %}
{% include "settings/controllers/wooModeController.njk" %}
<button id="settingsDone" onclick="siteSettings.close();">Done</button> <button id="settingsDone" onclick="siteSettings.close();">Done</button>
</dialog> </dialog>
</div> </div>

View File

@@ -1,7 +1,7 @@
<!-- weather --> <!-- weather -->
<!-- Based on https://codepen.io/codeconvey/pen/xRzQay --> <!-- Based on https://codepen.io/codeconvey/pen/xRzQay -->
{# This include causes a symbol (text, emoji, et cetera; from metadata.weatherSymbol) to fall from the top of the viewport like snow. #} {# This include causes a symbol (text, emoji, et cetera; from metadata.weatherSymbol) to fall from the top of the viewport like snow. #}
<div class="fallingObjects" id="weather" aria-hidden="true"> <div class="fallingObjects hidden" id="weather" aria-hidden="true">
<div class="fallingObject"> <div class="fallingObject">
<div>{{ metadata.weatherSymbol }}</div> <div>{{ metadata.weatherSymbol }}</div>
</div> </div>
@@ -35,28 +35,14 @@
</div> </div>
<script> <script>
const weather = document.getElementById("weather"); const turnOnWeather = (containerId) => {
const weatherToggle = document.getElementById("weatherToggle"); const container = document.getElementById(containerId);
const weatherPreference = localStorage.getItem("weather");
// Initial weather preference check on page load
if ({% if metadata.weatherOnByDefault == false %}!weatherPreference || {% endif %}weatherPreference == 0) {
weather.classList.add("hidden");
weatherToggle.checked = false;
} else {
weather.classList.remove("hidden"); weather.classList.remove("hidden");
weatherToggle.checked = true; }
};
// Handle weather setting toggle const turnOffWeather = (containerId) => {
weatherToggle.addEventListener('change', function() { const container = document.getElementById(containerId);
if (this.checked) {
localStorage.setItem("weather", 1);
weather.classList.remove("hidden");
} else {
localStorage.setItem("weather", 0);
weather.classList.add("hidden"); weather.classList.add("hidden");
}; }
});
</script> </script>
<!-- /weather --> <!-- /weather -->

View File

@@ -2,7 +2,7 @@
<!-- Based on https://codepen.io/tommyho/pen/JjgoZLK --> <!-- Based on https://codepen.io/tommyho/pen/JjgoZLK -->
{# This include replaces the page background with a crazy rainbow animated shader #} {# This include replaces the page background with a crazy rainbow animated shader #}
<canvas id="shaderCanvas"></canvas> <canvas class="hidden" id="shaderCanvas"></canvas>
<script src="/js/three.min.js"></script> <script src="/js/three.min.js"></script>
<script> <script>
let scene, camera, renderer, uniforms, material, mesh; let scene, camera, renderer, uniforms, material, mesh;
@@ -171,30 +171,11 @@
uniforms.time.value = timestamp * 0.001; uniforms.time.value = timestamp * 0.001;
renderer.render(scene, camera); renderer.render(scene, camera);
} }
</script>
<script>
const wooCanvas = document.getElementById("shaderCanvas"); const wooCanvas = document.getElementById("shaderCanvas");
const wooToggle = document.getElementById("wooToggle");
const wooPreference = localStorage.getItem("wooMode");
let forcedWoo = false;
// Initial preference check on page load
if ({% if metadata.wooModeOnByDefault == false %}!wooPreference || {% endif %}wooPreference == 0) {
forcedWoo ? null : wooCanvas.classList.add("hidden");
wooToggle.checked = false;
} else {
wooCanvas.classList.remove("hidden");
wooToggle.checked = true;
initWoo();
animate(0);
};
// Handle setting toggle
wooToggle.addEventListener('change', function() {
if (this.checked) {
localStorage.setItem("wooMode", 1);
// Function for when wooMode is toggled on
const deployWoo = () => {
let wooAudio = new Audio("/audio/30995__unclesigmund__woo-2.mp3"); let wooAudio = new Audio("/audio/30995__unclesigmund__woo-2.mp3");
wooAudio.volume = 0.4; wooAudio.volume = 0.4;
wooAudio.play(); wooAudio.play();
@@ -202,21 +183,19 @@
wooCanvas.classList.remove("hidden"); wooCanvas.classList.remove("hidden");
initWoo(); initWoo();
animate(0); animate(0);
} else { }
localStorage.setItem("wooMode", 0);
forcedWoo ? null : wooCanvas.classList.add("hidden");
};
});
{% if forcedWoo %} // Function for when wooMode is enabled by default
// Handle forced woo const wooSensibleDefault = () => {
forcedWoo = true;
console.log("Forcing woo mode: woo!");
wooCanvas.classList.remove("hidden"); wooCanvas.classList.remove("hidden");
initWoo(); initWoo();
animate(0); animate(0);
{% endif %} }
// Function for when wooMode is toggled off
const withdrawWoo = () => {
wooCanvas.classList.add("hidden");
}
</script> </script>
<!-- /weather --> <!-- /Woo Mode -->

View File

@@ -23,7 +23,8 @@
--color-gray-90: #333333; --color-gray-90: #333333;
--card-color: rgba(250, 250, 250, 1); --card-color: rgba(250, 250, 250, 1);
--contrast-color: #027860; --contrast-color: rgb(2, 120, 96);
--contrast-color-translucent: rgba(2, 120, 96, 0.5);
--background-color: #faf5f5; --background-color: #faf5f5;
--rss-orange: rgb(255, 152, 0); --rss-orange: rgb(255, 152, 0);
--text-color: var(--color-gray-90); --text-color: var(--color-gray-90);
@@ -98,7 +99,7 @@
--border-radius: 0.3rem; --border-radius: 0.3rem;
/* Transitions */ /* Transitions */
--transition-normal: all 0.3s; --transition-normal: all 0.3s allow-discrete;
/* Links */ /* Links */
--link-decoration-thickness: 0.06rem; --link-decoration-thickness: 0.06rem;
@@ -119,7 +120,8 @@
--color-gray-20: #253848; --color-gray-20: #253848;
--color-gray-90: #dad8d8; --color-gray-90: #dad8d8;
--card-color: #333333; --card-color: #333333;
--contrast-color: #04c49e; --contrast-color: rgb(4, 196, 158);
--contrast-color-translucent: rgba(4, 196, 158, 0.5);
/* --text-color is assigned to --color-gray-_ above */ /* --text-color is assigned to --color-gray-_ above */
--text-color-link: var(--text-color); --text-color-link: var(--text-color);
@@ -576,6 +578,31 @@ sup {
} }
/* Site Settings */ /* Site Settings */
#siteSettings {
border: 1.5px solid var(--color-gray-20);
border-radius: var(--border-radius);
background-color: var(--card-color);
transition: var(--transition-normal);
&::backdrop {
backdrop-filter: blur(3px);
background-color: var(--contrast-color-translucent);
transition: var(--transition-normal);
}
&[open] {
opacity: 1;
transition: var(--transition-normal);
@starting-style {
opacity: 0;
}
}
&[open]::backdrop {
opacity: 1;
@starting-style {
opacity: 0;
}
}
} /* TODO: figure out why exit animation doesn't work */
#siteSettingsContainer { #siteSettingsContainer {
& button:not(#settingsDone) { & button:not(#settingsDone) {
margin-top: 0; margin-top: 0;

64
public/js/main.js Normal file
View File

@@ -0,0 +1,64 @@
/*
* Function to handle settings toggles and the effects they control
* handleOnToggle: Function to be called if user turns the setting on
* handleOnDefault: Function to be called if the setting is on by default
* handleOffToggle: Function to be called if user turns the setting off
* handleOffDefault: Function to be called if the setting is off by default
* settingToggle: String - ID of the user-facing toggle element to control the effect
* preferenceName: String - Name to be used to record the user's setting preference in local storage'
* defaultSetting: Boolean
* forcedOn: Boolean - whether to ignore the user preference if defaultSetting = true
*/
const settingHandler = (settingsObject) => {
const toggle = document.getElementById(settingsObject.settingToggle);
const preference = localStorage.getItem(settingsObject.preferenceName);
// Report settings
console.info(
`
Settings: ${settingsObject.preferenceName}
----------
Default: ${settingsObject.defaultSetting}
Forced on: ${settingsObject.forcedOn}
User preference: ${preference}
`,
);
// User preference is positive
if (preference === "1") {
toggle.checked = true;
settingsObject.forcedOn ? (toggle.disabled = true) : null;
settingsObject.handleOnDefault();
} else if (settingsObject.defaultSetting && settingsObject.forcedOn) {
// Default on, user preference ignored
toggle.checked = true;
toggle.disabled = true;
settingsObject.handleOnDefault();
} else if (settingsObject.defaultSetting && !preference) {
// Default on, no user preference
toggle.checked = true;
settingsObject.forcedOn ? (toggle.disabled = true) : null;
settingsObject.handleOnDefault();
} else {
toggle.checked = false;
settingsObject.handleOffDefault();
}
// Handle setting toggle
toggle.addEventListener("change", function () {
if (this.checked) {
console.info(
`Settings: User turned on ${settingsObject.preferenceName}.`,
);
localStorage.setItem(settingsObject.preferenceName, 1);
settingsObject.handleOnToggle();
} else {
console.info(
`Settings: User turned off ${settingsObject.preferenceName}.`,
);
localStorage.setItem(settingsObject.preferenceName, 0);
settingsObject.handleOffToggle();
}
});
};