diff --git a/api/services/dump-service.ts b/api/services/dump-service.ts
index f007f63..ac369a1 100644
--- a/api/services/dump-service.ts
+++ b/api/services/dump-service.ts
@@ -107,7 +107,9 @@ export async function createUrlDump(
broadcastNewDump(dump);
notifyUserFollowersNewDump(userId, dumpId, title);
}
- if (request.comment) notifyMentions(userId, request.comment, "dump", dumpId, title);
+ if (request.comment) {
+ notifyMentions(userId, request.comment, "dump", dumpId, title);
+ }
return dump;
}
@@ -335,7 +337,13 @@ export async function updateDump(
if (updatedDump.isPrivate && !dump.isPrivate) broadcastDumpDeleted(dumpId);
else if (!updatedDump.isPrivate) broadcastDumpUpdated(updatedDump);
if (updatedDump.comment) {
- notifyMentions(dump.userId, updatedDump.comment, "dump", dumpId, updatedDump.title);
+ notifyMentions(
+ dump.userId,
+ updatedDump.comment,
+ "dump",
+ dumpId,
+ updatedDump.title,
+ );
}
return updatedDump;
}
diff --git a/api/services/notification-service.ts b/api/services/notification-service.ts
index 85686fe..85793ce 100644
--- a/api/services/notification-service.ts
+++ b/api/services/notification-service.ts
@@ -207,9 +207,11 @@ export function notifyMentions(
).get(mentionerUserId) as { username: string } | undefined;
if (!mentionerRow) return;
- const usernames = [...new Set(
- [...body.matchAll(MENTION_RE)].map((m) => m[1].toLowerCase()),
- )];
+ const usernames = [
+ ...new Set(
+ [...body.matchAll(MENTION_RE)].map((m) => m[1].toLowerCase()),
+ ),
+ ];
for (const username of usernames) {
const mentionedRow = db.prepare(
diff --git a/api/services/playlist-service.ts b/api/services/playlist-service.ts
index f3414c7..afec7e7 100644
--- a/api/services/playlist-service.ts
+++ b/api/services/playlist-service.ts
@@ -73,7 +73,9 @@ export function createPlaylist(
isPublic: req.isPublic,
createdAt,
};
- if (req.description) notifyMentions(userId, req.description, "playlist", id, req.title);
+ if (req.description) {
+ notifyMentions(userId, req.description, "playlist", id, req.title);
+ }
broadcastPlaylistCreated(playlist);
return playlist;
}
@@ -157,7 +159,14 @@ export function updatePlaylist(
const newSlug = makeSlug(newTitle, playlist.id);
db.prepare(
`UPDATE playlists SET title = ?, slug = ?, description = ?, is_public = ?, updated_at = ? WHERE id = ?;`,
- ).run(newTitle, newSlug, newDescription, newIsPublic ? 1 : 0, now.toISOString(), playlist.id);
+ ).run(
+ newTitle,
+ newSlug,
+ newDescription,
+ newIsPublic ? 1 : 0,
+ now.toISOString(),
+ playlist.id,
+ );
const updated: Playlist = {
...playlist,
@@ -167,7 +176,15 @@ export function updatePlaylist(
isPublic: newIsPublic,
updatedAt: now,
};
- if (newDescription) notifyMentions(requestingUserId, newDescription, "playlist", playlist.id, newTitle);
+ if (newDescription) {
+ notifyMentions(
+ requestingUserId,
+ newDescription,
+ "playlist",
+ playlist.id,
+ newTitle,
+ );
+ }
broadcastPlaylistUpdated(updated);
return updated;
}
diff --git a/src/App.css b/src/App.css
index 627d370..11e3619 100644
--- a/src/App.css
+++ b/src/App.css
@@ -2666,8 +2666,12 @@ body.has-player .fab-new {
}
@keyframes comment-highlight {
- 0% { background: color-mix(in srgb, var(--color-accent) 18%, transparent); }
- 100% { background: transparent; }
+ 0% {
+ background: color-mix(in srgb, var(--color-accent) 18%, transparent);
+ }
+ 100% {
+ background: transparent;
+ }
}
.comment-node--highlight {
border-radius: 6px;
diff --git a/src/components/CommentThread.tsx b/src/components/CommentThread.tsx
index cbf8eb6..2139c99 100644
--- a/src/components/CommentThread.tsx
+++ b/src/components/CommentThread.tsx
@@ -161,7 +161,9 @@ function CommentNode({
{children.length > 0 && (
= MAX_INDENT_DEPTH ? { paddingLeft: 0, marginLeft: 0, borderLeft: "none" } : undefined}
+ style={depth >= MAX_INDENT_DEPTH
+ ? { paddingLeft: 0, marginLeft: 0, borderLeft: "none" }
+ : undefined}
>
{children.map((child) => (
{
- if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) handleEditSave(e);
+ if (
+ e.key === "Enter" && (e.ctrlKey || e.metaKey)
+ ) handleEditSave(e);
}}
autoResize
rows={1}
@@ -299,7 +303,10 @@ function CommentNode({
{ setConfirmDelete(false); handleDelete(); }}
+ onConfirm={() => {
+ setConfirmDelete(false);
+ handleDelete();
+ }}
onCancel={() => setConfirmDelete(false)}
/>
)}
@@ -312,7 +319,9 @@ function CommentNode({
value={replyBody}
onChange={setReplyBody}
onKeyDown={(e) => {
- if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) handleReply(e);
+ if (
+ e.key === "Enter" && (e.ctrlKey || e.metaKey)
+ ) handleReply(e);
}}
placeholder="Write a reply…"
autoResize
@@ -348,7 +357,9 @@ function CommentNode({
{children.length > 0 && (
= MAX_INDENT_DEPTH ? { paddingLeft: 0, marginLeft: 0, borderLeft: "none" } : undefined}
+ style={depth >= MAX_INDENT_DEPTH
+ ? { paddingLeft: 0, marginLeft: 0, borderLeft: "none" }
+ : undefined}
>
{children.map((child) => (
{
- if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) handleTopLevelSubmit(e);
+ if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
+ handleTopLevelSubmit(e);
+ }
}}
placeholder="Add a comment…"
autoResize
diff --git a/src/components/DumpCreateModal.tsx b/src/components/DumpCreateModal.tsx
index 126b357..5b26f6a 100644
--- a/src/components/DumpCreateModal.tsx
+++ b/src/components/DumpCreateModal.tsx
@@ -13,7 +13,6 @@ import type {
import { deserializeDump, deserializePlaylistMembership } from "../model.ts";
import { useAuth } from "../hooks/useAuth.ts";
import { useWS } from "../hooks/useWS.ts";
-import { formatBytes } from "../utils/format.ts";
import { dumpUrl } from "../utils/urls.ts";
import RichContentCard from "./RichContentCard.tsx";
import { MediaPlayer } from "./MediaPlayer.tsx";
diff --git a/src/components/FileDropZone.tsx b/src/components/FileDropZone.tsx
index fdcabf8..bea7a74 100644
--- a/src/components/FileDropZone.tsx
+++ b/src/components/FileDropZone.tsx
@@ -71,23 +71,21 @@ export function FileDropZone({
{label &&
{label}}
{
- if (e.key === "Enter" || e.key === " ") {
- e.preventDefault();
- handleClick();
- }
- }
- }
+ onKeyDown={file || disabled ? undefined : (e) => {
+ if (e.key === "Enter" || e.key === " ") {
+ e.preventDefault();
+ handleClick();
+ }
+ }}
>
{
if (deletedDumpIds.size === 0) return;
- setDumpsRef.current((prev) => prev.filter((d) => !deletedDumpIds.has(d.id)));
+ setDumpsRef.current((prev) =>
+ prev.filter((d) => !deletedDumpIds.has(d.id))
+ );
}, [deletedDumpIds]);
useEffect(() => {
diff --git a/src/hooks/useMentionAutocomplete.ts b/src/hooks/useMentionAutocomplete.ts
index 40a4464..18b2341 100644
--- a/src/hooks/useMentionAutocomplete.ts
+++ b/src/hooks/useMentionAutocomplete.ts
@@ -1,4 +1,10 @@
-import { useCallback, useEffect, useRef, useState, type RefObject } from "react";
+import {
+ type RefObject,
+ useCallback,
+ useEffect,
+ useRef,
+ useState,
+} from "react";
import { API_URL } from "../config/api.ts";
export interface UserResult {
@@ -70,7 +76,9 @@ export function useMentionAutocomplete(
debounceRef.current = setTimeout(async () => {
try {
const res = await fetch(
- `${API_URL}/api/users/search?q=${encodeURIComponent(mention.query)}`,
+ `${API_URL}/api/users/search?q=${
+ encodeURIComponent(mention.query)
+ }`,
);
const body = await res.json();
if (body.success && body.data.length > 0) {
diff --git a/src/pages/Dump.tsx b/src/pages/Dump.tsx
index fdaad3a..e259015 100644
--- a/src/pages/Dump.tsx
+++ b/src/pages/Dump.tsx
@@ -125,7 +125,10 @@ export function Dump() {
if (!el) return;
el.scrollIntoView({ behavior: "smooth", block: "start" });
el.classList.add("comment-node--highlight");
- const t = setTimeout(() => el.classList.remove("comment-node--highlight"), 2000);
+ const t = setTimeout(
+ () => el.classList.remove("comment-node--highlight"),
+ 2000,
+ );
return () => clearTimeout(t);
}, [comments, location.hash]);
diff --git a/src/pages/DumpCreate.tsx b/src/pages/DumpCreate.tsx
index c600b82..fdfeb6d 100644
--- a/src/pages/DumpCreate.tsx
+++ b/src/pages/DumpCreate.tsx
@@ -5,7 +5,6 @@ import { Link, useNavigate } from "react-router";
import { API_URL } from "../config/api.ts";
import type { CreateUrlDumpRequest, RichContent } from "../model.ts";
import { useRequiredAuth } from "../hooks/useAuth.ts";
-import { formatBytes } from "../utils/format.ts";
import { dumpUrl } from "../utils/urls.ts";
import { PageShell } from "../components/PageShell.tsx";
import RichContentCard from "../components/RichContentCard.tsx";
diff --git a/src/pages/Notifications.tsx b/src/pages/Notifications.tsx
index 926fe3b..60276b1 100644
--- a/src/pages/Notifications.tsx
+++ b/src/pages/Notifications.tsx
@@ -97,7 +97,9 @@ function notificationLink(n: Notification): string {
return `/dumps/${(data as DumpUpvotedData).dumpId}`;
case "user_mentioned": {
const d = data as UserMentionedData;
- if (d.contextType === "comment") return `/dumps/${d.dumpId}#comment-${d.contextId}`;
+ if (d.contextType === "comment") {
+ return `/dumps/${d.dumpId}#comment-${d.contextId}`;
+ }
if (d.contextType === "dump") return `/dumps/${d.contextId}`;
return `/playlists/${d.contextId}`;
}
@@ -109,28 +111,64 @@ function notificationContent(n: Notification): React.ReactNode {
switch (n.type) {
case "user_followed": {
const d = data as UserFollowedData;
- return <>
{d.followerUsername}{" started following you"}>;
+ return (
+ <>
+
{d.followerUsername}
+ {" started following you"}
+ >
+ );
}
case "playlist_followed": {
const d = data as PlaylistFollowedData;
- return <>
{d.followerUsername}{" followed your playlist "}
{d.playlistTitle}>;
+ return (
+ <>
+
{d.followerUsername}
+ {" followed your playlist "}
+
{d.playlistTitle}
+ >
+ );
}
case "user_dump_posted": {
const d = data as UserDumpPostedData;
- return <>
{d.dumperUsername}{" posted "}
{d.dumpTitle}>;
+ return (
+ <>
+
{d.dumperUsername}
+ {" posted "}
+
{d.dumpTitle}
+ >
+ );
}
case "playlist_dump_added": {
const d = data as PlaylistDumpAddedData;
- return <>
{d.dumpTitle}{" was added to "}
{d.playlistTitle}>;
+ return (
+ <>
+
{d.dumpTitle}
+ {" was added to "}
+
{d.playlistTitle}
+ >
+ );
}
case "dump_upvoted": {
const d = data as DumpUpvotedData;
- return <>
{d.voterUsername}{" upvoted "}
{d.dumpTitle}>;
+ return (
+ <>
+
{d.voterUsername}
+ {" upvoted "}
+
{d.dumpTitle}
+ >
+ );
}
case "user_mentioned": {
const d = data as UserMentionedData;
- const where = d.contextTitle || (d.contextType === "comment" ? "a comment" : "a post");
- return <>
{d.mentionerUsername}{" mentioned you in "}
{where}>;
+ const where = d.contextTitle ||
+ (d.contextType === "comment" ? "a comment" : "a post");
+ return (
+ <>
+
{d.mentionerUsername}
+ {" mentioned you in "}
+
{where}
+ >
+ );
}
}
}
diff --git a/src/pages/PlaylistDetail.tsx b/src/pages/PlaylistDetail.tsx
index f6f4f84..5d67436 100644
--- a/src/pages/PlaylistDetail.tsx
+++ b/src/pages/PlaylistDetail.tsx
@@ -341,7 +341,9 @@ export function PlaylistDetail() {
dumpMap.set(dump.id, dump);
const reinserted = order.length > 0
? [
- ...order.filter((id) => dumpMap.has(id)).map((id) => dumpMap.get(id)!),
+ ...order.filter((id) => dumpMap.has(id)).map((id) =>
+ dumpMap.get(id)!
+ ),
...prev.playlist.dumps.filter((d) => !new Set(order).has(d.id)),
]
: [...prev.playlist.dumps, dump];
@@ -684,7 +686,9 @@ export function PlaylistDetail() {
{playlist.updatedAt && (
-
+
edited {relativeTime(playlist.updatedAt)}
@@ -705,7 +709,9 @@ export function PlaylistDetail() {
: (
e.preventDefault() : undefined}
+ onDragOver={isOwner
+ ? (e) => e.preventDefault()
+ : undefined}
>
{visibleDumps.map((dump) => {
const isActive = activeDumpIds.has(dump.id);
diff --git a/src/pages/UserLogin.tsx b/src/pages/UserLogin.tsx
index 429e8b7..b3ab6de 100644
--- a/src/pages/UserLogin.tsx
+++ b/src/pages/UserLogin.tsx
@@ -1,6 +1,6 @@
import { useState } from "react";
import type { SubmitEvent } from "react";
-import { Link, useNavigate } from "react-router";
+import { useNavigate } from "react-router";
import { API_URL } from "../config/api.ts";
import { deserializeAuthResponse } from "../model.ts";
diff --git a/src/pages/UserPlaylists.tsx b/src/pages/UserPlaylists.tsx
index 54c5a45..7fc24c8 100644
--- a/src/pages/UserPlaylists.tsx
+++ b/src/pages/UserPlaylists.tsx
@@ -77,7 +77,9 @@ export function UserPlaylists() {
const setCreated = useCallback((fn: (prev: Playlist[]) => Playlist[]) => {
setState((s) =>
- s.status !== "loaded" ? s : { ...s, created: { ...s.created, items: fn(s.created.items) } }
+ s.status !== "loaded"
+ ? s
+ : { ...s, created: { ...s.created, items: fn(s.created.items) } }
);
}, []);
usePlaylistListSync(setCreated, {
diff --git a/src/pages/UserPublicProfile.tsx b/src/pages/UserPublicProfile.tsx
index e352da8..0cde98a 100644
--- a/src/pages/UserPublicProfile.tsx
+++ b/src/pages/UserPublicProfile.tsx
@@ -1,4 +1,10 @@
-import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
+import React, {
+ useCallback,
+ useEffect,
+ useLayoutEffect,
+ useRef,
+ useState,
+} from "react";
import { Link, useNavigate, useParams } from "react-router";
import { API_URL } from "../config/api.ts";
@@ -151,7 +157,9 @@ export function UserPublicProfile() {
if (next.length < prev.length) {
const nextIds = new Set(next.map((d) => d.id));
prev.forEach((d, idx) => {
- if (!nextIds.has(d.id)) removedDumpPositionsRef.current.set(d.id, idx);
+ if (!nextIds.has(d.id)) {
+ removedDumpPositionsRef.current.set(d.id, idx);
+ }
});
}
return { ...s, dumps: { ...s.dumps, items: next } };
@@ -180,7 +188,9 @@ export function UserPublicProfile() {
if (next.length < prev.length) {
const nextIds = new Set(next.map((d) => d.id));
prev.forEach((d, idx) => {
- if (!nextIds.has(d.id)) removedVotePositionsRef.current.set(d.id, idx);
+ if (!nextIds.has(d.id)) {
+ removedVotePositionsRef.current.set(d.id, idx);
+ }
});
}
return { ...s, votes: { ...s.votes, items: next } };
@@ -422,7 +432,6 @@ export function UserPublicProfile() {
}
}, [lastVoteEvent, me, profileUserId]);
-
// Save scroll position + loaded state to sessionStorage on scroll
useEffect(() => {
if (state.status !== "loaded") return;