feat: musicland
This commit is contained in:
+376
-148
@@ -1,20 +1,30 @@
|
|||||||
import React, { useCallback, useMemo, useState } from "react";
|
import React, {
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
import {
|
import {
|
||||||
FlatList,
|
FlatList,
|
||||||
Image,
|
Image,
|
||||||
Platform,
|
Platform,
|
||||||
Pressable,
|
Pressable,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
|
StyleSheet,
|
||||||
Text,
|
Text,
|
||||||
View,
|
View,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
|
import { BlurView } from "expo-blur";
|
||||||
import { responsiveHeight } from "react-native-responsive-dimensions";
|
import { responsiveHeight } from "react-native-responsive-dimensions";
|
||||||
import { background, icons } from "../../assets";
|
import { background, icons } from "../../assets";
|
||||||
import BorderGradientButton from "../../components/BorderGradientButton";
|
import BorderGradientButton from "../../components/BorderGradientButton";
|
||||||
|
import SearchBar from "../../components/SearchBar";
|
||||||
import ShareBtn from "../../components/ShareBtn/ShareBtn";
|
import ShareBtn from "../../components/ShareBtn/ShareBtn";
|
||||||
import { projectsRef } from "../../config/firebase";
|
import { projectsRef } from "../../config/firebase";
|
||||||
import useDataFromRef from "../../hooks/useDataFromRef";
|
import useDataFromRef from "../../hooks/useDataFromRef";
|
||||||
import useNavigateToMusicDetails from "../../hooks/useNavigateToMusicDetails";
|
import useNavigateToMusicDetails from "../../hooks/useNavigateToMusicDetails";
|
||||||
|
import useSearch from "../../hooks/useSearch";
|
||||||
import Page from "../../layouts/Page";
|
import Page from "../../layouts/Page";
|
||||||
import { Routes } from "../../navigation";
|
import { Routes } from "../../navigation";
|
||||||
import { navigate } from "../../navigation/NavigationService";
|
import { navigate } from "../../navigation/NavigationService";
|
||||||
@@ -22,31 +32,33 @@ import { Palette, Style } from "../../styles";
|
|||||||
import { FONT_FAMILY } from "../../styles/Fonts";
|
import { FONT_FAMILY } from "../../styles/Fonts";
|
||||||
import CreateLyricsHeader from "../Writing/components/CreateLyricsHeader";
|
import CreateLyricsHeader from "../Writing/components/CreateLyricsHeader";
|
||||||
import MobileCoinBadge from "../../components/MobileCoinBadge";
|
import MobileCoinBadge from "../../components/MobileCoinBadge";
|
||||||
|
import ResearchHeader from "../Library/components/ResearchHeader";
|
||||||
|
import SearchResultsList from "../Library/components/SearchResultsList";
|
||||||
import PlaybacksCard from "./components/PlaybacksCard";
|
import PlaybacksCard from "./components/PlaybacksCard";
|
||||||
import SongCard from "./components/SongCard";
|
import SongCard from "./components/SongCard";
|
||||||
|
import BorderGradient from "../../components/BorderGradient/BorderGradient.web";
|
||||||
const HitParade = () => {
|
const HitParade = () => {
|
||||||
const [selected, setSelected] = useState("Chansons");
|
const [selectedCategory, setSelectedCategory] = useState("Chansons");
|
||||||
const navigateToMusicDetails = useNavigateToMusicDetails();
|
const navigateToMusicDetails = useNavigateToMusicDetails();
|
||||||
const { data: topSongs } = useDataFromRef({
|
const { data: topSongs } = useDataFromRef({
|
||||||
ref: projectsRef.where("views", ">", 0).orderBy("views", "desc").limit(10),
|
ref: projectsRef.where("views", ">", 0).orderBy("views", "desc").limit(20),
|
||||||
simpleRef: false,
|
simpleRef: false,
|
||||||
listener: true,
|
listener: true,
|
||||||
condition: true,
|
condition: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: topPlaybacks } = useDataFromRef({
|
const { data: topPlaybacks } = useDataFromRef({
|
||||||
ref: projectsRef.where("views", ">", 0).orderBy("views", "desc").limit(50),
|
ref: projectsRef.where("views", ">", 0).orderBy("views", "desc").limit(60),
|
||||||
format: (docs) => docs.filter((d) => d?.playbackUrl != null).slice(0, 10),
|
format: (docs) => docs.filter((d) => d?.playbackUrl != null).slice(0, 20),
|
||||||
simpleRef: false,
|
simpleRef: false,
|
||||||
listener: true,
|
listener: true,
|
||||||
condition: true,
|
condition: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Découpe en 2 colonnes (pour le web uniquement)
|
const songsList = useMemo(
|
||||||
const [songsCol1, songsCol2] = useMemo(() => {
|
() => (Array.isArray(topSongs) ? topSongs : []),
|
||||||
const arr = Array.isArray(topSongs) ? topSongs : [];
|
[topSongs]
|
||||||
return [arr.slice(0, 5), arr.slice(5)];
|
);
|
||||||
}, [topSongs]);
|
|
||||||
|
|
||||||
const [playbacksCol1, playbacksCol2] = useMemo(() => {
|
const [playbacksCol1, playbacksCol2] = useMemo(() => {
|
||||||
const arr = Array.isArray(topPlaybacks) ? topPlaybacks : [];
|
const arr = Array.isArray(topPlaybacks) ? topPlaybacks : [];
|
||||||
@@ -60,7 +72,7 @@ const HitParade = () => {
|
|||||||
project?.coverUrl,
|
project?.coverUrl,
|
||||||
];
|
];
|
||||||
const uri = candidates.find(
|
const uri = candidates.find(
|
||||||
(value) => typeof value === "string" && value.trim().length > 0,
|
(value) => typeof value === "string" && value.trim().length > 0
|
||||||
);
|
);
|
||||||
return uri || null;
|
return uri || null;
|
||||||
}, []);
|
}, []);
|
||||||
@@ -112,103 +124,147 @@ const HitParade = () => {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderSongsWeb = () => (
|
const renderSongList = () => (
|
||||||
<ScrollView
|
<View style={{ gap: 10 }}>
|
||||||
contentContainerStyle={{
|
{songsList.map((item, idx) => (
|
||||||
gap: 10,
|
<SongCard
|
||||||
paddingBottom: responsiveHeight(20),
|
key={item.id}
|
||||||
}}
|
rank={idx + 1}
|
||||||
>
|
title={item?.title || "Sans titre"}
|
||||||
<View style={{ flexDirection: "row", gap: 10, alignItems: "flex-start" }}>
|
artist={item?.userName}
|
||||||
{/* Colonne gauche (1..5) */}
|
coverUrl={item?.coverUrl || null}
|
||||||
<View style={{ flex: 1, gap: 10 }}>
|
onPress={() =>
|
||||||
{songsCol1.map((item, idx) => (
|
navigateToMusicDetails({
|
||||||
<SongCard
|
projectId: item.id,
|
||||||
key={item.id}
|
songUrl: item?.songUrl,
|
||||||
rank={idx + 1}
|
project: item,
|
||||||
title={item?.title || "Sans titre"}
|
})
|
||||||
artist={"MusicLand"}
|
}
|
||||||
coverUrl={item?.coverUrl || null}
|
/>
|
||||||
onPress={() =>
|
))}
|
||||||
navigateToMusicDetails({
|
</View>
|
||||||
projectId: item.id,
|
|
||||||
songUrl: item?.songUrl,
|
|
||||||
project: item,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
{/* Colonne droite (6..N) */}
|
|
||||||
|
|
||||||
{songsCol2.length > 0 && (
|
|
||||||
<View style={{ flex: 1, gap: 10 }}>
|
|
||||||
{songsCol2.map((item, idx) => (
|
|
||||||
<SongCard
|
|
||||||
key={item.id}
|
|
||||||
rank={5 + idx + 1}
|
|
||||||
title={item?.title || "Sans titre"}
|
|
||||||
artist={"MusicLand"}
|
|
||||||
coverUrl={item?.coverUrl || null}
|
|
||||||
onPress={() =>
|
|
||||||
navigateToMusicDetails({
|
|
||||||
projectId: item.id,
|
|
||||||
songUrl: item?.songUrl,
|
|
||||||
project: item,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderPlaybacksWeb = () => (
|
const renderPlaybackColumns = () => (
|
||||||
<ScrollView
|
<View style={{ flexDirection: "row", gap: 10, alignItems: "flex-start" }}>
|
||||||
contentContainerStyle={{
|
<View style={{ flex: 1, gap: 10 }}>
|
||||||
gap: 10,
|
{playbacksCol1.map((item, idx) => (
|
||||||
paddingBottom: responsiveHeight(20),
|
<PlaybacksCard
|
||||||
}}
|
key={item.id}
|
||||||
>
|
rank={idx + 1}
|
||||||
<View style={{ flexDirection: "row", gap: 10, alignItems: "flex-start" }}>
|
title={item?.title || "Sans titre"}
|
||||||
{/* Colonne gauche (1..5) */}
|
artist={item?.userName}
|
||||||
|
thumbnailUrl={resolvePlaybackThumbnail(item)}
|
||||||
|
onPress={() => navigate(Routes.Playbacks, { projectId: item.id })}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{playbacksCol2.length > 0 && (
|
||||||
<View style={{ flex: 1, gap: 10 }}>
|
<View style={{ flex: 1, gap: 10 }}>
|
||||||
{playbacksCol1.map((item, idx) => (
|
{playbacksCol2.map((item, idx) => (
|
||||||
<PlaybacksCard
|
<PlaybacksCard
|
||||||
key={item.id}
|
key={item.id}
|
||||||
rank={idx + 1}
|
rank={5 + idx + 1}
|
||||||
title={item?.title || "Sans titre"}
|
title={item?.title || "Sans titre"}
|
||||||
artist={"MusicLand"}
|
artist={item?.userName}
|
||||||
thumbnailUrl={resolvePlaybackThumbnail(item)}
|
thumbnailUrl={resolvePlaybackThumbnail(item)}
|
||||||
onPress={() => navigate(Routes.Playbacks, { projectId: item.id })}
|
onPress={() => navigate(Routes.Playbacks, { projectId: item.id })}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
|
)}
|
||||||
{/* Colonne droite (6..N) */}
|
</View>
|
||||||
{playbacksCol2.length > 0 && (
|
|
||||||
<View style={{ flex: 1, gap: 10 }}>
|
|
||||||
{playbacksCol2.map((item, idx) => (
|
|
||||||
<PlaybacksCard
|
|
||||||
key={item.id}
|
|
||||||
rank={5 + idx + 1}
|
|
||||||
title={item?.title || "Sans titre"}
|
|
||||||
artist={"MusicLand"}
|
|
||||||
thumbnailUrl={resolvePlaybackThumbnail(item)}
|
|
||||||
onPress={() =>
|
|
||||||
navigate(Routes.Playbacks, { projectId: item.id })
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const isWeb = Platform.OS === "web";
|
const isWeb = Platform.OS === "web";
|
||||||
|
const {
|
||||||
|
search,
|
||||||
|
setSearch,
|
||||||
|
selected: searchSelected,
|
||||||
|
setSelected: setSearchSelected,
|
||||||
|
users = [],
|
||||||
|
musics = [],
|
||||||
|
playbacks = [],
|
||||||
|
loading: searchLoading,
|
||||||
|
} = useSearch();
|
||||||
|
|
||||||
|
const [dropdownVisible, setDropdownVisible] = useState(false);
|
||||||
|
const searchWrapperRef = useRef(null);
|
||||||
|
const hasSearchQuery = search.trim().length > 0;
|
||||||
|
|
||||||
|
const toggleSearchSelected = useCallback(
|
||||||
|
(value) => {
|
||||||
|
setSearchSelected((previous) => (previous === value ? null : value));
|
||||||
|
},
|
||||||
|
[setSearchSelected]
|
||||||
|
);
|
||||||
|
|
||||||
|
const musicResults = useMemo(
|
||||||
|
() => (Array.isArray(musics) ? musics : []),
|
||||||
|
[musics]
|
||||||
|
);
|
||||||
|
|
||||||
|
const playbackResults = useMemo(
|
||||||
|
() => (Array.isArray(playbacks) ? playbacks : []),
|
||||||
|
[playbacks]
|
||||||
|
);
|
||||||
|
|
||||||
|
const userResults = useMemo(
|
||||||
|
() => (Array.isArray(users) ? users : []),
|
||||||
|
[users]
|
||||||
|
);
|
||||||
|
|
||||||
|
const musicsLoading = searchLoading;
|
||||||
|
const playbacksLoading = searchLoading;
|
||||||
|
const usersLoading = searchLoading;
|
||||||
|
|
||||||
|
const closeDropdown = useCallback(() => {
|
||||||
|
setDropdownVisible(false);
|
||||||
|
setSearchSelected(null);
|
||||||
|
setSearch("");
|
||||||
|
}, [setSearch, setSearchSelected]);
|
||||||
|
|
||||||
|
const handleSearchFocus = useCallback(() => {
|
||||||
|
if (isWeb) {
|
||||||
|
setDropdownVisible(true);
|
||||||
|
}
|
||||||
|
}, [isWeb]);
|
||||||
|
|
||||||
|
const handleSearchChange = useCallback(
|
||||||
|
(value) => {
|
||||||
|
setSearch(value);
|
||||||
|
if (isWeb) {
|
||||||
|
setDropdownVisible(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[isWeb, setSearch]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isWeb || !dropdownVisible) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClickOutside = (event) => {
|
||||||
|
if (searchWrapperRef.current?.contains?.(event.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
closeDropdown();
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener("mousedown", handleClickOutside);
|
||||||
|
document.addEventListener("touchstart", handleClickOutside);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener("mousedown", handleClickOutside);
|
||||||
|
document.removeEventListener("touchstart", handleClickOutside);
|
||||||
|
};
|
||||||
|
}, [closeDropdown, dropdownVisible, isWeb]);
|
||||||
|
|
||||||
|
const shouldShowResults = isWeb && dropdownVisible;
|
||||||
|
const shouldBlurContent = shouldShowResults && hasSearchQuery;
|
||||||
|
|
||||||
const handlePlayRandomSong = useCallback(() => {
|
const handlePlayRandomSong = useCallback(() => {
|
||||||
const arr = Array.isArray(topSongs) ? topSongs : [];
|
const arr = Array.isArray(topSongs) ? topSongs : [];
|
||||||
|
|
||||||
@@ -226,12 +282,162 @@ const HitParade = () => {
|
|||||||
});
|
});
|
||||||
}, [navigateToMusicDetails, topSongs]);
|
}, [navigateToMusicDetails, topSongs]);
|
||||||
|
|
||||||
|
const categoryLabel =
|
||||||
|
selectedCategory === "Playback" ? "playbacks" : "chansons";
|
||||||
|
|
||||||
|
const heroTitle = isWeb
|
||||||
|
? "Coups de coeur des utilisateurs"
|
||||||
|
: `Coups de coeur des utilisateurs catégorie ${selectedCategory}`;
|
||||||
|
|
||||||
|
const heroSubtitle = isWeb
|
||||||
|
? "Les 3 chansons et playbacks les plus likées du mois reçoivent des tokens."
|
||||||
|
: `Les 3 ${categoryLabel} les plus likées du mois reçoivent des tokens.`;
|
||||||
|
|
||||||
|
const renderHero = () => (
|
||||||
|
<View
|
||||||
|
style={{ gap: 11, maxWidth: 800, width: "100%", alignSelf: "center" }}
|
||||||
|
>
|
||||||
|
{/* <Pressable onPress={handlePlayRandomSong}>
|
||||||
|
<Image
|
||||||
|
source={icons.play}
|
||||||
|
style={{ alignSelf: "center", marginVertical: 10 }}
|
||||||
|
/>
|
||||||
|
</Pressable> */}
|
||||||
|
<CreateLyricsHeader gradientProps={{ colors: ["#F94697", "#7023F7"] }}>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
fontSize: 16,
|
||||||
|
color: Palette.white,
|
||||||
|
fontFamily: FONT_FAMILY.HelveticaNeueBold,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{heroTitle}
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
fontSize: 12,
|
||||||
|
color: Palette.white,
|
||||||
|
fontFamily: FONT_FAMILY.InterRegular,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{heroSubtitle}
|
||||||
|
</Text>
|
||||||
|
</CreateLyricsHeader>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderWebContent = () => (
|
||||||
|
<ScrollView
|
||||||
|
contentContainerStyle={{
|
||||||
|
flexGrow: 1,
|
||||||
|
gap: 24,
|
||||||
|
paddingBottom: responsiveHeight(20),
|
||||||
|
}}
|
||||||
|
showsVerticalScrollIndicator={false}
|
||||||
|
style={{ flex: 1, position: "relative", zIndex: 5 }}
|
||||||
|
>
|
||||||
|
{renderHero()}
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flexDirection: "row",
|
||||||
|
gap: 16,
|
||||||
|
alignItems: "flex-start",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<View style={{ flex: 1, gap: 12 }}>
|
||||||
|
<BlurView
|
||||||
|
intensity={50}
|
||||||
|
tint="dark"
|
||||||
|
style={{
|
||||||
|
alignSelf: "flex-start",
|
||||||
|
borderRadius: 10,
|
||||||
|
overflow: "hidden",
|
||||||
|
paddingHorizontal: 20,
|
||||||
|
paddingVertical: 10,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* <BorderGradient> */}
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
fontSize: 20,
|
||||||
|
color: Palette.white,
|
||||||
|
fontFamily: FONT_FAMILY.HelveticaNeueBold,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Chansons
|
||||||
|
</Text>
|
||||||
|
{/* </BorderGradient> */}
|
||||||
|
</BlurView>
|
||||||
|
{renderSongList()}
|
||||||
|
</View>
|
||||||
|
<View style={{ flex: 1, gap: 12 }}>
|
||||||
|
<BlurView
|
||||||
|
intensity={50}
|
||||||
|
tint="dark"
|
||||||
|
style={{
|
||||||
|
alignSelf: "flex-start",
|
||||||
|
borderRadius: 10,
|
||||||
|
overflow: "hidden",
|
||||||
|
paddingHorizontal: 20,
|
||||||
|
paddingVertical: 10,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* <BorderGradient> */}
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
fontSize: 20,
|
||||||
|
color: Palette.white,
|
||||||
|
fontFamily: FONT_FAMILY.HelveticaNeueBold,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Playbacks
|
||||||
|
</Text>
|
||||||
|
{/* </BorderGradient> */}
|
||||||
|
</BlurView>
|
||||||
|
{renderPlaybackColumns()}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderMobileContent = () => (
|
||||||
|
<View style={{ flex: 1, gap: 24 }}>
|
||||||
|
{renderHero()}
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
...Style.containerRow,
|
||||||
|
justifyContent: "space-between",
|
||||||
|
width: "auto",
|
||||||
|
gap: 12,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{["Chansons", "Playback"].map((item, index) => (
|
||||||
|
<BorderGradientButton
|
||||||
|
key={index}
|
||||||
|
title={item}
|
||||||
|
onPress={() => setSelectedCategory(item)}
|
||||||
|
tint={selectedCategory === item ? "light" : "dark"}
|
||||||
|
containerStyle={{ flex: 1 }}
|
||||||
|
titleStyle={{
|
||||||
|
fontSize: 16,
|
||||||
|
fontFamily: FONT_FAMILY.HelveticaNeueBold,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{selectedCategory === "Chansons" && renderSongsMobile()}
|
||||||
|
{selectedCategory === "Playback" && renderPlaybacksMobile()}
|
||||||
|
{/* "Clips" pourra reprendre la même logique si tu le réactives */}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page
|
<Page
|
||||||
backgroundImg={isWeb ? background.hitParadeBG2 : background.hitParadeBG}
|
backgroundImg={isWeb ? background.hitParadeBG2 : background.hitParadeBG}
|
||||||
headerType="NONE"
|
headerType="NONE"
|
||||||
width="100%"
|
width="100%"
|
||||||
maxWidth={800}
|
maxWidth={1200}
|
||||||
blurIntensity={isWeb ? 0 : 0}
|
blurIntensity={isWeb ? 0 : 0}
|
||||||
showCoin={false}
|
showCoin={false}
|
||||||
>
|
>
|
||||||
@@ -255,67 +461,89 @@ const HitParade = () => {
|
|||||||
source={icons.musicLandLogo}
|
source={icons.musicLandLogo}
|
||||||
style={{ alignSelf: "center", height: 150, resizeMode: "contain" }}
|
style={{ alignSelf: "center", height: 150, resizeMode: "contain" }}
|
||||||
/>
|
/>
|
||||||
<View style={{ flex: 1, gap: 24 }}>
|
|
||||||
<View style={{ gap: 11 }}>
|
|
||||||
<Pressable onPress={handlePlayRandomSong}>
|
|
||||||
<Image
|
|
||||||
source={icons.play}
|
|
||||||
style={{ alignSelf: "center", marginVertical: 10 }}
|
|
||||||
/>
|
|
||||||
</Pressable>
|
|
||||||
<CreateLyricsHeader
|
|
||||||
gradientProps={{ colors: ["#F94697", "#7023F7"] }}
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
fontSize: 16,
|
|
||||||
color: Palette.white,
|
|
||||||
fontFamily: FONT_FAMILY.HelveticaNeueBold,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Coups de coeur des utilisateurs catégorie {selected}
|
|
||||||
</Text>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
fontSize: 12,
|
|
||||||
color: Palette.white,
|
|
||||||
fontFamily: FONT_FAMILY.InterRegular,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Les 3 {selected} les plus likées du mois reçoivent des{"\n"}
|
|
||||||
tokens.
|
|
||||||
</Text>
|
|
||||||
</CreateLyricsHeader>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
|
{isWeb && (
|
||||||
<View
|
<View
|
||||||
|
ref={searchWrapperRef}
|
||||||
style={{
|
style={{
|
||||||
...Style.containerRow,
|
position: "relative",
|
||||||
justifyContent: "space-between",
|
alignSelf: "center",
|
||||||
width: "auto",
|
width: "65%",
|
||||||
gap: 12,
|
maxWidth: 520,
|
||||||
|
minWidth: 360,
|
||||||
|
zIndex: dropdownVisible ? 40 : 1,
|
||||||
|
overflow: "visible",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{["Chansons", "Playback"].map((item, index) => (
|
<SearchBar
|
||||||
<BorderGradientButton
|
textInputProps={{
|
||||||
key={index}
|
value: search,
|
||||||
title={item}
|
onChangeText: handleSearchChange,
|
||||||
onPress={() => setSelected(item)}
|
autoFocus: false,
|
||||||
tint={selected === item ? "light" : "dark"}
|
onFocus: handleSearchFocus,
|
||||||
containerStyle={{ flex: 1 }}
|
}}
|
||||||
titleStyle={{
|
/>
|
||||||
fontSize: 16,
|
{shouldShowResults && (
|
||||||
fontFamily: FONT_FAMILY.HelveticaNeueBold,
|
<View
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: 60,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
zIndex: 50,
|
||||||
|
width: "100%",
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
))}
|
<View
|
||||||
|
style={{
|
||||||
|
gap: 14,
|
||||||
|
borderRadius: 18,
|
||||||
|
padding: 16,
|
||||||
|
backgroundColor: Palette.ultraLightWhite,
|
||||||
|
...Style.defaultBorder,
|
||||||
|
width: "100%",
|
||||||
|
zIndex: 50,
|
||||||
|
elevation: 12,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ResearchHeader
|
||||||
|
onPress={toggleSearchSelected}
|
||||||
|
selected={searchSelected}
|
||||||
|
showSearchBar={false}
|
||||||
|
/>
|
||||||
|
<SearchResultsList
|
||||||
|
selected={searchSelected}
|
||||||
|
musics={musicResults}
|
||||||
|
musicsLoading={musicsLoading}
|
||||||
|
playbacks={playbackResults}
|
||||||
|
playbacksLoading={playbacksLoading}
|
||||||
|
users={userResults}
|
||||||
|
usersLoading={usersLoading}
|
||||||
|
onResultSelected={closeDropdown}
|
||||||
|
style={{ flex: 0, maxHeight: 420 }}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
{selected === "Chansons" &&
|
<View style={{ flex: 1, position: "relative" }}>
|
||||||
(isWeb ? renderSongsWeb() : renderSongsMobile())}
|
{shouldBlurContent && (
|
||||||
{selected === "Playback" &&
|
<BlurView
|
||||||
(isWeb ? renderPlaybacksWeb() : renderPlaybacksMobile())}
|
intensity={35}
|
||||||
{/* "Clips" pourra reprendre la même logique si tu le réactives */}
|
tint="dark"
|
||||||
|
style={[
|
||||||
|
StyleSheet.absoluteFillObject,
|
||||||
|
{
|
||||||
|
zIndex: 10,
|
||||||
|
backgroundColor: "rgba(0, 0, 0, 0.25)",
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isWeb ? renderWebContent() : renderMobileContent()}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</Page>
|
</Page>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const PlaybacksCard = ({
|
|||||||
return (
|
return (
|
||||||
<Pressable onPress={onPress}>
|
<Pressable onPress={onPress}>
|
||||||
<BlurView
|
<BlurView
|
||||||
intensity={Platform.OS !== "ios" ? 10 : 20}
|
intensity={Platform.OS === "web" ? 40 : Platform.OS !== "ios" ? 10 : 20}
|
||||||
tint="dark"
|
tint="dark"
|
||||||
style={{
|
style={{
|
||||||
...Style.containerSpaceBetween,
|
...Style.containerSpaceBetween,
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ const SongCard = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<BlurView
|
<BlurView
|
||||||
intensity={Platform.OS !== "ios" ? 10 : 20}
|
intensity={Platform.OS === "web" ? 40 : Platform.OS !== "ios" ? 10 : 20}
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
|
|||||||
Reference in New Issue
Block a user