A bunch of stuff

This commit is contained in:
2025-11-09 20:57:49 -06:00
parent 9327ca3a43
commit 0263c1de66
18 changed files with 347 additions and 17 deletions

View File

@@ -620,6 +620,13 @@ export default {
url: "https://thefoggiest.dev",
description: "The personal blog of Diederick de Vries of Amsterdam.",
},
{
title: "ThinksTooMuch",
feedUrl: "https://thinkstoomuch.net/index.xml",
url: "https://thinkstoomuch.net/",
description:
"Thoughts on atheism, leftism, firearms, work, and life.",
},
],
},
{

View File

@@ -1,6 +1,7 @@
export default {
title: "Nathan Upchurch",
logo: "/img/logo.svg",
holidayLogo: "",
url: "https://nathanupchurch.com/",
language: "en",
description:
@@ -166,6 +167,7 @@ export default {
iconURL: "/img/wafrn.svg",
},
],
weatherSymbol: "🍁",
webrings: [
{
name: "Fediring",

View File

@@ -1,8 +1,4 @@
<footer>
<a href="https://notbyai.fyi/">
<img src="/img/written-by-human-not-by-ai-white.svg" alt="Written by humans, not by AI.">
</a>
<p>{% if metadata.copyrightNotice %}<span class="copyright-notice">{{ metadata.copyrightNotice }}</span>{% endif %}
{% if metadata.webrings %}<br>
@@ -15,6 +11,11 @@
{% endfor %}
{% endif %}
<a href="/sitemap/">Sitemap</a>
<a href="/special/flying-toasters" style="color: var(--background-color); text-decoration: none;">Fly</a>
</p>
<div id="buttonsAndStuffContainer">
<a href="https://notbyai.fyi/">
<img src="/img/written-by-human-not-by-ai-white.svg" alt="Written by humans, not by AI.">
</a>
{% include "siteSettings.njk" %}
</div>
</footer>

View File

@@ -5,7 +5,7 @@
class="home-link">
<img
class="logo"
src="{{ metadata.logo }}"
src="{% if metadata.holidayLogo %}{{ metadata.holidayLogo }}{% else %}{{ metadata.logo }}{% endif %}"
alt="{{ metadata.title }}">
</a>
{% if not hideNav %}{% include "nav.njk" %}{% endif %}

View File

@@ -16,5 +16,6 @@
</section>
</main>
{% include "footer.njk" %}
{% include "weather.njk" %}
</body>
</html>

View File

@@ -0,0 +1,20 @@
<style>
#siteSettingsContainer {
& button:not(#settingsDone) {
margin-top: 0;
}
}
</style>
<script>
const settingsModal = document.getElementById("siteSettings");
</script>
<div id="siteSettingsContainer">
<button onclick="siteSettings.showModal();">Site Settings</button>
<dialog id="siteSettings">
<h2>Site Settings</h2>
{% include "weatherController.njk" %}
<button id="settingsDone" onclick="siteSettings.close();">Done</button>
</dialog>
</div>

172
_includes/weather.njk Normal file
View File

@@ -0,0 +1,172 @@
<!-- weather -->
<!-- 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. #}
<style>
.fallingObject {
color: #fff;
font-size: 1em;
font-family: Arial;
text-shadow: 0 0 1px #000;
}
@keyframes fallingObjects-fall {
0% {
top: -10%;
}
100% {
top: 100%;
}
}
@keyframes fallingObjects-shake {
0% {
transform: translateX(0px);
}
50% {
transform: translateX(80px);
}
100% {
transform: translateX(0px);
}
}
.fallingObject {
position: fixed;
top: -10%;
z-index: 9999;
user-select: none;
cursor: default;
animation-name: fallingObjects-fall, fallingObjects-shake;
animation-duration: 10s, 3s;
animation-timing-function: linear, ease-in-out;
animation-iteration-count: infinite, infinite;
animation-play-state: running, running;
}
.fallingObject:nth-of-type(0) {
left: 1%;
animation-delay: 0s, 0s;
& > div {
transform: rotate(45deg);
}
}
.fallingObject:nth-of-type(1) {
left: 10%;
animation-delay: 1s, 1s;
& > div {
transform: rotate(10deg);
}
}
.fallingObject:nth-of-type(2) {
left: 20%;
animation-delay: 6s, 0.5s;
& > div {
transform: rotate(60deg);
}
}
.fallingObject:nth-of-type(3) {
left: 30%;
animation-delay: 4s, 2s;
& > div {
transform: rotate(84deg);
}
}
.fallingObject:nth-of-type(4) {
left: 40%;
animation-delay: 2s, 2s;
& > div {
transform: rotate(267deg);
}
}
.fallingObject:nth-of-type(5) {
left: 50%;
animation-delay: 8s, 3s;
& > div {
transform: rotate(200deg);
}
}
.fallingObject:nth-of-type(6) {
left: 60%;
animation-delay: 6s, 2s;
& > div {
transform: rotate(20deg);
}
}
.fallingObject:nth-of-type(7) {
left: 70%;
animation-delay: 2.5s, 1s;
& > div {
transform: rotate(78deg);
}
}
.fallingObject:nth-of-type(8) {
left: 80%;
animation-delay: 1s, 0s;
& > div {
transform: rotate(3120deg);
}
}
.fallingObject:nth-of-type(9) {
left: 90%;
animation-delay: 3s, 1.5s;
& > div {
transform: rotate(123deg);
}
}
</style>
<div class="fallingObjects" id="weather" aria-hidden="true">
<div class="fallingObject">
<div>{{ metadata.weatherSymbol }}</div>
</div>
<div class="fallingObject">
<div>{{ metadata.weatherSymbol }}</div>
</div>
<div class="fallingObject">
<div>{{ metadata.weatherSymbol }}</div>
</div>
<div class="fallingObject">
<div>{{ metadata.weatherSymbol }}</div>
</div>
<div class="fallingObject">
<div>{{ metadata.weatherSymbol }}</div>
</div>
<div class="fallingObject">
<div>{{ metadata.weatherSymbol }}</div>
</div>
<div class="fallingObject">
<div>{{ metadata.weatherSymbol }}</div>
</div>
<div class="fallingObject">
<div>{{ metadata.weatherSymbol }}</div>
</div>
<div class="fallingObject">
<div>{{ metadata.weatherSymbol }}</div>
</div>
<div class="fallingObject">
<div>{{ metadata.weatherSymbol }}</div>
</div>
</div>
<script>
const weather = document.getElementById("weather");
const weatherToggle = document.getElementById("weatherToggle");
const weatherPreference = localStorage.getItem("weather");
// Initial weather preference check on page load
if (weatherPreference == 0) {
weather.classList.add("hidden");
weatherToggle.checked = false;
} else {
weather.classList.remove("hidden");
weatherToggle.checked = true;
};
// Handle weather setting toggle
weatherToggle.addEventListener('change', function() {
if (this.checked) {
localStorage.setItem("weather", 1);
weather.classList.remove("hidden");
} else {
localStorage.setItem("weather", 0);
weather.classList.add("hidden");
};
});
</script>
<!-- /weather -->

View File

@@ -0,0 +1,30 @@
<style>
#weatherController {
color: var(--text-color);
font-size: var(--step--2);
font-variation-settings: var(--font-variation-ui);
text-transform: uppercase;
letter-spacing: var(--ui-letter-spacing);
font-family: var(--font-family-ui);
& label {
display: inline;
}
& input {
accent-color: var(--contrast-color);
background-color: var(--background-color);
border: var(--border-details);
border-color: var(--contrast-color);
border-radius: var(--border-radius);
color: var(--text-color);
&:focus {
box-shadow: 0 0 0 2px var(--contrast-color);
outline: none;
}
}
}
</style>
<form id="weatherController">
<input type="checkbox" id="weatherToggle" checked />
<label for="weatherToggle">Show weather?</label>
</form>

View File

@@ -4,6 +4,10 @@ title: Nathan Upchurch | Changelog
structuredData: none
---
# Changelog
* 2025-11-9
* Added [ThinksTooMuch](https://thinkstoomuch.net) to the [blogroll](/blogroll).
* Updated [/incense](/incense).
* Added snow / weather, and site settings button and dialog.
* 2025-10-20
* Added [Moist Poetry Journal](https://moistpoetryjournal.com) to the [blogroll](/blogroll).
* Removed some less active and/or abandoned blogs from the [blogroll](/blogroll).

View File

@@ -55,6 +55,7 @@ Incense making is hard. While parts of the world with strong incense cultures en
### Other
* [A list of archived URLs](https://web.archive.org/web/*/https://talesofincense.com/*) from a now-defunct site with some good information on Chinese incense.
* [All of my writing on incense](/tags/incense/)
* [Aromasublime Learning Center](https://www.aromasublime.com/news/category/key+articles++-+learning+center)—Articles on agarwood and agarwood oil.
* [incensemakers.org](https://incensemakers.org/) is an invitation-only forum for relatively experienced incense makers. It is not incredibly active, but it does have a number of useful threads visible to non-members. If you are interested in joining, your best bet is to have an existing member you know personally get in touch with [me](/me) to provide a recommendation on your behalf.
* See the [incense, fragrance, and perfumery section of my blogroll](/blogroll/#incense-fragrance-and-perfumery) for a list of blogs with writing on incense and related topics.
@@ -78,6 +79,7 @@ Incense making is hard. While parts of the world with strong incense cultures en
* [Shoyeido Factory Works (YouTube)](https://www.youtube.com/watch?v=EQRxB4Gz-JM)
* [The Frankincense Trail](https://www.imdb.com/title/tt2056414/)—Kate Humble follows the ancient frankincense trade route from Oman to Palestine. I have linked to the IMDB page, but this documentary series is well worth sailing the high seas for.
* [*The Scent of Heaven: Inside Vietnams Incense Village* (YouTube)](https://www.youtube.com/watch?v=Wy8pDpIH31g)
* [*'The Scent of Sakai' 堺の香り - Handmade incense stick craftsman* (YouTube)](https://www.youtube.com/watch?v=-4vOPSJYvX4)
* [*Turf Peat Incense* (YouTube)](https://www.youtube.com/watch?v=4F7Xvdpq-GE)
## Reputable Suppliers of Aromatics

View File

@@ -0,0 +1,7 @@
---
title: Butterfly Spring Incense
manufacturer: Lijiali
date: 2025-10-28 12:07:00
time: 12:07 PM
---

View File

@@ -0,0 +1,7 @@
---
title: Green Kinam, AAA
manufacturer: Yuzhi Oud
date: 2025-11-03 11:41:00
time: 11:41 AM
---

View File

@@ -0,0 +1,7 @@
---
title: Palo Santo
manufacturer: Some random shop
date: 2025-11-05 14:37:00
time: 2:37 PM
---

View File

@@ -0,0 +1,7 @@
---
title: Some weird cedar, lavender, and orris composition I've been working on
manufacturer: Myself
date: 2025-11-03 9:33:00
time: 9:33 AM
---

View File

@@ -193,10 +193,14 @@ export default async function (eleventyConfig) {
);
// Passthrough
eleventyConfig
.addPassthroughCopy({ "./public/": "/" })
.addPassthroughCopy("./content/special/");
.addPassthroughCopy("./content/special/")
.addPassthroughCopy("./node_modules/@magenta/music/es6/core.js")
.addPassthroughCopy(
"./node_modules/html-midi-player/dist/midi-player.min.js",
)
.addPassthroughCopy("./node_modules/tone/build/Tone.js");
// Get the first `n` elements of a collection.
eleventyConfig.addFilter("head", (array, n) => {

View File

@@ -41,6 +41,7 @@
"mdfigcaption": "^0.1.1"
},
"dependencies": {
"html-midi-player": "^1.6.0",
"markdown-it-container": "^4.0.0",
"markdown-it-footnote": "^3.0.3",
"markdown-it-image-figures": "^2.1.1",

View File

@@ -183,7 +183,7 @@ html {
input.answer {
display: inline;
}
input:not(.answer),
input:not(.answer):not(#weatherToggle),
textarea {
background-color: var(--background-color);
border: var(--border-details);
@@ -334,15 +334,17 @@ a {
}
footer {
padding: var(--space-xl) 0 var(--space-m) 0;
& p {
font-size: var(--step-0);
grid-column: var(--span-grid);
margin-bottom: 0;
}
& .webring {
display: inline;
padding-right: var(--space-xs);
}
}
footer .webring {
display: inline;
padding-right: var(--space-xs);
}
footer p {
font-size: var(--step-0);
grid-column: var(--span-grid);
}
h1,
h2,
h3 {
@@ -1051,6 +1053,18 @@ article.post {
margin: var(--space-2xs) auto;
}
}
#buttonsAndStuffContainer {
display: flex;
grid-column: var(--span-grid);
width: 100%;
& a,
img,
div {
display: inline-block;
height: var(--space-m-l);
margin-right: var(--space-3xs);
}
}
.gallery-images {
display: flex;
flex-flow: row wrap;
@@ -1188,3 +1202,6 @@ dialog {
gap: var(--grid-gutter);
grid-template-columns: repeat(var(--grid-columns), 1fr);
}
.hidden {
display: none;
}

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 16 16"
version="1.1"
id="svg1"
sodipodi:docname="story-editor.svg"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="57.0625"
inkscape:cx="8"
inkscape:cy="8"
inkscape:window-width="2048"
inkscape:window-height="1080"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<defs
id="defs3051">
<style
type="text/css"
id="current-color-scheme">.ColorScheme-Text { color: #fcfcfc; } </style>
</defs>
<path
style="fill:#faf5f5;fill-opacity:1;stroke:none"
d="M 3 2 L 3 14 L 7 14 L 7 13 L 4 13 L 4 5 L 12 5 L 12 7 L 13 7 L 13 2 L 12 2 L 12 4 L 11 4 L 11 2 L 5 2 L 5 4 L 4 4 L 4 2 L 3 2 z M 5 6 L 5 7 L 11 7 L 11 6 L 5 6 z M 5 8 L 5 9 L 8 9 L 8 8 L 5 8 z M 12 8 L 8 12 L 8 14 L 10 14 L 14 10 L 12 8 z M 11.689453 9.6894531 L 12.28125 10.28125 L 10.59375 11.96875 L 10.59375 11.984375 L 9.3125 13.28125 L 8.71875 12.6875 L 11.689453 9.6894531 z M 5 10 L 5 11 L 7 11 L 7 10 L 5 10 z "
class="ColorScheme-Text"
id="path1" />
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB