feat: add personal playlists and shareable track links
release / release (версия и заметки) (push) Successful in 6s
release / android (APK в релиз) (push) Successful in 4m8s

EOF

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
mrleo1nidandCursor committed 2026-10-21 23:37:53 +03:00
1 parent 3a097c15c8
commit fa79394869
46 files changed
+2307 -292

No files matched your search

+7 -3
View File
@@ -1,7 +1,8 @@
import type { components } from '@pipu/api-client';
import { Link } from '@tanstack/react-router';
import { useVirtualizer } from '@tanstack/react-virtual';
import { Fragment, useRef } from 'react';
import { Fragment, useRef, type ReactNode } from 'react';
import { AddToPlaylist } from './playlists';
import { useTranslation } from 'react-i18next';
import { formatDuration } from '../shared/lib/format';
@@ -115,6 +116,7 @@ export function TrackList({
rowMeta,
lead,
disliked,
actions,
}: {
tracks: Track[];
showAlbum?: boolean;
@@ -126,6 +128,7 @@ export function TrackList({
lead?: (t: Track, i: number) => string;
/** Список дизлайков: строки приглушены, вместо лайка — «снять дизлайк». */
disliked?: boolean;
actions?: (track: Track, index: number) => ReactNode;
}) {
const { t } = useTranslation();
const player = usePlayer();
@@ -154,7 +157,7 @@ export function TrackList({
className={cx(s.track, !tr.available && s.unavailable, isCurrent && s.current)}
title={tr.available ? undefined : t('catalog.unavailable')}
onClick={(e) => {
if (!(e.target as HTMLElement).closest('a, button')) play();
if (e.currentTarget.contains(e.target as Node) && !(e.target as HTMLElement).closest('a, button')) play();
}}
onKeyDown={(e) => {
if (e.key === 'Enter' && e.target === e.currentTarget) play();
@@ -181,7 +184,8 @@ export function TrackList({
{tr.album.title}
</Link>
)}
<span className={s.end}>
<span className={s.end} data-playlist-actions={actions ? true : undefined}>
{actions ? actions(tr, i) : <AddToPlaylist trackIds={[tr.id]} compact />}
{disliked ? (
<button
type="button"