Refactor Root component to accept additional props and enhance LyricSearch functionality with URL hash handling and lyrics sanitization.

This commit is contained in:
2025-10-08 15:49:00 -04:00
parent ef4c80450a
commit 4227c21d1f
3 changed files with 38 additions and 7 deletions

View File

@@ -16,7 +16,7 @@ const MediaRequestForm = lazy(() => import('./TRip/MediaRequestForm.jsx'));
const RequestManagement = lazy(() => import('./TRip/RequestManagement.jsx'));
const Player = lazy(() => import('./AudioPlayer.jsx'));
export default function Root({ child, user = undefined }) {
export default function Root({ child, user = undefined, ...props }) {
window.toast = toast;
const theme = document.documentElement.getAttribute("data-theme")
usePrimeReactThemeSwitcher(theme);
@@ -35,7 +35,7 @@ export default function Root({ child, user = undefined }) {
Work in progress... bugs are to be expected.
</Alert> */}
{child == "LoginPage" && (<LoginPage client:only="react" />)}
{child == "LyricSearch" && (<LyricSearch client:only="react" />)}
{child == "LyricSearch" && (<LyricSearch {...props} client:only="react" />)}
{child == "Player" && (<Player client:only="react" user={user} />)}
{child == "Memes" && <Memes client:only="react" />}
{child == "qs2.MediaRequestForm" && <MediaRequestForm client:only="react" />}

View File

@@ -18,6 +18,7 @@ import { API_URL } from '../config';
export default function LyricSearch() {
const [showLyrics, setShowLyrics] = useState(false);
return (
<div className="lyric-search">
<h2 className="title">
@@ -52,6 +53,29 @@ export function LyricSearchInputField({ id, placeholder, setShowLyrics }) {
const autoCompleteRef = useRef(null);
const [theme, setTheme] = useState(document.documentElement.getAttribute("data-theme") || "light");
// Handle URL hash changes and initial load
useEffect(() => {
const handleHashChange = () => {
const hash = window.location.hash.slice(1); // Remove the # symbol
if (hash) {
try {
const [artist, song] = decodeURIComponent(hash).split('/');
if (artist && song) {
setValue(`${artist} - ${song}`);
handleSearch(`${artist} - ${song}`);
}
} catch (e) {
console.error('Failed to parse URL hash:', e);
}
}
};
window.addEventListener('hashchange', handleHashChange);
handleHashChange(); // Handle initial load
return () => window.removeEventListener('hashchange', handleHashChange);
}, []);
useEffect(() => {
const handler = (e) => {
const newTheme = e.detail;
@@ -118,17 +142,17 @@ export function LyricSearchInputField({ id, placeholder, setShowLyrics }) {
}, 0);
};
const handleSearch = async () => {
const handleSearch = async (searchValue = value) => {
if (autoCompleteRef.current) {
autoCompleteRef.current.hide();
}
if (!value.includes(" - ")) {
if (!searchValue.includes(" - ")) {
setAlertVisible(true);
return;
}
const [artist, song] = value.split(" - ", 2).map((v) => v.trim());
const [artist, song] = searchValue.split(" - ", 2).map((v) => v.trim());
if (!artist || !song) {
setAlertVisible(true);
return;
@@ -169,6 +193,10 @@ export function LyricSearchInputField({ id, placeholder, setShowLyrics }) {
setLyricsResult({ artist: data.artist, song: data.song, lyrics: data.lyrics });
setShowLyrics(true);
// Update URL hash with search parameters
const hash = `#${encodeURIComponent(data.artist)}/${encodeURIComponent(data.song)}`;
window.history.pushState(null, '', hash);
toast.update(searchToastRef.current, {
type: "success",
render: `Found! (Took ${duration}s)`,

View File

@@ -7,7 +7,10 @@ import LyricSearch from '../components/LyricSearch.jsx';
<Base>
<section>
<div class="prose prose-neutral dark:prose-invert">
<Root child="LyricSearch" client:only="react" />
<Root
child="LyricSearch"
client:only="react"
/>
</div>
</section>
</Base>