ddix-solid/src/routes/news/index.tsx
2024-05-22 09:35:22 +02:00

98 lines
2.7 KiB
TypeScript

import { createSignal, For, createMemo } from "solid-js";
import { cache, createAsync, A, type RouteDefinition } from "@solidjs/router";
import { classList } from "solid-js/web";
const getNewsList = cache(async () => {
"use server";
return await fetch("https://content.dd-ix.net/news/en").then((data) =>
data.json()
);
}, "news-list");
const getNewsTags = cache(async () => {
"use server";
return await fetch("https://content.dd-ix.net/news/keywords").then((data) =>
data.json()
);
}, "news-tags");
export const route = {
load: () => {
getNewsList();
getNewsTags();
},
} satisfies RouteDefinition;
export default () => {
const newsList = createAsync(() => getNewsList());
const tagsData = createAsync(() => getNewsTags());
const [tags, setTags] = createSignal(
Object.fromEntries(
tagsData()?.map((tag: string) => [tag, { active: false }]) ?? []
)
);
const tagsActive = createMemo(() =>
Object.entries(tags())
.filter(([, { active }]) => active)
.map(([tag]) => tag)
);
return (
<main class="container mx-auto p-4">
<h1 class="mb-12 mt-40">News</h1>
<div class="flex flex-wrap gap-2">
<For each={Object.entries(tags())}>
{([tag, { active }]) => (
<button
class="btn btn-sm"
classList={{ "btn-primary": active }}
onClick={() =>
setTags({
...tags(),
[tag]: { active: !active },
})
}
>
{tag}
</button>
)}
</For>
</div>
<For
each={
tagsActive()?.length
? newsList()?.filter((news) =>
Object.entries(tags())
.filter(([, state]) => state.active)
.some(([tag]) => news.keywords.includes(tag))
)
: newsList()
}
>
{(post) => (
<A href={`/news/${post.slug}`}>
<figure class="card md:card-side bg-base-100 shadow-xl mt-4">
<img
src={`https://content.dd-ix.net/news/assets/${post.image}`}
alt={post.title}
class="md:w-48 object-cover"
/>
<div class="card-body">
<h2 class="card-title">{post.title}</h2>
<p>{post.published}</p>
<p>{post.description}</p>
<div class="flex gap-2">
<For each={post.keywords}>
{(tag) => <div class="badge badge-secondary">{tag}</div>}
</For>
</div>
</div>
</figure>
</A>
)}
</For>
</main>
);
};