chore: remove resource pages, now published from notes
Deploy to SFTP Server / build (push) Successful in 4m18s

Resources live at /notes/resources, built by notes-publish. Dropping the
marka-backed pages stops the build from fetching and optimizing every
movie, series, recipe and article cover.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014zJGmwpp8p3zE2UQoRjKFE
This commit is contained in:
maxandClaude Opus 5.5 committed 2026-09-26 19:13:41 +02:00
1 parent f79308510b
commit a9648c9e06
11 files changed
-515

No files matched your search

-43
View File
@@ -1,43 +0,0 @@
<script lang="ts">
import { onMount } from "svelte";
let searchTerm = "";
let staticContainer: HTMLElement | null;
onMount(async () => {
staticContainer = document.getElementById("resource-list-static");
});
function search() {
if (!staticContainer) return;
const lowerCaseSearchTerm = searchTerm.toLowerCase().trim();
if (!lowerCaseSearchTerm) {
[...staticContainer?.children].forEach((element: HTMLElement) => {
element.style.display = "";
});
return;
}
for (const element of staticContainer?.children) {
const el = element as HTMLElement;
const isMatch = el.dataset.searchTerm?.includes(lowerCaseSearchTerm);
if (isMatch) {
el.style.display = "";
} else {
el.style.display = "none";
}
}
}
$: search();
</script>
<div class="search-wrapper my-4 noise relative">
<input
type="text"
bind:value={searchTerm}
placeholder={`Search...`}
class="w-full p-2 gradient border-1 border-neutral rounded noise" />
</div>
-29
View File
@@ -1,29 +0,0 @@
---
import * as memorium from "@helpers/memorium";
import { markdownToHtml } from "@helpers/markdown";
import Image from "@components/Image.astro";
import type { ImageMetadata } from "astro";
const { resource } = Astro.props;
---
<h1 class="text-4xl">{resource?.content?.headline}</h1>
<div>
{
resource?.content?.image && (
<Image
hash
src={
{ src: memorium.getImageUrl(resource.content.image) } as ImageMetadata
}
alt="Cover for {resource?.content?.name}"
class="rounded-2xl overflow-hidden"
pictureClass="rounded-2xl box-shadow"
/>
)
}
</div>
<div
class="flex flex-col gap-4"
set:html={markdownToHtml(resource?.content?.articleBody)}
/>
-25
View File
@@ -1,25 +0,0 @@
---
import { Code } from 'astro:components';
import Recipe from "./Recipe.astro";
import Article from "./Article.astro";
import Review from "./Review.astro";
const { resource } = Astro.props;
const type = resource?.content?._type ?? "unknown";
---
{type === "Recipe" && <Recipe resource={resource} />}
{type === "Article" && <Article resource={resource} />}
{type === "Review" && <Review resource={resource} />}
{
type === "unknown" && (
<div>
<h3>Unknown resource type</h3>
</div>
)
}
<details >
<summary class="flex"><span class="i-tabler-code w-6 h-6 inline"/></summary>
<Code code={JSON.stringify(resource??"{}", null, 2)} lang="json" theme="dark-plus" />
</details>
-48
View File
@@ -1,48 +0,0 @@
---
import * as memorium from "@helpers/memorium";
import { markdownToHtml } from "@helpers/markdown";
import Image from "@components/Image.astro";
import type { ImageMetadata } from "astro";
const { resource } = Astro.props;
const ingredients = resource?.content?.recipeIngredient || [];
const instructions = resource?.content?.recipeInstructions || [];
---
<h1 class="text-4xl">{resource?.content?.name}</h1>
<div>
{
resource?.content?.image && (
<Image
hash
src={
{ src: memorium.getImageUrl(resource.content.image) } as ImageMetadata
}
alt="Cover for {resource?.content?.name}"
class="rounded-2xl overflow-hidden"
pictureClass="rounded-2xl box-shadow"
/>
)
}
</div>
<div
class="flex flex-col gap-4 px-4"
set:html={markdownToHtml(resource?.content?.description ?? "")}
/>
<h2 class="text-2xl px-4">Ingredients</h2>
<ul class="list-disc px-10">
{
ingredients.filter((s:string) => !!s?.length).map((ingredient: string) => (
<li set:html={markdownToHtml(ingredient)} />
))
}
</ul>
<h2 class="text-2xl px-4">Steps</h2>
<ol class="list-decimal px-10">
{
instructions.filter((s:string) => !!s?.length).map((ingredient: string) => (
<li set:html={markdownToHtml(ingredient)} />
))
}
</ol>
-40
View File
@@ -1,40 +0,0 @@
---
import * as memorium from "@helpers/memorium";
import { markdownToHtml } from "@helpers/markdown";
import Image from "@components/Image.astro";
import type { ImageMetadata } from "astro";
const { resource } = Astro.props;
function formatRating(rating: string | number) {
if (typeof rating === "number") {
return "⭐".repeat(rating);
}
return rating;
}
---
<div>
{
resource?.content?.image && (
<Image
hash
src={
{ src: memorium.getImageUrl(resource.content.image) } as ImageMetadata
}
alt="Cover for {resource?.content?.name}"
class="rounded-2xl overflow-hidden"
pictureClass="rounded-2xl w-1/2 mr-4 mb-4 float-left box-shadow"
/>
)
}
<h1 class="text-4xl mb-4">
{resource?.content?.itemReviewed?.name || "Unknown Name"}
</h1>
{
resource?.content?.reviewRating?.ratingValue !== undefined && (
<div>{formatRating(resource?.content?.reviewRating?.ratingValue)}</div>
)
}
<div set:html={markdownToHtml(resource?.content?.reviewBody)} />
</div>
-37
View File
@@ -1,37 +0,0 @@
const collection = "resources";
export type ResourceType = {
id: "articles" | "recipes" | "movies" | "series";
collection: string;
cover: string;
};
const articles = {
id: "articles",
collection,
cover:
"https://i0.wp.com/old-dressaday-images.s3-website-us-west-2.amazonaws.com/6a0133ed1b1479970b0134809d9f8b970c.jpg",
} as const;
const recipes = {
id: "recipes",
collection,
cover:
"https://marka.max-richter.dev/resources/recipes/images/auberginen_reispfanne.webp",
} as const;
const movies = {
id: "movies",
collection,
cover:
"https://marka.max-richter.dev/resources/movies/images/2001_a_space_odyssey_cover.jpg",
} as const;
const series = {
id: "series",
collection,
cover:
"https://marka.max-richter.dev/resources/series/images/arcane_cover.jpg",
} as const;
export const resources: ResourceType[] = [recipes, articles, movies, series];
-68
View File
@@ -1,68 +0,0 @@
export type MemoriumFile = {
type: "file";
name: string;
path: string;
modTime: string;
mime: string;
size: string;
content: any;
};
export type MemoriumDir = {
type: "dir";
name: string;
path: string;
modTime: string;
mime: string;
size: string;
content: MemoriumEntry[];
};
export type MemoriumEntry = MemoriumFile | MemoriumDir;
const SERVER_URL = "https://marka.max-richter.dev";
//const SERVER_URL = "http://localhost:8080";
const cache = {};
export async function listResource(
id: string,
): Promise<MemoriumEntry | undefined> {
const url = `${SERVER_URL}/resources/${id}`;
if (cache[url]) return cache[url];
try {
const response = await fetch(url, { signal: AbortSignal.timeout(5000) });
if (response.ok) {
const json = await response.json();
if (json.type == "dir") {
const res = {
...json,
content: json.content.filter((res: MemoriumEntry) =>
res.mime === "application/markdown"
),
};
cache[url] = res;
return res;
}
cache[url] = json;
return json;
}
} catch (_e) {
console.log("Failed to get: ", url);
cache[url] = undefined;
return;
}
}
export function getImageUrl(input: string): string {
if (!input) {
return;
}
if (input.startsWith("https://") || input.startsWith("http://")) {
return input;
}
if (input.startsWith("/")) {
return `${SERVER_URL}${input}`;
}
return `${SERVER_URL}/${input}`;
}
-18
View File
@@ -24,14 +24,6 @@ export const ui = {
"nav.photos": "Photos",
"toc.title": "Table of Contents",
"resume": "Resume",
"articles": "📰 Articles",
"articles.description": "Random articles that impressed me while reading.",
"movies": "🎥 Movies",
"movies.description": "Watched, not watched, found good, found bad.",
"recipes": "🍲 Recipes",
"recipes.description": "Things I have cooked or want to cook.",
"series": "📺 Series",
"series.description": "Series I have watched or plan to watch.",
},
de: {
"en": "English",
@@ -51,16 +43,6 @@ export const ui = {
"nav.photos": "Fotos",
"resume": "Lebenslauf",
"toc.title": "Inhaltsverzeichnis",
"articles": "📰 Artikel",
"articles.description":
"Random Artikel die mich beim Lesen beindruckt haben",
"movies": "🎥 Filme",
"movies.description":
"Gesehen, nicht gesehen, für gut befunden, für schlecht befunden.",
"recipes": "🍲 Rezepte",
"recipes.description": "Sachen die ich gekocht habe oder kochen will",
"series": "📺 Serien",
"series.description": "Serien die ich angeguckt habe",
},
} as const;
@@ -1,67 +0,0 @@
---
import Layout from "@layouts/Layout.astro";
import { useTranslatedPath } from "@i18n/utils";
import ResourceDisplay from "@components/resources/Display.astro";
import * as memorium from "@helpers/memorium";
import { resources as resourceTypes } from "@content/resources.ts";
const { resourceType, resourceName } = Astro?.params;
const path = useTranslatedPath(Astro.url);
export async function getStaticPaths() {
try {
const paths = await Promise.all(
resourceTypes.map(async (resourceType) => {
const resources = await memorium.listResource(resourceType.id);
return resources?.content?.map((res: any) => {
return {
params: {
resourceType: resourceType.id,
resourceName: res?.name?.replace(/\.md$/, ""),
},
};
});
}),
);
return paths.flat().filter(Boolean);
} catch (err) {
return [];
}
}
const resource = await memorium.listResource(
`${resourceType}/${resourceName}.md`,
);
---
<Layout title="Max Richter">
<div class="top-info flex items-center place-content-between m-y-2">
<a
class="flex items-center gap-1 opacity-50"
href={path("/resources/" + resourceType)}>
<span class="i-tabler-arrow-left"></span> back
</a>
<div class="links">
{
resource?.content?.url && (
<a class="flex gap-1 items-center" href={resource?.content?.url}>
source link
<span class="inline-block w-3 h-3 i-tabler-external-link" />
</a>
)
}
</div>
<div class="date opacity-50">
{
resource?.content.datePublished?.toLocaleString("en-US", {
month: "long",
day: "numeric",
year: "numeric",
})
}
</div>
</div>
<ResourceDisplay resource={resource} />
</Layout>
@@ -1,87 +0,0 @@
---
import Layout from "@layouts/Layout.astro";
import HeroCard from "@components/HeroCard.astro";
import * as memorium from "@helpers/memorium";
import { resources as resourceTypes } from "@content/resources.ts";
import { useTranslations } from "@i18n/utils";
import ClientSearch from "@components/ClientSearch.svelte";
const { resourceType } = Astro.params;
const t = useTranslations(Astro.url);
async function safeGetResource() {
try {
return await memorium.listResource(resourceType);
} catch (error) {
return { content: [] };
}
}
const resources = await safeGetResource();
export async function getStaticPaths() {
return resourceTypes.map((type: any) => {
return {
params: {
resourceType: type.id,
},
};
});
}
function isValidResource(res: any) {
return !!res?.content?._type;
}
function buildSearchTerm(res: any) {
if (!res) return "";
return Object.keys(res)
.map((key) => {
if (key.startsWith("_")) return;
const value = res[key];
if (Array.isArray(value)) return value.join(" ");
if (typeof value === "object") return buildSearchTerm(value);
return value;
})
.filter((s) => !!s?.length)
.join(" ")
.toLowerCase();
}
---
<Layout title="Max Richter">
<h1 class="text-4xl mb-4">{t(resourceType)}</h1>
<p>{t(`${resourceType as "articles"}.description`)}</p>
<ClientSearch client:load />
<div id="resource-list-static" class="flex flex-col gap-6">
{
resources?.content
.filter((res: any) => isValidResource(res))
.map((resource: any) => (
<div data-search-term={buildSearchTerm(resource?.content)}>
<HeroCard
post={{
collection: "resources/" + resourceType,
id: resource.name.replace(/\.md$/, ""),
data: {
title:
resource?.content?.name ??
resource?.content?.headline ??
resource.content?.itemReviewed?.name,
date: resource?.content?.datePublished,
author: resource?.content?.author?.name,
rating: resource?.content?.reviewRating?.ratingValue,
cover: {
src: memorium.getImageUrl(resource.content.image),
},
},
}}
/>
</div>
))
}
</div>
</Layout>
-53
View File
@@ -1,53 +0,0 @@
---
import Layout from "@layouts/Layout.astro";
import HeroCard from "@components/HeroCard.astro";
import { resources } from "@content/resources.ts";
import { useTranslations } from "@i18n/utils";
import * as memorium from "@helpers/memorium";
const t = useTranslations(Astro.url);
async function getCoverImage(resourceName: string) {
const resources = await memorium.listResource(resourceName);
if (!resources?.content) return "";
let amount = 0;
while (true) {
amount++;
const randomResource =
resources?.content[Math.floor(Math.random() * resources?.content.length)];
const cover =
randomResource?.content?.cover || randomResource?.content?.image;
if (cover) {
if (cover.startsWith("https://") || cover.startsWith("http://")) {
continue;
}
return `https://marka.max-richter.dev/${cover}`;
}
if (amount > 50) {
break;
}
}
}
---
<Layout title="Max Richter">
{
await Promise.all(
resources.map(async (resource) => {
const cover = await getCoverImage(resource.id);
return (
<HeroCard
post={{
...resource,
body: t(`${resource.id}.description`),
data: {
cover: { src: cover },
title: t(resource.id),
},
}}
/>
);
}),
)
}
</Layout>