chore: remove resource pages, now published from notes
Deploy to SFTP Server / build (push) Successful in 4m18s
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:
11 files changed
-515
No files matched your search
@@ -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>
|
||||
@@ -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)}
|
||||
/>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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];
|
||||
@@ -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}`;
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
Reference in new issue
Block a user