v3: add backlinks between dumps (via either dump url or dump target url mentioned through dump description and dump comments)
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 43s

This commit is contained in:
khannurien
2026-06-21 20:30:03 +00:00
parent d038116de5
commit 4687a6b515
9 changed files with 234 additions and 0 deletions

View File

@@ -3509,6 +3509,21 @@ body.has-player .fab-new {
letter-spacing: 0.08em;
}
.related-section {
margin-top: 2.5rem;
padding-top: 1.75rem;
border-top: 2px solid var(--color-border);
}
.related-section-title {
font-size: 0.8rem;
font-weight: 700;
color: var(--color-text-muted);
margin: 0 0 1.25rem;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.comment-list {
list-style: none;
margin: 0;

View File

@@ -29,6 +29,7 @@ import { Avatar } from "../components/Avatar.tsx";
import RichContentCard from "../components/RichContentCard.tsx";
import FilePreview from "../components/FilePreview.tsx";
import { VoteButton } from "../components/VoteButton.tsx";
import { DumpCard } from "../components/DumpCard.tsx";
import { PageShell } from "../components/PageShell.tsx";
import { PageError } from "../components/PageError.tsx";
import { Markdown } from "../components/Markdown.tsx";
@@ -54,6 +55,7 @@ export function Dump() {
const [playlistModalOpen, setPlaylistModalOpen] = useState(false);
const [comments, setComments] = useState<Comment[]>([]);
const [relatedDumps, setRelatedDumps] = useState<Dump[]>([]);
const [titleEditing, setTitleEditing] = useState(false);
const [titleDraft, setTitleDraft] = useState("");
@@ -145,6 +147,24 @@ export function Dump() {
return () => controller.abort();
}, [selectedDump, token]);
// Fetch related dumps (backlinks) when dump loads
useEffect(() => {
if (!selectedDump) return;
const controller = new AbortController();
fetch(`${API_URL}/api/dumps/${selectedDump}/related`, {
signal: controller.signal,
headers: token ? { Authorization: `Bearer ${token}` } : {},
})
.then((r) => r.json())
.then((body) => {
if (body.success) {
setRelatedDumps((body.data as RawDump[]).map(deserializeDump));
}
})
.catch(() => {});
return () => controller.abort();
}, [selectedDump, token]);
// Scroll to and highlight a comment when navigating to #comment-{id}
useEffect(() => {
if (!location.hash.startsWith("#comment-")) return;
@@ -440,6 +460,28 @@ export function Dump() {
</Link>
</div>
{/* Related (backlinks) */}
{relatedDumps.length > 0 && (
<section className="related-section">
<h2 className="related-section-title">
<Trans>Related</Trans>
</h2>
<ul className="dump-feed">
{relatedDumps.map((related) => (
<DumpCard
key={related.id}
dump={related}
voteCount={voteCounts[related.id] ?? related.voteCount}
voted={myVotes.has(related.id)}
canVote={!!user}
castVote={castVote}
removeVote={removeVote}
/>
))}
</ul>
</section>
)}
{/* Comments */}
<CommentThread
dumpId={dump.id}