Refactor Root component to accept additional props and enhance LyricSearch functionality with URL hash handling and lyrics sanitization.
This commit is contained in:
@@ -16,7 +16,7 @@ const MediaRequestForm = lazy(() => import('./TRip/MediaRequestForm.jsx'));
|
|||||||
const RequestManagement = lazy(() => import('./TRip/RequestManagement.jsx'));
|
const RequestManagement = lazy(() => import('./TRip/RequestManagement.jsx'));
|
||||||
const Player = lazy(() => import('./AudioPlayer.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;
|
window.toast = toast;
|
||||||
const theme = document.documentElement.getAttribute("data-theme")
|
const theme = document.documentElement.getAttribute("data-theme")
|
||||||
usePrimeReactThemeSwitcher(theme);
|
usePrimeReactThemeSwitcher(theme);
|
||||||
@@ -35,7 +35,7 @@ export default function Root({ child, user = undefined }) {
|
|||||||
Work in progress... bugs are to be expected.
|
Work in progress... bugs are to be expected.
|
||||||
</Alert> */}
|
</Alert> */}
|
||||||
{child == "LoginPage" && (<LoginPage client:only="react" />)}
|
{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 == "Player" && (<Player client:only="react" user={user} />)}
|
||||||
{child == "Memes" && <Memes client:only="react" />}
|
{child == "Memes" && <Memes client:only="react" />}
|
||||||
{child == "qs2.MediaRequestForm" && <MediaRequestForm client:only="react" />}
|
{child == "qs2.MediaRequestForm" && <MediaRequestForm client:only="react" />}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { API_URL } from '../config';
|
|||||||
|
|
||||||
export default function LyricSearch() {
|
export default function LyricSearch() {
|
||||||
const [showLyrics, setShowLyrics] = useState(false);
|
const [showLyrics, setShowLyrics] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="lyric-search">
|
<div className="lyric-search">
|
||||||
<h2 className="title">
|
<h2 className="title">
|
||||||
@@ -52,6 +53,29 @@ export function LyricSearchInputField({ id, placeholder, setShowLyrics }) {
|
|||||||
const autoCompleteRef = useRef(null);
|
const autoCompleteRef = useRef(null);
|
||||||
const [theme, setTheme] = useState(document.documentElement.getAttribute("data-theme") || "light");
|
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(() => {
|
useEffect(() => {
|
||||||
const handler = (e) => {
|
const handler = (e) => {
|
||||||
const newTheme = e.detail;
|
const newTheme = e.detail;
|
||||||
@@ -118,17 +142,17 @@ export function LyricSearchInputField({ id, placeholder, setShowLyrics }) {
|
|||||||
}, 0);
|
}, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSearch = async () => {
|
const handleSearch = async (searchValue = value) => {
|
||||||
if (autoCompleteRef.current) {
|
if (autoCompleteRef.current) {
|
||||||
autoCompleteRef.current.hide();
|
autoCompleteRef.current.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!value.includes(" - ")) {
|
if (!searchValue.includes(" - ")) {
|
||||||
setAlertVisible(true);
|
setAlertVisible(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [artist, song] = value.split(" - ", 2).map((v) => v.trim());
|
const [artist, song] = searchValue.split(" - ", 2).map((v) => v.trim());
|
||||||
if (!artist || !song) {
|
if (!artist || !song) {
|
||||||
setAlertVisible(true);
|
setAlertVisible(true);
|
||||||
return;
|
return;
|
||||||
@@ -169,6 +193,10 @@ export function LyricSearchInputField({ id, placeholder, setShowLyrics }) {
|
|||||||
setLyricsResult({ artist: data.artist, song: data.song, lyrics: data.lyrics });
|
setLyricsResult({ artist: data.artist, song: data.song, lyrics: data.lyrics });
|
||||||
setShowLyrics(true);
|
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, {
|
toast.update(searchToastRef.current, {
|
||||||
type: "success",
|
type: "success",
|
||||||
render: `Found! (Took ${duration}s)`,
|
render: `Found! (Took ${duration}s)`,
|
||||||
|
|||||||
@@ -6,8 +6,11 @@ import LyricSearch from '../components/LyricSearch.jsx';
|
|||||||
|
|
||||||
<Base>
|
<Base>
|
||||||
<section>
|
<section>
|
||||||
<div class="prose prose-neutral dark:prose-invert">
|
<div class="prose prose-neutral dark:prose-invert">
|
||||||
<Root child="LyricSearch" client:only="react" />
|
<Root
|
||||||
|
child="LyricSearch"
|
||||||
|
client:only="react"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</Base>
|
</Base>
|
||||||
|
|||||||
Reference in New Issue
Block a user