learn and share notes on atproto (wip) 馃
malfestio.stormlightlabs.org/
readability
solid
axum
atproto
srs
1import { useDensity } from "$lib/density-context";
2import type { DensityMode } from "$lib/design-tokens";
3import type { Note } from "$lib/model";
4import { Card } from "$ui/Card";
5import { Tag } from "$ui/Tag";
6import { A } from "@solidjs/router";
7import type { Component } from "solid-js";
8import { For, Show } from "solid-js";
9
10type NoteCardProps = { note: Note; density?: DensityMode };
11
12export const NoteCard: Component<NoteCardProps> = (props) => {
13 const globalDensity = useDensity();
14 const density = () => props.density || globalDensity;
15
16 const truncateBody = (body: string, maxLength: number) => {
17 const plainText = body.replace(/[#*`[\]]/g, "").trim();
18 return plainText.length > maxLength ? plainText.slice(0, maxLength) + "..." : plainText;
19 };
20
21 const paddingClass = () => {
22 const d = density();
23 return d === "compact" ? "p-4" : d === "spacious" ? "p-8" : "p-6";
24 };
25
26 return (
27 <A href={`/notes/${props.note.id}`} class="block h-full no-underline group">
28 <Card class="h-full flex flex-col hover:border-blue-400 dark:hover:border-blue-500 transition-colors">
29 <div class={`${paddingClass()} flex-1 space-y-3`}>
30 <div class="space-y-1">
31 <h3 class="text-lg font-semibold text-slate-900 dark:text-white line-clamp-1 group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors">
32 {props.note.title || "Untitled"}
33 </h3>
34 <p class="text-xs text-slate-500 dark:text-slate-400">
35 {props.note.updated_at ? new Date(props.note.updated_at).toLocaleDateString() : ""}
36 </p>
37 </div>
38
39 <p class="text-sm text-slate-600 dark:text-slate-300 line-clamp-3">{truncateBody(props.note.body, 120)}</p>
40
41 <Show when={props.note.tags.length > 0}>
42 <div class="flex flex-wrap gap-1.5 pt-2">
43 <For each={props.note.tags.slice(0, 3)}>
44 {(tag) => <Tag label={tag} color="blue" density={density()} />}
45 </For>
46 <Show when={props.note.tags.length > 3}>
47 <span class="text-xs text-slate-400">+{props.note.tags.length - 3}</span>
48 </Show>
49 </div>
50 </Show>
51 </div>
52 </Card>
53 </A>
54 );
55};