1 line
12 KiB
Plaintext
1 line
12 KiB
Plaintext
{"version":3,"sources":["components/Header.tsx","components/Search.tsx","components/Card.tsx","components/Results.tsx","components/App.tsx","index.tsx"],"names":["Header","props","Box","as","direction","align","justify","background","pad","left","right","vertical","style","zIndex","Search","inputValue","handleChange","suggestions","handleSelect","margin","TextInput","value","onChange","onSelect","placeholder","icon","FormSearch","color","dropHeight","Card","image","name","round","elevation","overflow","height","Image","src","fit","horizontal","top","Heading","level","bottom","Results","artists","selectedName","selectedImage","selectedAlbums","albums","Grid","rows","columns","gap","areas","gridArea","map","artist","key","id","Avatar","ResponsiveContext","Consumer","size","count","album","QUERY_ARTISTS","gql","App","useState","setInputValue","useLazyQuery","getArtists","data","setArtists","setSuggestions","selected","setSelected","delayedQuery","useCallback","debounce","variables","byName","useEffect","cancel","queryArtists","updatedSuggestions","slice","el","Grommet","theme","e","target","suggestion","updatedArtists","suggestedArtists","item","i","length","selectedArtist","splice","otherArtists","global","font","family","client","ApolloClient","uri","cache","InMemoryCache","ReactDOM","render","StrictMode","ApolloProvider","document","getElementById"],"mappings":"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","file":"static/js/main.d5729ca7.chunk.js","sourcesContent":["import React, { PropsWithChildren } from 'react';\nimport { Box } from 'grommet';\n\nexport const Header = (props: PropsWithChildren<{}>) => {\n\treturn (\n\t\t<Box\n\t\t\tas='header'\n\t\t\tdirection='row'\n\t\t\talign='center'\n\t\t\tjustify='center'\n\t\t\tbackground='brand'\n\t\t\tpad={{ left: 'medium', right: 'small', vertical: 'small' }}\n\t\t\tstyle={{ zIndex: 1 }}\n\t\t\t{...props}\n\t\t/>\n\t);\n};\n","import React from 'react';\nimport { Box, TextInput } from 'grommet';\nimport { FormSearch } from 'grommet-icons';\n\nexport const Search = ({\n\tinputValue,\n\thandleChange,\n\tsuggestions,\n\thandleSelect,\n}: {\n\tinputValue: string;\n\thandleChange: (e: React.ChangeEvent<HTMLInputElement>) => void;\n\tsuggestions: string[] | undefined;\n\thandleSelect: (x: { target: HTMLElement | null; suggestion: any }) => void;\n}) => (\n\t<Box\n\t\tas='section'\n\t\tdirection='row'\n\t\tjustify='center'\n\t\tmargin={{ vertical: 'large' }}\n\t>\n\t\t<TextInput\n\t\t\tvalue={inputValue}\n\t\t\tonChange={handleChange}\n\t\t\tonSelect={handleSelect}\n\t\t\tplaceholder='Type an artist name'\n\t\t\ticon={<FormSearch color='plain' />}\n\t\t\tdropHeight='large'\n\t\t\tsuggestions={suggestions}\n\t\t/>\n\t</Box>\n);\n","import React from 'react';\nimport { Box, Heading, Image } from 'grommet';\n\nexport const Card = ({ image, name }: { image: string; name: string }) => {\n\treturn (\n\t\t<Box round='xxsmall' elevation='small' overflow='hidden'>\n\t\t\t<Box height='300px'>\n\t\t\t\t<Image src={image} fit='cover' />\n\t\t\t</Box>\n\n\t\t\t<Box pad={{ horizontal: 'small' }}>\n\t\t\t\t<Box\n\t\t\t\t\tmargin={{ top: 'small' }}\n\t\t\t\t\tdirection='row'\n\t\t\t\t\talign='center'\n\t\t\t\t\tjustify='between'\n\t\t\t\t>\n\t\t\t\t\t<Box>\n\t\t\t\t\t\t<Heading level='4' margin={{bottom: \"small\", top : \"xsmall\"}}>\n\t\t\t\t\t\t\t{name}\n\t\t\t\t\t\t</Heading>\n\t\t\t\t\t</Box>\n\t\t\t\t</Box>\n\t\t\t</Box>\n\t\t</Box>\n\t);\n};\n","import React from 'react';\nimport { Box, Grid, Avatar, Image, ResponsiveContext, Heading } from 'grommet';\n\nimport { Card as Album } from './Card';\nimport { Artists } from '../interfaces';\nimport { size } from 'lodash';\n\nexport const Results = ({ artists }: { artists: Artists }) => {\n\tconst {\n\t\tname: selectedName,\n\t\timage: selectedImage,\n\t\talbums: selectedAlbums,\n\t} = artists[0];\n\n\treturn (\n\t\t<Grid\n\t\t\trows={['fit', 'fit']}\n\t\t\tcolumns={['1/4', '3/4']}\n\t\t\tgap='small'\n\t\t\tareas={[\n\t\t\t\t['artist', 'other'],\n\t\t\t\t['discography', 'discography'],\n\t\t\t]}\n\t\t>\n\t\t\t<Box gridArea='artist' height='300px' >\n\t\t\t\t<h1>{selectedName}</h1>\n\t\t\t\t<Image src={selectedImage} fit='cover' />\n\t\t\t</Box>\n\t\t\t<Box gridArea='other' background='light-2'>\n\t\t\t\t<h3>Other results</h3>\n\t\t\t\t{artists.map((artist) => (\n\t\t\t\t\t<Box gridArea='artist' key={artist.id}>\n\t\t\t\t\t\t<Avatar src={artist.image} />\n\t\t\t\t\t\t<h4>{artist.name}</h4>\n\t\t\t\t\t</Box>\n\t\t\t\t))}\n\t\t\t</Box>\n\t\t\t<ResponsiveContext.Consumer>\n\t\t\t\t{(size) => (\n\t\t\t\t\t<Grid\n\t\t\t\t\t\tgridArea='discography'\n\t\t\t\t\t\talign='start'\n\t\t\t\t\t\tcolumns={{ count: 'fill', size: '300px' }}\n\t\t\t\t\t\tgap='medium'\n\t\t\t\t\t>\n\t\t\t\t\t\t<Heading level='1'>\n\t\t\t\t\t\t\tDiscography\n\t\t\t\t\t\t</Heading>\n\t\t\t\t\t\t{selectedAlbums.map((album) => (\n\t\t\t\t\t\t\t<Album\n\t\t\t\t\t\t\t\tkey={album.id}\n\t\t\t\t\t\t\t\timage={album.image}\n\t\t\t\t\t\t\t\tname={album.name}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</Grid>\n\t\t\t\t)}\n\t\t\t</ResponsiveContext.Consumer>\n\t\t</Grid>\n\t);\n};\n","import React, { useState, useCallback, useEffect } from 'react';\nimport { Grommet } from 'grommet';\nimport { debounce } from 'lodash';\nimport { gql, useLazyQuery } from '@apollo/client';\n\nimport { Header } from './Header';\nimport { Search } from './Search';\nimport { Results } from './Results';\nimport { Artists, Artist } from '../interfaces';\n\nconst QUERY_ARTISTS = gql`\n\tquery Artist($byName: String!) {\n\t\tqueryArtists(byName: $byName) {\n\t\t\tname\n\t\t\timage\n\t\t\tid\n\t\t\talbums {\n\t\t\t\tname\n\t\t\t\timage\n\t\t\t\tid\n\t\t\t}\n\t\t}\n\t}\n`;\n\nexport default function App() {\n\tconst [inputValue, setInputValue] = useState('');\n\tconst [getArtists, { data }] = useLazyQuery(QUERY_ARTISTS);\n\tconst [artists, setArtists] = useState<Artists>([]);\n\tconst [suggestions, setSuggestions] = useState<string[] | undefined>();\n\tconst [selected, setSelected] = useState(false);\n\n\t// Debounce the database query\n\t// Based on: https://archive.is/wip/6JDqb\n\tconst handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\tsetInputValue(e.target.value);\n\t};\n\n\tconst updateQuery = () => {\n\t\tgetArtists({ variables: { byName: inputValue } });\n\t};\n\n\tconst delayedQuery = useCallback(debounce(updateQuery, 500), [inputValue]);\n\n\tuseEffect(() => {\n\t\tdelayedQuery();\n\t\t// Cancel previous debounce calls during useEffect cleanup.\n\t\treturn delayedQuery.cancel;\n\t}, [inputValue, delayedQuery]);\n\n\tconst handleSelect = (suggestion: any) => {\n\t\tconst selectedName: string = suggestion.suggestion;\n\t\tlet updatedArtists: Artists = [];\n\n\t\t// Use map to create a copy of the array\n\t\tlet suggestedArtists: Artists = data.queryArtists\n\t\t\t.slice(0, 5)\n\t\t\t.map((item: Artist) => item);\n\n\t\t// Find the selected artist and move it to index 0\n\t\tfor (let i = 0; i < suggestedArtists!.length; i++) {\n\t\t\tif (suggestedArtists![i].name === selectedName) {\n\t\t\t\tlet selectedArtist: Artists = suggestedArtists?.splice(i, 1);\n\t\t\t\tlet otherArtists: Artists = suggestedArtists;\n\t\t\t\tupdatedArtists = [...selectedArtist, ...otherArtists];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tsetArtists(updatedArtists);\n\t\tsetSelected(true);\n\t};\n\n\tuseEffect(() => {\n\t\t// TODO optimize re-rendering, probably by using onCompleted instead of this useEffect\n\t\t// See https://github.com/apollographql/apollo-client/issues/5268#issuecomment-596950174\n\t\tif (data && data.queryArtists !== []) {\n\t\t\t// Limit artists to 5\n\t\t\tconst updatedArtists = data.queryArtists.slice(0, 5);\n\t\t\tconst updatedSuggestions: string[] = updatedArtists.map(\n\t\t\t\t(el: Artist) => {\n\t\t\t\t\treturn el.name;\n\t\t\t\t},\n\t\t\t);\n\t\t\tsetSuggestions(updatedSuggestions);\n\t\t}\n\t}, [data]);\n\n\treturn (\n\t\t<Grommet theme={theme}>\n\t\t\t<Header>\n\t\t\t\t<h1>Spoti Search</h1>\n\t\t\t</Header>\n\t\t\t<Search\n\t\t\t\tinputValue={inputValue}\n\t\t\t\thandleChange={handleChange}\n\t\t\t\tsuggestions={suggestions}\n\t\t\t\thandleSelect={handleSelect}\n\t\t\t/>\n\t\t\t{selected && <Results artists={artists} />}\n\t\t</Grommet>\n\t);\n}\n\nconst theme = {\n\tglobal: {\n\t\tfont: {\n\t\t\tfamily: 'Roboto',\n\t\t\tsize: '18px',\n\t\t\theight: '20px',\n\t\t},\n\t},\n};\n","import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';\n\nimport App from './components/App';\n\nconst client = new ApolloClient({\n\turi: 'https://spotify-graphql-server.herokuapp.com/graphql',\n\tcache: new InMemoryCache(),\n});\n\nReactDOM.render(\n\t<React.StrictMode>\n\t\t<ApolloProvider client={client}>\n\t\t\t<App />\n\t\t</ApolloProvider>\n\t</React.StrictMode>,\n\tdocument.getElementById('root'),\n);\n"],"sourceRoot":""} |