From cc8b8b6d8b2ab398c237f2e16d1a3a31be06407f Mon Sep 17 00:00:00 2001 From: Daniel Ledda Date: Sun, 18 Jan 2026 22:15:07 +0100 Subject: [PATCH] update new article --- app/blog/DjBlogMain.tsx | 8 +- app/blog/DjBlogRoot.tsx | 55 ++-- app/home/DjHomeRoot.tsx | 3 +- main.ts | 132 +++++--- public/blog/content/poof-and-its-gone.html | 1 + .../content/straightjacket-of-indecision.html | 291 ++++++++++++++++++ public/static/assets/leaf-hrule.svg | 52 ++++ public/static/theme.css | 40 ++- 8 files changed, 515 insertions(+), 67 deletions(-) create mode 100644 public/blog/content/straightjacket-of-indecision.html create mode 100644 public/static/assets/leaf-hrule.svg diff --git a/app/blog/DjBlogMain.tsx b/app/blog/DjBlogMain.tsx index c6349a5..fffd4b1 100644 --- a/app/blog/DjBlogMain.tsx +++ b/app/blog/DjBlogMain.tsx @@ -10,6 +10,10 @@ const style = css` flex-direction: row; gap: 4px; } + +h2 { + margin-top: 0; +} `; export default defineComponent({ @@ -28,9 +32,9 @@ export default defineComponent({ {blogEntries.result.value?.map(_ => (
  • - { _.title } - - + - + { _.title }
  • )) ??
  • Blog posts loading...
  • } diff --git a/app/blog/DjBlogRoot.tsx b/app/blog/DjBlogRoot.tsx index 1f9c622..752303b 100644 --- a/app/blog/DjBlogRoot.tsx +++ b/app/blog/DjBlogRoot.tsx @@ -28,27 +28,32 @@ export const routes: RouteRecordRaw[] = [ ]; const styles = css` +body { + height: 100svh; +} + .dj-blog-root { - width: 100vw; display: flex; flex-direction: column; align-items: center; - height: 100vh; + margin: auto; + width: 800px; - .container { - width: 800px; + .dot { + margin-left: 10px; + margin-right: 10px; } - .spacer { - flex: 1; + .container { + width: 100%; } footer { - color: gray; - width: calc(100% - 10px); - margin-bottom: 20px; + width: 800px; font-style: italic; - padding-left: 10px; + margin-left: 10px; + margin-bottom: 25px; + text-align: left; } a { @@ -61,11 +66,12 @@ const styles = css` } nav { + width: 100%; font-size: 40px; - margin-bottom: 40px; + margin-top: 10px; + margin-bottom: 10px; text-decoration: none; text-align: right; - width: 100%; a, a:visited { color: var(--dj-palette3); @@ -73,11 +79,16 @@ const styles = css` } @media only screen and (max-width: 1024px) { + width: 100%; + .container { - width: calc(100% - 20px); padding: 10px; } + .dj-title { + margin-right: 30px; + } + footer { margin-bottom: 0; } @@ -98,14 +109,14 @@ export default defineComponent({ <>
    +
    - {{ default: ({ Component }: { Component: VNode }) => (Component && @@ -120,11 +131,11 @@ export default defineComponent({ }}
    -
    +
    diff --git a/app/home/DjHomeRoot.tsx b/app/home/DjHomeRoot.tsx index eac18cc..9b373f0 100644 --- a/app/home/DjHomeRoot.tsx +++ b/app/home/DjHomeRoot.tsx @@ -6,7 +6,7 @@ import { addCSS, css } from "@/util.ts"; const styles = css` body { - height: 100vh; + height: 100svh; } .dj-home-root { @@ -65,6 +65,7 @@ body { footer { margin-left: 10px; margin-bottom: 20px; + font-style: italic; } @media only screen and (max-width: 1024px) { diff --git a/main.ts b/main.ts index 37b9204..e1ba956 100644 --- a/main.ts +++ b/main.ts @@ -12,8 +12,90 @@ import { type DjAPIResult, type DjAPIResultMap } from "@/api.ts"; const utf8Decoder = new TextDecoder("utf-8"); +const HOST = 'https://djledda.net'; + const parser = new DOMParser(); +async function getBlogEntries() { + const paths: string[] = []; + const contentDir = './public/blog/content/'; + for await (const dirEnt of Deno.readDir(contentDir)) { + if (dirEnt.isFile && dirEnt.name.endsWith('.html')) { + paths.push(`${contentDir}${dirEnt.name}`); + } + } + const result: DjAPIResultMap['/blog-entries'] = []; + for (const filePath of paths) { + const content = await Deno.readTextFile(filePath); + const dom = parser.parseFromString(content, 'text/html'); + const metadata = { + slug: '', + tags: [] as string[], + guid: '', + title: '', + createdAt: '', + updatedAt: '', + }; + const metaTags = dom.querySelectorAll('meta') as unknown as NodeListOf; + for (const metaTag of metaTags) { + const name = metaTag.attributes.getNamedItem('name')?.value ?? ''; + const content = metaTag.attributes.getNamedItem('content')?.value ?? ''; + if (name === 'title') { + metadata.title = content; + } else if (name === 'tags') { + metadata.tags = content ? content.split(",") : []; + } else if (name === 'guid') { + metadata.guid = content; + } else if (name === 'slug') { + metadata.slug = content; + } else if (name === 'updatedAt') { + metadata.createdAt = content; + } else if (name === 'createdAt') { + metadata.updatedAt = content; + } + } + result.push(metadata); + } + result.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()); + return result; +} + +async function rss() { + const articles = await getBlogEntries(); + + return ` + + + djledda's blog + djledda's personal blog + ${ HOST }/blog + dan@djledda.net (Daniel Ledda) + + djledda's blog + ${ HOST }/favicon.png + ${ HOST }/blog + djledda's personal blog + + en-au + ${ new Date().getFullYear() } djledda.net All rights reserved + ${ new Date(articles.at(-1)!.updatedAt).toUTCString() } + ${ new Date(articles.at(-1)!.updatedAt).toUTCString() } + 1440 + + ${ articles.map(article => ` + ${ article.title } + ${ HOST }/blog/${ article.slug } + ${ new Date(article.createdAt).toUTCString() } + dan@djledda.net (Daniel Ledda) + ${ article.guid } + + `).join('')} + + + +`; +} + function appHeaderScript(params: { ssrContext: DjSSRContext, entryPath: string }) { return ` ${ toValue(params.ssrContext.head.title) } @@ -32,7 +114,7 @@ function appHeaderScript(params: { ssrContext: DjSSRContext, entryPath: string } - `; @@ -53,8 +135,6 @@ for await (const entry of siteEntries("app")) { sites.push(entry); } -console.log(sites); - async function getAPIResponse(apiReq: Request): Promise { let jsonResponse: DjAPIResult | { error: string } | null = null; let status = 200; @@ -102,44 +182,7 @@ async function getAPIResponse(apiReq: Request): Promise { result.sort((a, b) => a.titleDe.localeCompare(b.titleDe)); jsonResponse = result; } else if (apiPath === "/blog-entries") { - const paths: string[] = []; - const contentDir = './public/blog/content/'; - for await (const dirEnt of Deno.readDir(contentDir)) { - if (dirEnt.isFile && dirEnt.name.endsWith('.html')) { - paths.push(`${contentDir}${dirEnt.name}`); - } - } - const result: DjAPIResultMap['/blog-entries'] = []; - for (const filePath of paths) { - const content = await Deno.readTextFile(filePath); - const dom = parser.parseFromString(content, 'text/html'); - const metadata = { - slug: '', - tags: [] as string[], - title: '', - createdAt: '', - updatedAt: '', - }; - const metaTags = dom.querySelectorAll('meta') as unknown as NodeListOf; - for (const metaTag of metaTags) { - const name = metaTag.attributes.getNamedItem('name')?.value ?? ''; - const content = metaTag.attributes.getNamedItem('content')?.value ?? ''; - if (name === 'title') { - metadata.title = content; - } else if (name === 'tags') { - metadata.tags = content ? content.split(",") : []; - } else if (name === 'slug') { - metadata.slug = content; - } else if (name === 'updatedAt') { - metadata.createdAt = content; - } else if (name === 'createdAt') { - metadata.updatedAt = content; - } - } - result.push(metadata); - } - result.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()); - jsonResponse = result; + jsonResponse = await getBlogEntries(); } if (!jsonResponse) { @@ -195,6 +238,13 @@ Deno.serve({ response = await getAPIResponse(req); } + // RSS + if (response === null) { + if (pathname === '/blog/djblog.rss') { + response = new Response(await rss(), { status: 200 }); + } + } + // Public/static files if (response === null) { let filepath = join(".", "public", pathname); diff --git a/public/blog/content/poof-and-its-gone.html b/public/blog/content/poof-and-its-gone.html index c004947..47aacad 100644 --- a/public/blog/content/poof-and-its-gone.html +++ b/public/blog/content/poof-and-its-gone.html @@ -3,6 +3,7 @@ +

    diff --git a/public/blog/content/straightjacket-of-indecision.html b/public/blog/content/straightjacket-of-indecision.html new file mode 100644 index 0000000..c3da613 --- /dev/null +++ b/public/blog/content/straightjacket-of-indecision.html @@ -0,0 +1,291 @@ + + + + + + + +

    +

    + Over the last six or seven years living abroad in the faraway place of + Munich, Germany, I’ve often wondered when, or even whether, I might return + home to Melbourne, Australia. Even though I never spent much time + contemplating my distant future, my mother certainly didn’t let me forget + that she wished to have me back at home sooner rather than later. I'd + listen to her talk in absolutes every return visit, “when you’re back + next year…,” and so on. I shrugged it off as just motherly love. I'm + in Germany, Mum, and I’m staying here for now! +

    + +

    + Despite this, the thought in the back of my mind that this overseas + journey would in all likelihood be ephemeral proved to be a constant + burden. Wherever I went, whichever decision I made, the immense doubt + haunted me. Before the COVID pandemic, I had originally planned + to study my Master’s, probably work a couple of years at a local + company “in the industry”, and then return home ideally feeling fulfilled and + satisfied. Like I had earnt some kind of imaginary certificate of + intercultural aptitude. Secretly however, I imagined falling in love + with a beautiful German girl and living in the idyllic Bavarian + countryside, happily ever after, even if I was unwilling to admit it + even to myself. +

    + +

    + But given the retreat of pandemic-related restrictions and regulations was + so gradual, as were too the many changes in my life circumstances + in-between, it never seemed like quite the right time to draw a line in the + sand. It would seem I became the frog in boiling water. +

    + +

    + Finally, maybe around late 2023, things seemed to have settled. I chose to + move into my own apartment, after my roommate moved in with his + girlfriend. It became clear to me that I would soon have to give serious + thought as to whether I wanted to return home, or if I wanted to seriously + commit to “being German.” The weight I was carrying was growing + heavier, and somehow I knew this was slowing me down. I just didn't + realise how much exactly. +

    + +

    + In the first few years here, sure—it never made much sense to paint my + student dorm room or invest in expensive furniture, even once I began earning a + full-time salary—I figured I probably wouldn’t be here much longer, + anyway. But as the years went by and the dorm rooms became my own rental + apartments, I could feel the desire to invest in long-term commitments grow + stronger within me. Actually bringing any of them to fruition, on the other + hand, seemed impossible. I could hardly bring myself to buy a + dishwasher for the longest time: moving countries could have always been + right around the corner, so I had better not waste the money and effort. +

    + +

    + Never knowing when I was going to leave, I froze in the face of more + important decisions, even ones that might have promised to greatly improve + my quality of life, and that seemed frankly banal to outsiders. It plagued + the back of my mind when searching for the motivation to meet people or go + on dates. What if I eventually want to go home? Will she lose interest in me + because I’m a flight risk? +

    + +

    + Whenever I would meet someone in my daily life, they would inevitably + ask me whether I would like to stay in Germany forever or if I plan to + move home at some stage. Over the years, I learnt to come with + pre-prepared answers that suggested I was comfortable with my + open-ended life abroad. But I wasn’t. I felt trapped, like I couldn’t + go anywhere. Like I couldn’t start any meaningful projects. I wanted to + take on so much more and feel resolute in each step. But I felt + suffocated by the idea that the rug would soon be pulled out from under + my feet. +

    + +

    + I did however eventually start voicing the idea that, as long as I + don’t meet anybody here that I come to love so much that I simply must + stay, it would be better for me to go home. That was the beginning of + the end, I suppose, but the thought was so limp in spirit that it + hardly made any difference in my life. Instead it was the perfect + excuse to remain undecided: at any moment, the love of my life could + waltz around the corner. Ironically, this straitjacket of indecision + all but prevented me from doing anything about my bachelorhood. +

    + +

    + Things did improve; I grew adamant that I would break down old habits + that were once born of helplessness. I found it increasingly easier to + “just do things,” as the chronically online say, but there was an upper + limit to their magnitude. Such things as buying more expensive home + furnishings or making slightly more long-term commitments became easier + (think “one year” rather than “a couple of months”), but nonetheless I + stillfelt tremendously stuck. +

    + +

    + In the summer of 2025, my parents visited and stayed with me for two + months, during which we went on many European trips alongside my daily + life in Munich. Afterwards, I joined them on the plane ride home and + visited Melbourne. This time, it was outside of the usual Christmas + holiday period so as to really get a sense of how life back home had + changed. +

    + +

    + I stayed a month, bringing the total time spent with family and friends + to three months, which was a lot of time for me after having lived for + so long abroad. Alhoutgh I had visited for a month almost every year, + this time around felt a bit different. I felt like I was actually back + home, and not just peering through the window. Maybe it was the time of + year, maybe because of the high school reunion I attended, or maybe + even just due to how much time had passed since COVID. Whatever it was, + those three months made their mark. After saying our goodbyes at the + airport, I headed to stand in line at the first security checkpoint. + After turning the corner, I lost sight of my parents, and my heart + sank. +

    + +

    + For the first time in seven years, something felt wrong. I didn’t want + to leave any more. I realised that my time in Munich was over. After + two years of deliberating over the minutiae of my life and where I + lived, the epiphany seemed to come in an instant. It was emotional. + There was no logical breakthrough. No intellectual victory. I was just + homesick. After six years, no less. +

    + +

    + Once I arrived back in Munich, everything about this charming place + became grossly annoying overnight. The northern winter annoyed me. The + people annoyed me. My job annoyed me. My entire surroundings were so + fastidious that I couldn’t wait to get home. Even the German language + that has brought me so much joy to learn, to which I effortlessly + dedicated so much time and interest; even it became a nuisance. I + wanted my native tongue back. I wanted effortless freedom of expression + back. I was imprinted with a culture when I was younger and I just + wanted it back. +

    + +

    + Paradoxically, though, I felt fully liberated all of a sudden. Free to + do whatever I wanted. Having made the decision to pack up and leave + filled me with such a profound sense of direction that everything else + was able to just slide into place, as if a circuit had been completed. +

    + +

    + By forfeiting many potential futures for just one that I could count + on, the organisation of the rest of my life was able to spontaneously + emerge. I guess I always sensed this would happen, but I seriously + underestimated the ramifications. A cataclysmic domino effect resolved + a hierarchy of assumptions about who I was, where I was, and what I was + doing, running incredibly deep. Before, I was basically floundering. + Even though I could feel that I knew what feeling I wanted out of + life—and indeed I strove to work towards it&mash;I was + nonetheless totally directionless. And it was painful. Not so any more. +

    + +

    + The irony of all this is that by making this decision, I suddenly feel + like I know what I’m doing here right now and can arrange the + coming months accordingly. I feel freer that ever to date people in + Germany and with even more intention than I did before. I feel like I + have permission to take on any domestic projects I feel like. Isn’t + that strange? I sure thought so. In all honesty I expected the opposite + outcome. But now there’s a timeline: I can see how it all fits into the + grand plan. +

    + +
    + +

    + There are more reasons to move home, however, than just family and + friends, as important as they are to me. They were simply the more + obvious tip of the iceberg, as it were. +

    + +

    + Trying to live in two cultures at once results in a kind of purgatory, + and I suppose I never quite committed to living in one or the other. + But over the last few years, especially upon contemplating the + physiological and psychological impact of learnt helplessness, it + became clear that there was a deep desire in me to self-actualise, and + that it should be given more serious attention. During my preteen and + early teen years, I was a prolific user of the Adobe suite, I loved to + draw, write stories, and produce music. I loved to make silly games and + build worlds with atmosphere. It was here where I was completely in my + element, and I sense deep within myself that I need to reprise these + pursuits. Alas, it would seem I can hardly find the time (or if I am + honest, the energy) to invest in them. I have mostly blamed this on my + day job, but it has become increasingly obvious that I’m mostly + being stifled simply by living alone in a foreign country. +

    + +

    + The purpose of a culture is apparently to obviate the need to think + about what to do as much as possible so as to free up energy for more + niche specialisation. Having to think about how to greet somebody, or + what is appropriate to do in public versus in private, or even what + amount and what type of conversation is appropriate, and with + whom—these are all things that are imparted simply by virtue of + growing up in a particular culture. They are acquired in similar + fashion to language (and some might say that these two are indeed + exactly the same thing). If it weren’t for these effortless + assumptions, it might become an exhausting moment-by-moment decision + making process, in perpetuity. The broader cultural context can take + care of much of this, both in the aforementioned sense of traditions + and customs as well as by making use of particular industrial + specialisations, such as manufacturing and the provision of services + and application of expertise. This way, you can focus on you, so you + can “relax into complexity”. +

    + +

    + The imprinting of childhood seems especially important. It's possible, + and certainly proven in the case of language acquisition, that children + growing up with multiple cultural contexts in parallel find the + context-switching relatively painless and easy, if not equally as easy + as the monoculturally reared child. These additional cultures are like + an extra sub-context within a single culture. Being “German” is, for + example, another social language, with its own grammar, akin to + attending church versus going to a bar. And it, too, has multiple + manifestations. +

    + +

    + But I am not a child of Germany. Neither is German my native tongue. I + may have long been a C2 speaker, and indeed, I live my life basically + incognito unless I explicitly mention my background—no one really + notices I’m not from around here. Yet no matter how good my language + skills get, this mismatch still presents as an extra layer of + abstraction. For the programmers out there: I do not feel like I’m + running on “bare metal” like I do back home. The extra latency becomes + cumulatively exhausting. I’m running in an interpreter, playing life on + hard mode, when the opportunity to compile to machine code and switch + to normal mode (or even easy) is right at my fingertips. +

    + +

    + I previously described my circumstances as a purgatory, and this is an + apt word to exemplify the cultural incongruencies. The word itself is + frequently used—but only in English speaking cultures—in a + looser sense to refer to a state of suffering that is almost always + temporary, before a type of finalising “decision” relieves oneself of + it. This is not so in other languages. Whilst the word and idea of a + purgatory do exist in German (Fegefeuer), they don’t in this + metaphorical sense. Many other types of analogies, turns of phrases, + and cultural metaphors used in everyday life don't neatly map to one + another (even though some do, thanks to the more remotely shared + cultural and linguistic history). +

    + +

    + I’ve come to believe that you might have to fully relinquish one + cultural context for another in order to remove the extra cognitive + burden. That would entail essentially “giving up” Australia once and + for all to stay in Germany and focus on more specialised pursuits. Upon + reflection, I think I really did do this for a few years, whilst I was + still enthralled by the joy of learning a new language to proficiency, + but its novelty soon faded. +

    + +

    + When I use my computer, I always have two keyboard layouts active, + depending on what I’m doing. One for writing German prose and + messaging, and another with my “native” layout for everything else. I + originally figured this two-pronged approach would make things easier, + but really, it's constant chaos. Forever having one foot in each door + is the same kind of chaos. +

    + +

    + As such, it now seems obvious to me that I have to return to a single + keyboard layout and go home. If I want to “relax into complexity,” then + I must free up as much energy as possible, and in making this decision + I can feel another entanglement of helplessness slowly unravel. +

    + +

    + And this time, it’s a big one. +

    +
    diff --git a/public/static/assets/leaf-hrule.svg b/public/static/assets/leaf-hrule.svg new file mode 100644 index 0000000..b063d1f --- /dev/null +++ b/public/static/assets/leaf-hrule.svg @@ -0,0 +1,52 @@ + + + + diff --git a/public/static/theme.css b/public/static/theme.css index 3e6d5b4..92e5cb7 100644 --- a/public/static/theme.css +++ b/public/static/theme.css @@ -26,6 +26,7 @@ --dj-palette1: #83a6bf; --dj-palette2: #5e81ac; --dj-palette3: #8fbcbb; + --dj-prose: #98aab7; --dj-visited: #8d8bd5; --dj-bgpalette1: #2e3440; } @@ -43,7 +44,44 @@ html, body { font-size: 16px; } -h1, h2, h3, h4, h5, nav, .dj-title, .roboto-slab { +hr { + border: 0; + height: 1px; + background-image: linear-gradient(to right, transparent, var(--dj-prose), transparent); + margin: 40px 0 40px 0; + width: 100%; + + &::before, &::after { + content: ' '; + position: absolute; + display: block; + margin: auto; + left: 0; + right: 0; + transform: translateY(-50%); + } + + &::before { + background-color: var(--dj-bgpalette1); + width: 74px; + height: 30px; + } + + &::after { + width: 66px; + height: 22px; + background-color: var(--dj-prose); + background-size: cover; + mask-image: url('assets/leaf-hrule.svg'); + mask-size: cover; + } +} + +p { + color: var(--dj-prose); +} + +h1, h2, h3, h4, h5, nav, .dj-title { font-family: "Baskervville", serif; font-optical-sizing: auto; font-weight: 400;