From 9bcf2900f88e94037cce065910d363291cb03acf Mon Sep 17 00:00:00 2001 From: SrGooglo Date: Tue, 30 May 2023 01:11:00 +0000 Subject: [PATCH] implement search feature --- .../src/pages/music/components/feed/index.jsx | 278 +++++++++++------- .../pages/music/components/feed/index.less | 42 ++- 2 files changed, 214 insertions(+), 106 deletions(-) diff --git a/packages/app/src/pages/music/components/feed/index.jsx b/packages/app/src/pages/music/components/feed/index.jsx index 59b018b0..fcf36313 100755 --- a/packages/app/src/pages/music/components/feed/index.jsx +++ b/packages/app/src/pages/music/components/feed/index.jsx @@ -1,11 +1,18 @@ import React from "react" import * as antd from "antd" import classnames from "classnames" -import { ImageViewer, UserPreview } from "components" -import { Icons } from "components/Icons" import { Translation } from "react-i18next" +import Searcher from "components/Searcher" +import { ImageViewer, UserPreview } from "components" +import { Icons, createIconRender } from "components/Icons" + +import { WithPlayerContext } from "contexts/WithPlayerContext" + import FeedModel from "models/feed" +import PlaylistModel from "models/playlists" + +import MusicTrack from "components/MusicTrack" import "./index.less" @@ -25,7 +32,23 @@ const PlaylistsList = (props) => { return } - setOffset((value) => value - hopNumber) + setOffset((value) => { + const newOffset = value - hopNumber + + // check if newOffset is NaN + if (newOffset !== newOffset) { + return false + } + + if (typeof makeRequest === "function") { + makeRequest({ + trim: newOffset, + limit: hopNumber, + }) + } + + return newOffset + }) } const onClickNext = () => { @@ -33,14 +56,24 @@ const PlaylistsList = (props) => { return } - setOffset((value) => value + hopNumber) - } + setOffset((value) => { + const newOffset = value + hopNumber - React.useEffect(() => { - if (typeof makeRequest === "function") { - makeRequest() - } - }, [offset]) + // check if newOffset is NaN + if (newOffset !== newOffset) { + return false + } + + if (typeof makeRequest === "function") { + makeRequest({ + trim: newOffset, + limit: hopNumber, + }) + } + + return newOffset + }) + } React.useEffect(() => { if (result) { @@ -135,6 +168,10 @@ const PlaylistItem = (props) => { onMouseLeave={() => setCoverHover(false)} onClick={onClickPlay} > +
+ +
+ @@ -144,7 +181,10 @@ const PlaylistItem = (props) => {

{playlist.title}

- + + { + playlist.publisher && + } } @@ -191,113 +231,141 @@ const MayLike = (props) => { } -const SearchResultItem = (props) => { - return
-

SearchResultItem

+const ResultGroupsDecorators = { + "playlists": { + icon: "MdPlaylistPlay", + label: "Playlists", + renderItem: (props) => { + return + } + }, + "tracks": { + icon: "MdMusicNote", + label: "Tracks", + renderItem: (props) => { + return app.cores.player.start(props.item)} + /> + } + } +} + +const SearchResults = ({ + data +}) => { + if (typeof data !== "object") { + return null + } + + let groupsKeys = Object.keys(data) + + // filter out empty groups + groupsKeys = groupsKeys.filter((key) => { + return data[key].length > 0 + }) + + if (groupsKeys.length === 0) { + return
+ +
+ } + + return
+ + { + groupsKeys.map((key, index) => { + const decorator = ResultGroupsDecorators[key] ?? { + icon: null, + label: key, + renderItem: () => null + } + + return
+
+

+ { + createIconRender(decorator.icon) + } + + {(t) => t(decorator.label)} + +

+
+ +
+ { + data[key].map((item, index) => { + return decorator.renderItem({ + key: index, + item + }) + }) + } +
+
+ }) + } +
} export default (props) => { - const [searchLoading, setSearchLoading] = React.useState(false) - const [searchFocused, setSearchFocused] = React.useState(false) - const [searchValue, setSearchValue] = React.useState("") - const [searchResult, setSearchResult] = React.useState([]) - - const handleSearchValueChange = (e) => { - // not allow to input space as first character - if (e.target.value[0] === " ") { - return - } - - setSearchValue(e.target.value) - } - - const makeSearch = async (value) => { - setSearchResult([]) - - await new Promise((resolve) => setTimeout(resolve, 1000)) - - setSearchResult([ - { - title: "test", - thumbnail: "/assets/no_song.png", - }, - { - title: "test2", - thumbnail: "/assets/no_song.png", - } - ]) - } - - React.useEffect(() => { - const timer = setTimeout(async () => { - setSearchLoading(true) - - await makeSearch(searchValue) - - setSearchLoading(false) - }, 400) - - if (searchValue === "") { - if (typeof props.onEmpty === "function") { - //props.onEmpty() - } - } else { - if (typeof props.onFilled === "function") { - //props.onFilled() - } - } - - return () => clearTimeout(timer) - }, [searchValue]) + const [searchResults, setSearchResults] = React.useState(false) return
-
- } - onFocus={() => setSearchFocused(true)} - onBlur={() => setSearchFocused(false)} - onChange={handleSearchValueChange} - value={searchValue} - /> + setSearchResults(false)} + /> -
- { - searchLoading && - } - { - searchFocused && searchValue !== "" && searchResult.length > 0 && searchResult.map((result, index) => { - return - }) - } + { + searchResults && + } + + { + !searchResults &&
+ + + } + fetchMethod={FeedModel.getPlaylistsFeed} + /> + + } + fetchMethod={FeedModel.getGlobalMusicFeed} + />
-
- -
- - - } - fetchMethod={FeedModel.getPlaylistsFeed} - /> - - } - fetchMethod={FeedModel.getGlobalMusicFeed} - /> -
+ }
} \ No newline at end of file diff --git a/packages/app/src/pages/music/components/feed/index.less b/packages/app/src/pages/music/components/feed/index.less index 5d35a08c..b3843d1e 100755 --- a/packages/app/src/pages/music/components/feed/index.less +++ b/packages/app/src/pages/music/components/feed/index.less @@ -97,7 +97,7 @@ min-width: 400px; max-width: 800px; - //overflow: hidden; + overflow: visible; box-sizing: border-box !important; @@ -111,6 +111,10 @@ &.cover-hovering { .playlistItem_cover { transform: scale(1.1); + + .playlistItem_cover_mask { + opacity: 1; + } } .playlistItem_info { @@ -135,6 +139,8 @@ } .playlistItem_cover { + position: relative; + height: 10vh; transition: all 0.2s ease-in-out; @@ -145,6 +151,36 @@ object-fit: cover; border-radius: 8px; + + background-color: black; + + z-index: 50 + } + + .playlistItem_cover_mask { + position: absolute; + + top: 0; + left: 0; + + display: flex; + + align-items: center; + justify-content: center; + + width: 100%; + height: 100%; + + opacity: 0; + + transition: all 0.2s ease-in-out; + + z-index: 55; + + background-color: rgba(var(--layoutBackgroundColor), 0.6); + color: var(--text-color); + + font-size: 3rem; } } @@ -169,6 +205,10 @@ overflow: hidden; + &:hover { + text-decoration: underline; + } + h1, h4 { overflow: hidden;