v3: follows, notifications, invite-only registration, unread markers

This commit is contained in:
khannurien
2026-03-21 18:42:47 +00:00
parent 7c098e7c4c
commit 608c6bc6a8
55 changed files with 4743 additions and 884 deletions

View File

@@ -1,6 +1,7 @@
import { Link, useNavigate } from "react-router";
import type { Dump } from "../model.ts";
import { relativeTime } from "../utils/relativeTime.ts";
import { isDumpVisited, isRecent, markDumpVisited } from "../utils/visited.ts";
import FilePreview from "./FilePreview.tsx";
import RichContentCard from "./RichContentCard.tsx";
import { VoteButton } from "./VoteButton.tsx";
@@ -22,12 +23,19 @@ export function DumpCard(
DumpCardProps,
) {
const navigate = useNavigate();
const unread = !isOwner && isRecent(dump.createdAt) &&
!isDumpVisited(dump.id);
function handleNavigate() {
markDumpVisited(dump.id);
navigate(`/dumps/${dump.id}`);
}
return (
<li className={`dump-card${className ? ` ${className}` : ""}`}>
<div
className="dump-card-inner"
onClick={() => navigate(`/dumps/${dump.id}`)}
onClick={handleNavigate}
>
<div
className="dump-card-preview"
@@ -44,12 +52,18 @@ export function DumpCard(
<Link
to={`/dumps/${dump.id}`}
className="dump-card-title"
onClick={(e) => e.stopPropagation()}
onClick={(e) => {
e.stopPropagation();
markDumpVisited(dump.id);
}}
>
{unread && <span className="unread-dot" aria-hidden="true" />}
{dump.title}
</Link>
{dump.comment && (
<Markdown className="dump-card-comment" inline>{dump.comment}</Markdown>
<Markdown className="dump-card-comment" inline>
{dump.comment}
</Markdown>
)}
<div className="dump-card-meta">
<time
@@ -61,7 +75,8 @@ export function DumpCard(
</time>
{dump.commentCount > 0 && (
<span className="dump-card-comment-count">
{dump.commentCount} {dump.commentCount === 1 ? "comment" : "comments"}
{dump.commentCount}{" "}
{dump.commentCount === 1 ? "comment" : "comments"}
</span>
)}
{dump.isPrivate && isOwner && (