mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 07:15:47 +00:00
c8e130ecea
* refactor(internet-radio): G.86.1 — extract RadioToolbar + AlphabetFilterBar First cut on InternetRadio.tsx: pulled the two header bars into their own files under src/components/internetRadio/. RadioToolbar exports the RadioSortBy type alias so the page state and the toolbar share the same union. AlphabetFilterBar owns the A-Z + # key list internally. Pure code move. * refactor(internet-radio): G.86.2 — extract RadioCard Pulled the single radio-station card component (cover, live overlay, play/delete buttons, name + edit/favourite/homepage chip row) into its own file. It owns its drag source + the psy-drop listener that fires onDropOnto with the cursor-side (before/after). Pure code move. * refactor(internet-radio): G.86.3 — extract RadioEditModal Pulled the create/edit-station modal (cover preview + change/remove, name + stream URL + homepage URL fields, save spinner) into its own file. station=null means "create new". Pure code move. * refactor(internet-radio): G.86.4 — extract RadioDirectoryModal Pulled the radio-browser directory modal (top-stations preload, debounced search, IntersectionObserver-driven pagination, favicon + add-station flow with cover upload from favicon URL) into its own file. Pure code move. InternetRadio.tsx is now 299 LOC — every subcomponent lives in src/components/internetRadio/.
44 lines
1.4 KiB
TypeScript
44 lines
1.4 KiB
TypeScript
import React from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import CustomSelect from '../CustomSelect';
|
|
|
|
export type RadioSortBy = 'manual' | 'az' | 'za' | 'newest';
|
|
|
|
interface RadioToolbarProps {
|
|
sortBy: RadioSortBy;
|
|
activeFilter: string;
|
|
onSortChange: (s: RadioSortBy) => void;
|
|
onFilterChange: (f: string) => void;
|
|
}
|
|
|
|
export default function RadioToolbar({ sortBy, activeFilter, onSortChange, onFilterChange }: RadioToolbarProps) {
|
|
const { t } = useTranslation();
|
|
const sortOptions = [
|
|
{ value: 'manual', label: t('radio.sortManual') },
|
|
{ value: 'az', label: t('radio.sortAZ') },
|
|
{ value: 'za', label: t('radio.sortZA') },
|
|
{ value: 'newest', label: t('radio.sortNewest') },
|
|
];
|
|
return (
|
|
<div className="radio-toolbar">
|
|
<div className="radio-toolbar-chips">
|
|
{(['all', 'favorites'] as const).map(f => (
|
|
<button
|
|
key={f}
|
|
className={`radio-filter-chip${activeFilter === f ? ' active' : ''}`}
|
|
onClick={() => onFilterChange(f)}
|
|
>
|
|
{f === 'all' ? t('radio.filterAll') : t('radio.filterFavorites')}
|
|
</button>
|
|
))}
|
|
</div>
|
|
<CustomSelect
|
|
value={sortBy}
|
|
options={sortOptions}
|
|
onChange={v => onSortChange(v as RadioSortBy)}
|
|
style={{ width: 'max-content', minWidth: 130, maxWidth: 220, flexShrink: 0 }}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|