v3: added localization, use global player for uploaded audio/video files

This commit is contained in:
khannurien
2026-04-03 15:29:33 +00:00
parent 378b3ffa46
commit 0ce80398a4
64 changed files with 4248 additions and 941 deletions

View File

@@ -1,5 +1,7 @@
import { useCallback, useEffect, useRef, useState } from "react";
import { Link, useSearchParams } from "react-router";
import { t } from "@lingui/core/macro"
import { Trans } from "@lingui/react/macro";
import { AppHeader } from "../components/AppHeader.tsx";
import { SearchBar } from "../components/SearchBar.tsx";
import { DumpCard } from "../components/DumpCard.tsx";
@@ -151,10 +153,10 @@ export function Search() {
!state.dumps.loadingMore,
);
function setTab(t: Tab) {
function setTab(tab: Tab) {
setSearchParams((prev) => {
const next = new URLSearchParams(prev);
next.set("tab", t);
next.set("tab", tab);
return next;
}, { replace: true });
}
@@ -165,13 +167,13 @@ export function Search() {
? state.playlists.length
: null;
function tabLabel(t: Tab, count: number | null) {
const label = t === "dumps"
? "Dumps"
: t === "users"
? "Users"
: "Playlists";
return count !== null ? `${label} (${count})` : label;
function tabLabel(tab: Tab, count: number | null) {
const label = tab === "dumps"
? t`Dumps`
: tab === "users"
? t`Users`
: t`Playlists`;
return count !== null ? t`${label} (${count})` : label;
}
return (
@@ -180,18 +182,18 @@ export function Search() {
<main className="search-page">
{q && (
<div className="search-tabs">
{(["dumps", "users", "playlists"] as Tab[]).map((t) => (
{(["dumps", "users", "playlists"] as Tab[]).map((tabKey) => (
<button
key={t}
key={tabKey}
type="button"
className={`feed-sort-btn${tab === t ? " active" : ""}`}
onClick={() => setTab(t)}
className={`feed-sort-btn${tab === tabKey ? " active" : ""}`}
onClick={() => setTab(tabKey)}
>
{tabLabel(
t,
t === "dumps"
tabKey,
tabKey === "dumps"
? dumpCount
: t === "users"
: tabKey === "users"
? userCount
: playlistCount,
)}
@@ -201,21 +203,21 @@ export function Search() {
)}
{state.status === "idle" && (
<p className="search-page-empty">Enter a query to search.</p>
<p className="search-page-empty"><Trans>Enter a query to search.</Trans></p>
)}
{state.status === "loading" && (
<p className="search-page-empty">Searching…</p>
<p className="search-page-empty"><Trans>Searching…</Trans></p>
)}
{state.status === "error" && (
<ErrorCard title="Search failed" message={state.error} />
<ErrorCard title={t`Search failed`} message={state.error} />
)}
{state.status === "loaded" && tab === "dumps" && (
<>
{state.dumps.items.length === 0
? <p className="search-page-empty">No dumps match "{q}".</p>
? <p className="search-page-empty">{t`No dumps match "${q}".`}</p>
: (
<ul className="dump-feed">
{state.dumps.items.map((dump) => (
@@ -234,17 +236,17 @@ export function Search() {
)}
<div ref={sentinelRef} />
{state.dumps.loadingMore && (
<p className="feed-loading-more">Loading more…</p>
<p className="feed-loading-more"><Trans>Loading more…</Trans></p>
)}
{!state.dumps.hasMore && state.dumps.items.length > 0 && (
<p className="feed-end">You've reached the end.</p>
<p className="feed-end"><Trans>You've reached the end.</Trans></p>
)}
</>
)}
{state.status === "loaded" && tab === "users" && (
state.users.length === 0
? <p className="search-page-empty">No users match "{q}".</p>
? <p className="search-page-empty">{t`No users match "${q}".`}</p>
: (
<ul className="user-results">
{state.users.map((u) => (
@@ -268,7 +270,7 @@ export function Search() {
{state.status === "loaded" && tab === "playlists" && (
state.playlists.length === 0
? <p className="search-page-empty">No playlists match "{q}".</p>
? <p className="search-page-empty">{t`No playlists match "${q}".`}</p>
: (
<ul className="dump-feed">
{state.playlists.map((p) => (