diff --git a/components/CharacterSearchFilterBar/index.scss b/components/CharacterSearchFilterBar/index.scss new file mode 100644 index 00000000..e69de29b diff --git a/components/CharacterSearchFilterBar/index.tsx b/components/CharacterSearchFilterBar/index.tsx new file mode 100644 index 00000000..df451ec5 --- /dev/null +++ b/components/CharacterSearchFilterBar/index.tsx @@ -0,0 +1,205 @@ +import React, { useEffect, useState } from 'react' +import { useTranslation } from 'next-i18next' + +import cloneDeep from 'lodash.clonedeep' + +import * as DropdownMenu from '@radix-ui/react-dropdown-menu' + +import SearchFilter from '~components/SearchFilter' +import SearchFilterCheckboxItem from '~components/SearchFilterCheckboxItem' + +import './index.scss' +import { emptyElementState, emptyProficiencyState, emptyRarityState } from '~utils/emptyStates' +import { elements, proficiencies, rarities } from '~utils/stateValues' + +interface Props { + sendFilters: (filters: { [key: string]: number[] }) => void +} + +const CharacterSearchFilterBar = (props: Props) => { + const { t } = useTranslation('common') + + const [rarityMenu, setRarityMenu] = useState(false) + const [elementMenu, setElementMenu] = useState(false) + const [proficiency1Menu, setProficiency1Menu] = useState(false) + const [proficiency2Menu, setProficiency2Menu] = useState(false) + + const [rarityState, setRarityState] = useState(emptyRarityState) + const [elementState, setElementState] = useState(emptyElementState) + const [proficiency1State, setProficiency1State] = useState(emptyProficiencyState) + const [proficiency2State, setProficiency2State] = useState(emptyProficiencyState) + + function rarityMenuOpened(open: boolean) { + if (open) { + setRarityMenu(true) + setElementMenu(false) + setProficiency1Menu(false) + setProficiency2Menu(false) + } else setRarityMenu(false) + } + + function elementMenuOpened(open: boolean) { + if (open) { + setRarityMenu(false) + setElementMenu(true) + setProficiency1Menu(false) + setProficiency2Menu(false) + } else setElementMenu(false) + } + + function proficiency1MenuOpened(open: boolean) { + if (open) { + setRarityMenu(false) + setElementMenu(false) + setProficiency1Menu(true) + setProficiency2Menu(false) + } else setProficiency1Menu(false) + } + + function proficiency2MenuOpened(open: boolean) { + if (open) { + setRarityMenu(false) + setElementMenu(false) + setProficiency1Menu(false) + setProficiency2Menu(true) + } else setProficiency2Menu(false) + } + + function handleRarityChange(checked: boolean, key: string) { + let newRarityState = cloneDeep(rarityState) + newRarityState[key].checked = checked + setRarityState(newRarityState) + } + + function handleElementChange(checked: boolean, key: string) { + let newElementState = cloneDeep(elementState) + newElementState[key].checked = checked + setElementState(newElementState) + } + + function handleProficiency1Change(checked: boolean, key: string) { + let newProficiencyState = cloneDeep(proficiency1State) + newProficiencyState[key].checked = checked + setProficiency1State(newProficiencyState) + } + + function handleProficiency2Change(checked: boolean, key: string) { + let newProficiencyState = cloneDeep(proficiency2State) + newProficiencyState[key].checked = checked + setProficiency2State(newProficiencyState) + } + + function sendFilters() { + const checkedRarityFilters = Object.values(rarityState).filter(x => x.checked).map((x, i) => x.id) + const checkedElementFilters = Object.values(elementState).filter(x => x.checked).map((x, i) => x.id) + const checkedProficiency1Filters = Object.values(proficiency1State).filter(x => x.checked).map((x, i) => x.id) + const checkedProficiency2Filters = Object.values(proficiency2State).filter(x => x.checked).map((x, i) => x.id) + + const filters = { + rarity: checkedRarityFilters, + element: checkedElementFilters, + proficiency1: checkedProficiency1Filters, + proficiency2: checkedProficiency2Filters + } + + props.sendFilters(filters) + } + + useEffect(() => { + sendFilters() + }, [rarityState, elementState, proficiency1State, proficiency2State]) + + function renderProficiencyFilter(proficiency: 1 | 2) { + const onCheckedChange = (proficiency == 1) ? handleProficiency1Change : handleProficiency2Change + const numSelected = (proficiency == 1) + ? Object.values(proficiency1State).map(x => x.checked).filter(Boolean).length + : Object.values(proficiency2State).map(x => x.checked).filter(Boolean).length + const open = (proficiency == 1) ? proficiency1Menu : proficiency2Menu + const onOpenChange = (proficiency == 1) ? proficiency1MenuOpened : proficiency2MenuOpened + + return ( + + {`${t('filters.labels.proficiency')} ${proficiency}`} +
+ + { Array.from(Array(proficiencies.length / 2)).map((x, i) => { + const checked = (proficiency == 1) + ? proficiency1State[proficiencies[i]].checked + : proficiency2State[proficiencies[i]].checked + + return ( + + {t(`proficiencies.${proficiencies[i]}`)} + + )} + ) } + + + { Array.from(Array(proficiencies.length / 2)).map((x, i) => { + const checked = (proficiency == 1) + ? proficiency1State[proficiencies[i + (proficiencies.length / 2)]].checked + : proficiency2State[proficiencies[i + (proficiencies.length / 2)]].checked + + return ( + + {t(`proficiencies.${proficiencies[i + (proficiencies.length / 2)]}`)} + + )} + ) } + +
+
+ ) + } + + return ( +
+ x.checked).filter(Boolean).length} open={rarityMenu} onOpenChange={rarityMenuOpened}> + {t('filters.labels.rarity')} + { Array.from(Array(rarities.length)).map((x, i) => { + return ( + + {t(`rarities.${rarities[i]}`)} + + )} + ) } + + + x.checked).filter(Boolean).length} open={elementMenu} onOpenChange={elementMenuOpened}> + {t('filters.labels.element')} + { Array.from(Array(elements.length)).map((x, i) => { + return ( + + {t(`elements.${elements[i]}`)} + + )} + ) } + + + { renderProficiencyFilter(1) } + { renderProficiencyFilter(2) } +
+ ) +} + +export default CharacterSearchFilterBar diff --git a/components/SearchFilter/index.scss b/components/SearchFilter/index.scss new file mode 100644 index 00000000..0c1bf29e --- /dev/null +++ b/components/SearchFilter/index.scss @@ -0,0 +1,74 @@ +.DropdownLabel { + align-items: center; + background: $grey-90; + border: none; + border-radius: $unit * 2; + color: $grey-40; + display: flex; + gap: calc($unit / 2); + flex-direction: row; + padding: ($unit) ($unit * 2); + + &:hover { + background: $grey-80; + color: $grey-00; + cursor: pointer; + } + + .count { + color: $grey-60; + font-weight: $medium; + } + + & > .icon { + $diameter: 12px; + height: $diameter; + width: $diameter; + + svg { + transform: scale(0.85); + + path { + fill: $grey-60; + } + } + } +} + +.Dropdown { + background: white; + border-radius: $unit; + box-shadow: 0 0 2px rgba(0, 0, 0, 0.18); + display: flex; + flex-direction: column; + gap: calc($unit / 2); + padding: $unit; + min-width: 120px; + + & > span { + overflow: hidden; + + svg { + fill: white; + filter: drop-shadow(0px 0px 1px rgb(0 0 0 / 0.18)); + } + } + + section { + display: flex; + flex-direction: row; + gap: $unit; + } + + .Group { + flex: 1 1 0px; + flex-direction: column; + } + + .Label { + color: $grey-60; + font-size: $font-small; + margin-bottom: calc($unit / 2); + padding-left: calc($unit / 2); + } +} \ No newline at end of file diff --git a/components/SearchFilter/index.tsx b/components/SearchFilter/index.tsx new file mode 100644 index 00000000..8d6678fb --- /dev/null +++ b/components/SearchFilter/index.tsx @@ -0,0 +1,34 @@ +import React from 'react' + +import * as DropdownMenu from '@radix-ui/react-dropdown-menu' + +import ArrowIcon from '~public/icons/Arrow.svg' +import './index.scss' + +interface Props { + label: string + open: boolean + numSelected: number + onOpenChange: (open: boolean) => void + children: React.ReactNode +} + +const SearchFilter = (props: Props) => { + return ( + + + {props.label} + {props.numSelected} + + + + + + {props.children} + + + + ) +} + +export default SearchFilter diff --git a/components/SearchFilterCheckboxItem/index.scss b/components/SearchFilterCheckboxItem/index.scss new file mode 100644 index 00000000..7a951781 --- /dev/null +++ b/components/SearchFilterCheckboxItem/index.scss @@ -0,0 +1,41 @@ +.Item { + align-items: center; + border-radius: calc($unit / 2); + color: $grey-40; + font-size: $font-regular; + line-height: 1.2; + min-width: 100px; + position: relative; + padding: $unit; + padding-left: $unit * 3; + + &:hover { + background: $grey-90; + cursor: pointer; + } + + &[data-state="checked"] { + background: $grey-90; + + svg { + fill: $grey-50; + } + } + + .Indicator { + $diameter: 18px; + + display: flex; + align-items: center; + justify-content: center; + position: absolute; + left: calc($unit / 2); + height: $diameter; + width: $diameter; + + svg { + height: $diameter; + width: $diameter; + } + } +} \ No newline at end of file diff --git a/components/SearchFilterCheckboxItem/index.tsx b/components/SearchFilterCheckboxItem/index.tsx new file mode 100644 index 00000000..b6429fec --- /dev/null +++ b/components/SearchFilterCheckboxItem/index.tsx @@ -0,0 +1,34 @@ +import React from 'react' + +import * as DropdownMenu from '@radix-ui/react-dropdown-menu' + +import CheckIcon from '~public/icons/Check.svg' +import './index.scss' + +interface Props { + checked?: boolean + valueKey: string + onCheckedChange: (open: boolean, key: string) => void + children: React.ReactNode +} + +const SearchFilterCheckboxItem = (props: Props) => { + function handleCheckedChange(checked: boolean) { + props.onCheckedChange(checked, props.valueKey) + } + + return ( + event.preventDefault() }> + + + + {props.children} + + ) +} + +export default SearchFilterCheckboxItem diff --git a/components/SearchModal/index.scss b/components/SearchModal/index.scss index d9b5e5aa..35862d4f 100644 --- a/components/SearchModal/index.scss +++ b/components/SearchModal/index.scss @@ -3,38 +3,52 @@ flex-direction: column; min-height: 431px; width: 600px; + height: 480px; gap: 0; padding: 0; #Header { - border-top-left-radius: $unit; - border-top-right-radius: $unit; + border-bottom: 1px solid transparent; display: flex; - gap: $unit * 2.5; - margin: 0; - padding: ($unit * 3) ($unit * 3) ($unit) ($unit * 3); - position: sticky; - top: 0; + flex-direction: column; + gap: $unit; + padding-bottom: $unit * 2; - button { - background: transparent; - border: none; - height: 42px; - padding: 0; + &.scrolled { + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + box-shadow: 0 0 8px rgba(0, 0, 0, 0.12); } - label { - width: 100%; + #Bar { + border-top-left-radius: $unit; + border-top-right-radius: $unit; + display: flex; + gap: $unit * 2.5; + margin: 0; + padding: ($unit * 3) ($unit * 3) 0 ($unit * 3); + position: sticky; + top: 0; - .Input { - background: $grey-90; + button { + background: transparent; border: none; - border-radius: calc($unit / 2); - box-sizing: border-box; - font-size: $font-regular; - padding: $unit * 1.5; - text-align: left; + height: 42px; + padding: 0; + } + + label { width: 100%; + + .Input { + background: $grey-90; + border: none; + border-radius: calc($unit / 2); + box-sizing: border-box; + font-size: $font-regular; + padding: $unit * 1.5; + text-align: left; + width: 100%; + } } } } @@ -45,6 +59,23 @@ padding: 0 ($unit * 1.5); overflow-y: scroll; + h5.total { + font-size: $font-regular; + font-weight: $normal; + color: $grey-40; + padding: calc($unit / 2) ($unit * 1.5); + } + + .footer { + align-items: center; + display: flex; + color: $grey-60; + font-size: $font-regular; + font-weight: $normal; + height: $unit * 10; + justify-content: center; + } + .WeaponResult:last-child { margin-bottom: $unit * 1.5; } diff --git a/components/SearchModal/index.tsx b/components/SearchModal/index.tsx index ea011f7d..60d5089a 100644 --- a/components/SearchModal/index.tsx +++ b/components/SearchModal/index.tsx @@ -1,12 +1,18 @@ -import React, { useEffect, useState } from 'react' +import React, { useEffect, useRef, useState } from 'react' import { useRouter } from 'next/router' import { useSnapshot } from 'valtio' +import { useTranslation } from 'react-i18next' +import InfiniteScroll from 'react-infinite-scroll-component' import { appState } from '~utils/appState' import api from '~utils/api' import * as Dialog from '@radix-ui/react-dialog' +import CharacterSearchFilterBar from '~components/CharacterSearchFilterBar' +import WeaponSearchFilterBar from '~components/WeaponSearchFilterBar' +import SummonSearchFilterBar from '~components/SummonSearchFilterBar' + import CharacterResult from '~components/CharacterResult' import WeaponResult from '~components/WeaponResult' import SummonResult from '~components/SummonResult' @@ -28,17 +34,23 @@ const SearchModal = (props: Props) => { const router = useRouter() const locale = router.locale + const { t } = useTranslation('common') + let searchInput = React.createRef() + let scrollContainer = React.createRef() const [objects, setObjects] = useState<{[id: number]: GridCharacter | GridWeapon | GridSummon}>() + const [filters, setFilters] = useState<{ [key: string]: number[] }>() const [open, setOpen] = useState(false) const [query, setQuery] = useState('') - const [results, setResults] = useState({}) - const [loading, setLoading] = useState(false) - const [message, setMessage] = useState('') - const [totalResults, setTotalResults] = useState(0) + const [results, setResults] = useState<(Weapon | Summon | Character)[]>([]) - useEffect(() => { + // Pagination states + const [recordCount, setRecordCount] = useState(0) + const [currentPage, setCurrentPage] = useState(1) + const [totalPages, setTotalPages] = useState(1) + + useEffect(() => { setObjects(grid[props.object]) }, [grid, props.object]) @@ -47,50 +59,46 @@ const SearchModal = (props: Props) => { searchInput.current.focus() }, [searchInput]) - useEffect(() => { - if (query.length > 1) - fetchResults() - }, [query]) - function inputChanged(event: React.ChangeEvent) { const text = event.target.value if (text.length) { setQuery(text) - setLoading(true) - setMessage('') } else { setQuery('') - setResults({}) - setMessage('') } } - function fetchResults() { - // Exclude objects in grid from search results - // unless the object is in the position that the user clicked - // so that users can replace object versions with - // compatible other objects. - const excludes = (objects) ? Object.values(objects) - .filter(filterExclusions) - .map((o) => { return (o.object) ? o.object.name.en : undefined }).join(',') : '' + function fetchResults({ replace = false }: { replace?: boolean }) { + api.search({ + object: props.object, + query: query, + filters: filters, + locale: locale, + page: currentPage + }).then(response => { + setTotalPages(response.data.total_pages) + setRecordCount(response.data.count) - api.search(props.object, query, excludes, locale) - .then(response => { - setResults(response.data) - setTotalResults(response.data.length) - setLoading(false) - }) - .catch(error => { - setMessage(error) - setLoading(false) - }) + if (replace) { + replaceResults(response.data.count, response.data.results) + } else { + appendResults(response.data.results) + } + }).catch(error => { + console.error(error) + }) } - function filterExclusions(gridObject: GridCharacter | GridWeapon | GridSummon) { - if (objects && gridObject.object && - gridObject.object.granblue_id === objects[props.fromPosition]?.object.granblue_id) - return null - else return gridObject + function replaceResults(count: number, list: Weapon[] | Summon[] | Character[]) { + if (count > 0) { + setResults(list) + } else { + setResults([]) + } + } + + function appendResults(list: Weapon[] | Summon[] | Character[]) { + setResults([...results, ...list]) } function sendData(result: Character | Weapon | Summon) { @@ -98,106 +106,160 @@ const SearchModal = (props: Props) => { setOpen(false) } + function receiveFilters(filters: { [key: string]: number[] }) { + setCurrentPage(1) + setResults([]) + setFilters(filters) + } + + useEffect(() => { + // Current page changed + if (open && currentPage > 1) { + fetchResults({ replace: false }) + } else if (open && currentPage == 1) { + fetchResults({ replace: true }) + } + }, [currentPage]) + + useEffect(() => { + // Filters changed + if (open) { + setCurrentPage(1) + fetchResults({ replace: true }) + } + }, [filters]) + + useEffect(() => { + // Query changed + if (open && query.length != 1) { + setCurrentPage(1) + fetchResults({ replace: true }) + } + }, [query]) + function renderResults() { + let jsx + switch(props.object) { case 'weapons': - return renderWeaponSearchResults(results) + jsx = renderWeaponSearchResults() break case 'summons': - return renderSummonSearchResults(results) + jsx = renderSummonSearchResults(results) break case 'characters': - return renderCharacterSearchResults(results) + jsx = renderCharacterSearchResults(results) break } - } - - function renderWeaponSearchResults(results: { [key: string]: any }) { - const elements = results.map((result: Weapon) => { - return { sendData(result) }} - /> - }) - - return (
    {elements}
) - } - - function renderSummonSearchResults(results: { [key: string]: any }) { - const elements = results.map((result: Summon) => { - return { sendData(result) }} - /> - }) - - return (
    {elements}
) - } - - function renderCharacterSearchResults(results: { [key: string]: any }) { - const elements = results.map((result: Character) => { - return { sendData(result) }} - /> - }) - - return (
    {elements}
) - } - - function renderEmptyState() { - let string = '' - - if (query === '') { - string = `No ${props.object}` - } else if (query.length < 2) { - string = `Type at least 2 characters` - } else { - string = `No results found for '${query}'` - } return ( -
-

{string}

-
+ 0) ? results.length : 0} + next={ () => setCurrentPage(currentPage + 1) } + hasMore={totalPages > currentPage} + scrollableTarget="Results" + loader={
Loading...
}> + {jsx} +
) } + + function renderWeaponSearchResults() { + let jsx: React.ReactNode + + const castResults: Weapon[] = results as Weapon[] + if (castResults && Object.keys(castResults).length > 0) { + jsx = castResults.map((result: Weapon) => { + return { sendData(result) }} + /> + }) + } + + return jsx + } + + function renderSummonSearchResults(results: { [key: string]: any }) { + let jsx: React.ReactNode + + const castResults: Summon[] = results as Summon[] + if (castResults && Object.keys(castResults).length > 0) { + jsx = castResults.map((result: Summon) => { + return { sendData(result) }} + /> + }) + } + + return jsx + } + + function renderCharacterSearchResults(results: { [key: string]: any }) { + let jsx: React.ReactNode + + const castResults: Character[] = results as Character[] + if (castResults && Object.keys(castResults).length > 0) { + jsx = castResults.map((result: Character) => { + return { sendData(result) }} + /> + }) + } + + return jsx + } - function resetAndClose() { - setQuery('') - setResults({}) - setOpen(true) + function openChange() { + if (open) { + setQuery('') + setResults([]) + setOpen(false) + } else { + setOpen(true) + } } return ( - + {props.children} + +
+
{t('search.result_count', { "record_count": recordCount })}
+ { (open) ? renderResults() : ''}
- { ((Object.entries(results).length == 0) ? renderEmptyState() : renderResults()) }
diff --git a/components/SummonSearchFilterBar/index.scss b/components/SummonSearchFilterBar/index.scss new file mode 100644 index 00000000..e69de29b diff --git a/components/SummonSearchFilterBar/index.tsx b/components/SummonSearchFilterBar/index.tsx new file mode 100644 index 00000000..14be3c1c --- /dev/null +++ b/components/SummonSearchFilterBar/index.tsx @@ -0,0 +1,105 @@ +import React, { useEffect, useState } from 'react' +import { useTranslation } from 'next-i18next' + +import cloneDeep from 'lodash.clonedeep' + +import * as DropdownMenu from '@radix-ui/react-dropdown-menu' + +import SearchFilter from '~components/SearchFilter' +import SearchFilterCheckboxItem from '~components/SearchFilterCheckboxItem' + +import './index.scss' +import { emptyElementState, emptyRarityState } from '~utils/emptyStates' +import { elements, rarities } from '~utils/stateValues' + +interface Props { + sendFilters: (filters: { [key: string]: number[] }) => void +} + +const SummonSearchFilterBar = (props: Props) => { + const { t } = useTranslation('common') + + const [rarityMenu, setRarityMenu] = useState(false) + const [elementMenu, setElementMenu] = useState(false) + + const [rarityState, setRarityState] = useState(emptyRarityState) + const [elementState, setElementState] = useState(emptyElementState) + + function rarityMenuOpened(open: boolean) { + if (open) { + setRarityMenu(true) + setElementMenu(false) + } else setRarityMenu(false) + } + + function elementMenuOpened(open: boolean) { + if (open) { + setRarityMenu(false) + setElementMenu(true) + } else setElementMenu(false) + } + + function handleRarityChange(checked: boolean, key: string) { + let newRarityState = cloneDeep(rarityState) + newRarityState[key].checked = checked + setRarityState(newRarityState) + } + + function handleElementChange(checked: boolean, key: string) { + let newElementState = cloneDeep(elementState) + newElementState[key].checked = checked + setElementState(newElementState) + } + + function sendFilters() { + const checkedRarityFilters = Object.values(rarityState).filter(x => x.checked).map((x, i) => x.id) + const checkedElementFilters = Object.values(elementState).filter(x => x.checked).map((x, i) => x.id) + + const filters = { + rarity: checkedRarityFilters, + element: checkedElementFilters + } + + props.sendFilters(filters) + } + + useEffect(() => { + sendFilters() + }, [rarityState, elementState]) + + return ( +
+ x.checked).filter(Boolean).length} open={rarityMenu} onOpenChange={rarityMenuOpened}> + {t('filters.labels.rarity')} + { Array.from(Array(rarities.length)).map((x, i) => { + return ( + + {t(`rarities.${rarities[i]}`)} + + )} + ) } + + + x.checked).filter(Boolean).length} open={elementMenu} onOpenChange={elementMenuOpened}> + {t('filters.labels.element')} + { Array.from(Array(elements.length)).map((x, i) => { + return ( + + {t(`elements.${elements[i]}`)} + + )} + ) } + +
+ ) +} + +export default SummonSearchFilterBar diff --git a/components/WeaponSearchFilterBar/index.scss b/components/WeaponSearchFilterBar/index.scss new file mode 100644 index 00000000..e69de29b diff --git a/components/WeaponSearchFilterBar/index.tsx b/components/WeaponSearchFilterBar/index.tsx new file mode 100644 index 00000000..68ae7063 --- /dev/null +++ b/components/WeaponSearchFilterBar/index.tsx @@ -0,0 +1,224 @@ +import React, { useEffect, useState } from 'react' +import { useTranslation } from 'next-i18next' + +import cloneDeep from 'lodash.clonedeep' + +import * as DropdownMenu from '@radix-ui/react-dropdown-menu' + +import SearchFilter from '~components/SearchFilter' +import SearchFilterCheckboxItem from '~components/SearchFilterCheckboxItem' + +import './index.scss' +import { emptyElementState, emptyProficiencyState, emptyRarityState, emptyWeaponSeriesState } from '~utils/emptyStates' +import { elements, proficiencies, rarities, weaponSeries } from '~utils/stateValues' + +interface Props { + sendFilters: (filters: { [key: string]: number[] }) => void +} + +const WeaponSearchFilterBar = (props: Props) => { + const { t } = useTranslation('common') + + const [rarityMenu, setRarityMenu] = useState(false) + const [elementMenu, setElementMenu] = useState(false) + const [proficiencyMenu, setProficiencyMenu] = useState(false) + const [seriesMenu, setSeriesMenu] = useState(false) + + const [rarityState, setRarityState] = useState(emptyRarityState) + const [elementState, setElementState] = useState(emptyElementState) + const [proficiencyState, setProficiencyState] = useState(emptyProficiencyState) + const [seriesState, setSeriesState] = useState(emptyWeaponSeriesState) + + function rarityMenuOpened(open: boolean) { + if (open) { + setRarityMenu(true) + setElementMenu(false) + setProficiencyMenu(false) + setSeriesMenu(false) + } else setRarityMenu(false) + } + + function elementMenuOpened(open: boolean) { + if (open) { + setRarityMenu(false) + setElementMenu(true) + setProficiencyMenu(false) + setSeriesMenu(false) + } else setElementMenu(false) + } + + function proficiencyMenuOpened(open: boolean) { + if (open) { + setRarityMenu(false) + setElementMenu(false) + setProficiencyMenu(true) + setSeriesMenu(false) + } else setProficiencyMenu(false) + } + + function seriesMenuOpened(open: boolean) { + if (open) { + setRarityMenu(false) + setElementMenu(false) + setProficiencyMenu(false) + setSeriesMenu(true) + } else setSeriesMenu(false) + } + + function handleRarityChange(checked: boolean, key: string) { + let newRarityState = cloneDeep(rarityState) + newRarityState[key].checked = checked + setRarityState(newRarityState) + } + + function handleElementChange(checked: boolean, key: string) { + let newElementState = cloneDeep(elementState) + newElementState[key].checked = checked + setElementState(newElementState) + } + + function handleProficiencyChange(checked: boolean, key: string) { + let newProficiencyState = cloneDeep(proficiencyState) + newProficiencyState[key].checked = checked + setProficiencyState(newProficiencyState) + } + + function handleSeriesChange(checked: boolean, key: string) { + let newSeriesState = cloneDeep(seriesState) + newSeriesState[key].checked = checked + setSeriesState(newSeriesState) + } + + function sendFilters() { + const checkedRarityFilters = Object.values(rarityState).filter(x => x.checked).map((x, i) => x.id) + const checkedElementFilters = Object.values(elementState).filter(x => x.checked).map((x, i) => x.id) + const checkedProficiencyFilters = Object.values(proficiencyState).filter(x => x.checked).map((x, i) => x.id) + const checkedSeriesFilters = Object.values(seriesState).filter(x => x.checked).map((x, i) => x.id) + + const filters = { + rarity: checkedRarityFilters, + element: checkedElementFilters, + proficiency1: checkedProficiencyFilters, + series: checkedSeriesFilters + } + + props.sendFilters(filters) + } + + useEffect(() => { + sendFilters() + }, [rarityState, elementState, proficiencyState, seriesState]) + + return ( +
+ x.checked).filter(Boolean).length} open={rarityMenu} onOpenChange={rarityMenuOpened}> + {t('filters.labels.rarity')} + { Array.from(Array(rarities.length)).map((x, i) => { + return ( + + {t(`rarities.${rarities[i]}`)} + + )} + ) } + + + x.checked).filter(Boolean).length} open={elementMenu} onOpenChange={elementMenuOpened}> + {t('filters.labels.element')} + { Array.from(Array(elements.length)).map((x, i) => { + return ( + + {t(`elements.${elements[i]}`)} + + )} + ) } + + + x.checked).filter(Boolean).length} open={proficiencyMenu} onOpenChange={proficiencyMenuOpened}> + {t('filters.labels.proficiency')} +
+ + { Array.from(Array(proficiencies.length / 2)).map((x, i) => { + return ( + + {t(`proficiencies.${proficiencies[i]}`)} + + )} + ) } + + + { Array.from(Array(proficiencies.length / 2)).map((x, i) => { + return ( + + {t(`proficiencies.${proficiencies[i + (proficiencies.length / 2)]}`)} + + )} + ) } + +
+
+ + x.checked).filter(Boolean).length} open={seriesMenu} onOpenChange={seriesMenuOpened}> + {t('filters.labels.series')} +
+ + { Array.from(Array(weaponSeries.length / 3)).map((x, i) => { + return ( + + {t(`series.${weaponSeries[i]}`)} + + )} + ) } + + + { Array.from(Array(weaponSeries.length / 3)).map((x, i) => { + return ( + + {t(`series.${weaponSeries[i + (weaponSeries.length / 3)]}`)} + + )} + ) } + + + { Array.from(Array(weaponSeries.length / 3)).map((x, i) => { + return ( + + {t(`series.${weaponSeries[i + (2 * (weaponSeries.length / 3))]}`)} + + )} + ) } + +
+
+
+ ) +} + +export default WeaponSearchFilterBar diff --git a/package-lock.json b/package-lock.json index 30d15c8f..8bfb66b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "dependencies": { "@radix-ui/react-alert-dialog": "^0.1.5", "@radix-ui/react-dialog": "^0.1.5", - "@radix-ui/react-dropdown-menu": "^0.1.4", + "@radix-ui/react-dropdown-menu": "^0.1.6", "@radix-ui/react-hover-card": "^0.1.5", "@radix-ui/react-label": "^0.1.4", "@radix-ui/react-switch": "^0.1.5", @@ -31,6 +31,8 @@ "react-cookie": "^4.1.1", "react-dom": "^17.0.2", "react-i18next": "^11.15.5", + "react-infinite-scroll-component": "^6.1.0", + "react-infinite-scroller": "^1.2.5", "react-linkify": "^1.0.0-alpha", "react-scroll": "^1.8.5", "sass": "^1.49.0", @@ -42,6 +44,7 @@ "@types/node": "17.0.11", "@types/react": "17.0.38", "@types/react-dom": "^17.0.11", + "@types/react-infinite-scroller": "^1.2.2", "@types/react-linkify": "^1.0.1", "@types/react-scroll": "^1.8.3", "eslint": "8.7.0", @@ -2319,26 +2322,50 @@ } }, "node_modules/@radix-ui/react-arrow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-0.1.3.tgz", - "integrity": "sha512-9x1gRYdlUD5OUwY7L+M+4FY/YltDSsrNSj8QXGPbxZxL5ghWXB/4lhyIGccCwk/e8ggfmQYv9SRNmn3LavPo3A==", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-0.1.4.tgz", + "integrity": "sha512-BB6XzAb7Ml7+wwpFdYVtZpK1BlMgqyafSQNGzhIpSZ4uXvXOHPlR5GP8M449JkeQzgQjv9Mp1AsJxFC0KuOtuA==", "dependencies": { "@babel/runtime": "^7.13.10", - "@radix-ui/react-primitive": "0.1.3" + "@radix-ui/react-primitive": "0.1.4" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-primitive": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz", + "integrity": "sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "0.1.2" }, "peerDependencies": { "react": "^16.8 || ^17.0" } }, "node_modules/@radix-ui/react-collection": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-0.1.3.tgz", - "integrity": "sha512-tMBY65l87tj77fMX44EBjm5p8clR6swkcNFr0/dDVdEPC0Vf3fwkv62dezCnZyrRBpkOgZPDOp2kO73hYlCfXw==", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-0.1.4.tgz", + "integrity": "sha512-3muGI15IdgaDFjOcO7xX8a35HQRBRF6LH9pS6UCeZeRmbslkVeHyJRQr2rzICBUoX7zgIA0kXyMDbpQnJGyJTA==", "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "0.1.0", "@radix-ui/react-context": "0.1.1", - "@radix-ui/react-primitive": "0.1.3", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-slot": "0.1.2" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-primitive": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz", + "integrity": "sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA==", + "dependencies": { + "@babel/runtime": "^7.13.10", "@radix-ui/react-slot": "0.1.2" }, "peerDependencies": { @@ -2411,17 +2438,17 @@ } }, "node_modules/@radix-ui/react-dropdown-menu": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-0.1.4.tgz", - "integrity": "sha512-KNFHOK+zKKqZ7x3OoxCXZ2TRESRmHpgxkXpY75i/GFt3i5N/RIH5rB9WSdwhdQXM7gkihYZIDwjdmhhSsgzHkw==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-0.1.6.tgz", + "integrity": "sha512-RZhtzjWwJ4ZBN7D8ek4Zn+ilHzYuYta9yIxFnbC0pfqMnSi67IQNONo1tuuNqtFh9SRHacPKc65zo+kBBlxtdg==", "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "0.1.0", "@radix-ui/react-compose-refs": "0.1.0", "@radix-ui/react-context": "0.1.1", - "@radix-ui/react-id": "0.1.4", - "@radix-ui/react-menu": "0.1.4", - "@radix-ui/react-primitive": "0.1.3", + "@radix-ui/react-id": "0.1.5", + "@radix-ui/react-menu": "0.1.6", + "@radix-ui/react-primitive": "0.1.4", "@radix-ui/react-use-controllable-state": "0.1.0" }, "peerDependencies": { @@ -2429,6 +2456,30 @@ "react-dom": "^16.8 || ^17.0" } }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-id": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-0.1.5.tgz", + "integrity": "sha512-IPc4H/63bes0IZ1GJJozSEkSWcDyhNGtKFWUpJ+XtaLyQ1X3x7Mf6fWwWhDcpqlYEP+5WtAvfqcyEsyjP+ZhBQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "0.1.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-primitive": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz", + "integrity": "sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "0.1.2" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, "node_modules/@radix-ui/react-focus-guards": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-0.1.0.tgz", @@ -2475,18 +2526,6 @@ "react-dom": "^16.8 || ^17.0" } }, - "node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-arrow": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-0.1.4.tgz", - "integrity": "sha512-BB6XzAb7Ml7+wwpFdYVtZpK1BlMgqyafSQNGzhIpSZ4uXvXOHPlR5GP8M449JkeQzgQjv9Mp1AsJxFC0KuOtuA==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-primitive": "0.1.4" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0" - } - }, "node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-dismissable-layer": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-0.1.5.tgz", @@ -2504,25 +2543,6 @@ "react": "^16.8 || ^17.0" } }, - "node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-popper": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-0.1.4.tgz", - "integrity": "sha512-18gDYof97t8UQa7zwklG1Dr8jIdj3u+rVOQLzPi9f5i1YQak/pVGkaqw8aY+iDUknKKuZniTk/7jbAJUYlKyOw==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/popper": "0.1.0", - "@radix-ui/react-arrow": "0.1.4", - "@radix-ui/react-compose-refs": "0.1.0", - "@radix-ui/react-context": "0.1.1", - "@radix-ui/react-primitive": "0.1.4", - "@radix-ui/react-use-rect": "0.1.1", - "@radix-ui/react-use-size": "0.1.1", - "@radix-ui/rect": "0.1.1" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0" - } - }, "node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-portal": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-0.1.4.tgz", @@ -2574,17 +2594,6 @@ "react": "^16.8 || ^17.0" } }, - "node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-use-size": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-0.1.1.tgz", - "integrity": "sha512-pTgWM5qKBu6C7kfKxrKPoBI2zZYZmp2cSXzpUiGM3qEBQlMLtYhaY2JXdXUCxz+XmD1YEjc8oRwvyfsD4AG4WA==", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0" - } - }, "node_modules/@radix-ui/react-id": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-0.1.4.tgz", @@ -2637,24 +2646,24 @@ } }, "node_modules/@radix-ui/react-menu": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-0.1.4.tgz", - "integrity": "sha512-50HvBojjj2CrwIxcECRF9MdReoALRdpG7vtCAGbYs3eciIOLqtP6+Dx/sVz1YWe6Fsree/5vFQXZGImZYY/3TQ==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-0.1.6.tgz", + "integrity": "sha512-ho3+bhpr3oAFkOBJ8VkUb1BcGoiZBB3OmcWPqa6i5RTUKrzNX/d6rauochu2xDlWjiRtpVuiAcsTVOeIC4FbYQ==", "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "0.1.0", - "@radix-ui/react-collection": "0.1.3", + "@radix-ui/react-collection": "0.1.4", "@radix-ui/react-compose-refs": "0.1.0", "@radix-ui/react-context": "0.1.1", - "@radix-ui/react-dismissable-layer": "0.1.3", + "@radix-ui/react-dismissable-layer": "0.1.5", "@radix-ui/react-focus-guards": "0.1.0", - "@radix-ui/react-focus-scope": "0.1.3", - "@radix-ui/react-id": "0.1.4", - "@radix-ui/react-popper": "0.1.3", - "@radix-ui/react-portal": "0.1.3", - "@radix-ui/react-presence": "0.1.1", - "@radix-ui/react-primitive": "0.1.3", - "@radix-ui/react-roving-focus": "0.1.4", + "@radix-ui/react-focus-scope": "0.1.4", + "@radix-ui/react-id": "0.1.5", + "@radix-ui/react-popper": "0.1.4", + "@radix-ui/react-portal": "0.1.4", + "@radix-ui/react-presence": "0.1.2", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-roving-focus": "0.1.5", "@radix-ui/react-use-callback-ref": "0.1.0", "@radix-ui/react-use-direction": "0.1.0", "aria-hidden": "^1.1.1", @@ -2665,25 +2674,131 @@ "react-dom": "^16.8 || ^17.0" } }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-dismissable-layer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-0.1.5.tgz", + "integrity": "sha512-J+fYWijkX4M4QKwf9dtu1oC0U6e6CEl8WhBp3Ad23yz2Hia0XCo6Pk/mp5CAFy4QBtQedTSkhW05AdtSOEoajQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "0.1.0", + "@radix-ui/react-compose-refs": "0.1.0", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-use-body-pointer-events": "0.1.1", + "@radix-ui/react-use-callback-ref": "0.1.0", + "@radix-ui/react-use-escape-keydown": "0.1.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-focus-scope": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-0.1.4.tgz", + "integrity": "sha512-fbA4ES3H4Wkxp+OeLhvN6SwL7mXNn/aBtUf7DRYxY9+Akrf7dRxl2ck4lgcpPsSg3zSDsEwLcY+h5cmj5yvlug==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "0.1.0", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-use-callback-ref": "0.1.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-id": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-0.1.5.tgz", + "integrity": "sha512-IPc4H/63bes0IZ1GJJozSEkSWcDyhNGtKFWUpJ+XtaLyQ1X3x7Mf6fWwWhDcpqlYEP+5WtAvfqcyEsyjP+ZhBQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "0.1.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-portal": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-0.1.4.tgz", + "integrity": "sha512-MO0wRy2eYRTZ/CyOri9NANCAtAtq89DEtg90gicaTlkCfdqCLEBsLb+/q66BZQTr3xX/Vq01nnVfc/TkCqoqvw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-use-layout-effect": "0.1.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0", + "react-dom": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-presence": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-0.1.2.tgz", + "integrity": "sha512-3BRlFZraooIUfRlyN+b/Xs5hq1lanOOo/+3h6Pwu2GMFjkGKKa4Rd51fcqGqnVlbr3jYg+WLuGyAV4KlgqwrQw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "0.1.0", + "@radix-ui/react-use-layout-effect": "0.1.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-primitive": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz", + "integrity": "sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "0.1.2" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-use-body-pointer-events": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-body-pointer-events/-/react-use-body-pointer-events-0.1.1.tgz", + "integrity": "sha512-R8leV2AWmJokTmERM8cMXFHWSiv/fzOLhG/JLmRBhLTAzOj37EQizssq4oW0Z29VcZy2tODMi9Pk/htxwb+xpA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "0.1.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, "node_modules/@radix-ui/react-popper": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-0.1.3.tgz", - "integrity": "sha512-2OV2YaJv7iTZexJY3HJ7B6Fs1A/3JXd3fRGU4JY0guACfGMD1C/jSgds505MKQOTiHE/quI6j3/q8yfzFjJR9g==", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-0.1.4.tgz", + "integrity": "sha512-18gDYof97t8UQa7zwklG1Dr8jIdj3u+rVOQLzPi9f5i1YQak/pVGkaqw8aY+iDUknKKuZniTk/7jbAJUYlKyOw==", "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/popper": "0.1.0", - "@radix-ui/react-arrow": "0.1.3", + "@radix-ui/react-arrow": "0.1.4", "@radix-ui/react-compose-refs": "0.1.0", "@radix-ui/react-context": "0.1.1", - "@radix-ui/react-primitive": "0.1.3", + "@radix-ui/react-primitive": "0.1.4", "@radix-ui/react-use-rect": "0.1.1", - "@radix-ui/react-use-size": "0.1.0", + "@radix-ui/react-use-size": "0.1.1", "@radix-ui/rect": "0.1.1" }, "peerDependencies": { "react": "^16.8 || ^17.0" } }, + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-primitive": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz", + "integrity": "sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "0.1.2" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, "node_modules/@radix-ui/react-portal": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-0.1.3.tgz", @@ -2724,17 +2839,17 @@ } }, "node_modules/@radix-ui/react-roving-focus": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-0.1.4.tgz", - "integrity": "sha512-zaixcAxRcWQliUSx6l9rdfJhvcbuY7Tb4Emb7H4DWCTx1kenXH8+n9mwa8gaSIJLLSSSMzBpQATlpFw9xv/bJQ==", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-0.1.5.tgz", + "integrity": "sha512-ClwKPS5JZE+PaHCoW7eu1onvE61pDv4kO8W4t5Ra3qMFQiTJLZMdpBQUhksN//DaVygoLirz4Samdr5Y1x1FSA==", "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "0.1.0", - "@radix-ui/react-collection": "0.1.3", + "@radix-ui/react-collection": "0.1.4", "@radix-ui/react-compose-refs": "0.1.0", "@radix-ui/react-context": "0.1.1", - "@radix-ui/react-id": "0.1.4", - "@radix-ui/react-primitive": "0.1.3", + "@radix-ui/react-id": "0.1.5", + "@radix-ui/react-primitive": "0.1.4", "@radix-ui/react-use-callback-ref": "0.1.0", "@radix-ui/react-use-controllable-state": "0.1.0" }, @@ -2742,6 +2857,30 @@ "react": "^16.8 || ^17.0" } }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-id": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-0.1.5.tgz", + "integrity": "sha512-IPc4H/63bes0IZ1GJJozSEkSWcDyhNGtKFWUpJ+XtaLyQ1X3x7Mf6fWwWhDcpqlYEP+5WtAvfqcyEsyjP+ZhBQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "0.1.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-primitive": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz", + "integrity": "sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "0.1.2" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0" + } + }, "node_modules/@radix-ui/react-slot": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-0.1.2.tgz", @@ -2785,17 +2924,6 @@ "react": "^16.8 || ^17.0" } }, - "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-use-size": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-0.1.1.tgz", - "integrity": "sha512-pTgWM5qKBu6C7kfKxrKPoBI2zZYZmp2cSXzpUiGM3qEBQlMLtYhaY2JXdXUCxz+XmD1YEjc8oRwvyfsD4AG4WA==", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0" - } - }, "node_modules/@radix-ui/react-toggle": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-0.1.4.tgz", @@ -2827,33 +2955,6 @@ "react": "^16.8 || ^17.0" } }, - "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-collection": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-0.1.4.tgz", - "integrity": "sha512-3muGI15IdgaDFjOcO7xX8a35HQRBRF6LH9pS6UCeZeRmbslkVeHyJRQr2rzICBUoX7zgIA0kXyMDbpQnJGyJTA==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "0.1.0", - "@radix-ui/react-context": "0.1.1", - "@radix-ui/react-primitive": "0.1.4", - "@radix-ui/react-slot": "0.1.2" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0" - } - }, - "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-id": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-0.1.5.tgz", - "integrity": "sha512-IPc4H/63bes0IZ1GJJozSEkSWcDyhNGtKFWUpJ+XtaLyQ1X3x7Mf6fWwWhDcpqlYEP+5WtAvfqcyEsyjP+ZhBQ==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-use-layout-effect": "0.1.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0" - } - }, "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-primitive": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz", @@ -2866,25 +2967,6 @@ "react": "^16.8 || ^17.0" } }, - "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-roving-focus": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-0.1.5.tgz", - "integrity": "sha512-ClwKPS5JZE+PaHCoW7eu1onvE61pDv4kO8W4t5Ra3qMFQiTJLZMdpBQUhksN//DaVygoLirz4Samdr5Y1x1FSA==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "0.1.0", - "@radix-ui/react-collection": "0.1.4", - "@radix-ui/react-compose-refs": "0.1.0", - "@radix-ui/react-context": "0.1.1", - "@radix-ui/react-id": "0.1.5", - "@radix-ui/react-primitive": "0.1.4", - "@radix-ui/react-use-callback-ref": "0.1.0", - "@radix-ui/react-use-controllable-state": "0.1.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0" - } - }, "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-primitive": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz", @@ -2990,9 +3072,9 @@ } }, "node_modules/@radix-ui/react-use-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-0.1.0.tgz", - "integrity": "sha512-TcZAsR+BYI46w/RbaSFCRACl+Jh6mDqhu6GS2r0iuJpIVrj8atff7qtTjmMmfGtEDNEjhl7DxN3pr1nTS/oruQ==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-0.1.1.tgz", + "integrity": "sha512-pTgWM5qKBu6C7kfKxrKPoBI2zZYZmp2cSXzpUiGM3qEBQlMLtYhaY2JXdXUCxz+XmD1YEjc8oRwvyfsD4AG4WA==", "dependencies": { "@babel/runtime": "^7.13.10" }, @@ -3362,6 +3444,15 @@ "@types/react": "*" } }, + "node_modules/@types/react-infinite-scroller": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/react-infinite-scroller/-/react-infinite-scroller-1.2.2.tgz", + "integrity": "sha512-3Tu/wspMKAOH/YkGmTrXgfYizL9DnMb4opksrl+m5jiESxGkRN4tiKf6lr7SN0FUgoFyQyK9o+yMKn1bWMTVmA==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-linkify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/react-linkify/-/react-linkify-1.0.1.tgz", @@ -6764,6 +6855,28 @@ } } }, + "node_modules/react-infinite-scroll-component": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-infinite-scroll-component/-/react-infinite-scroll-component-6.1.0.tgz", + "integrity": "sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==", + "dependencies": { + "throttle-debounce": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.0.0" + } + }, + "node_modules/react-infinite-scroller": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/react-infinite-scroller/-/react-infinite-scroller-1.2.5.tgz", + "integrity": "sha512-2A+SFUliZhVcxr4R2kFBrW/naGSluNMLqT6wfgmXKCggN1u/H4AW7flBLWHcY/5n/KviVLnpQfaMfBb/pG/m7g==", + "dependencies": { + "prop-types": "^15.5.8" + }, + "peerDependencies": { + "react": "^0.14.9 || ^15.3.0 || ^16.0.0 || ^17.0.0" + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -7452,6 +7565,14 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "node_modules/throttle-debounce": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz", + "integrity": "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/tlds": { "version": "1.230.0", "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.230.0.tgz", @@ -9414,24 +9535,46 @@ } }, "@radix-ui/react-arrow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-0.1.3.tgz", - "integrity": "sha512-9x1gRYdlUD5OUwY7L+M+4FY/YltDSsrNSj8QXGPbxZxL5ghWXB/4lhyIGccCwk/e8ggfmQYv9SRNmn3LavPo3A==", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-0.1.4.tgz", + "integrity": "sha512-BB6XzAb7Ml7+wwpFdYVtZpK1BlMgqyafSQNGzhIpSZ4uXvXOHPlR5GP8M449JkeQzgQjv9Mp1AsJxFC0KuOtuA==", "requires": { "@babel/runtime": "^7.13.10", - "@radix-ui/react-primitive": "0.1.3" + "@radix-ui/react-primitive": "0.1.4" + }, + "dependencies": { + "@radix-ui/react-primitive": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz", + "integrity": "sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "0.1.2" + } + } } }, "@radix-ui/react-collection": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-0.1.3.tgz", - "integrity": "sha512-tMBY65l87tj77fMX44EBjm5p8clR6swkcNFr0/dDVdEPC0Vf3fwkv62dezCnZyrRBpkOgZPDOp2kO73hYlCfXw==", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-0.1.4.tgz", + "integrity": "sha512-3muGI15IdgaDFjOcO7xX8a35HQRBRF6LH9pS6UCeZeRmbslkVeHyJRQr2rzICBUoX7zgIA0kXyMDbpQnJGyJTA==", "requires": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "0.1.0", "@radix-ui/react-context": "0.1.1", - "@radix-ui/react-primitive": "0.1.3", + "@radix-ui/react-primitive": "0.1.4", "@radix-ui/react-slot": "0.1.2" + }, + "dependencies": { + "@radix-ui/react-primitive": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz", + "integrity": "sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "0.1.2" + } + } } }, "@radix-ui/react-compose-refs": { @@ -9487,18 +9630,38 @@ } }, "@radix-ui/react-dropdown-menu": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-0.1.4.tgz", - "integrity": "sha512-KNFHOK+zKKqZ7x3OoxCXZ2TRESRmHpgxkXpY75i/GFt3i5N/RIH5rB9WSdwhdQXM7gkihYZIDwjdmhhSsgzHkw==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-0.1.6.tgz", + "integrity": "sha512-RZhtzjWwJ4ZBN7D8ek4Zn+ilHzYuYta9yIxFnbC0pfqMnSi67IQNONo1tuuNqtFh9SRHacPKc65zo+kBBlxtdg==", "requires": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "0.1.0", "@radix-ui/react-compose-refs": "0.1.0", "@radix-ui/react-context": "0.1.1", - "@radix-ui/react-id": "0.1.4", - "@radix-ui/react-menu": "0.1.4", - "@radix-ui/react-primitive": "0.1.3", + "@radix-ui/react-id": "0.1.5", + "@radix-ui/react-menu": "0.1.6", + "@radix-ui/react-primitive": "0.1.4", "@radix-ui/react-use-controllable-state": "0.1.0" + }, + "dependencies": { + "@radix-ui/react-id": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-0.1.5.tgz", + "integrity": "sha512-IPc4H/63bes0IZ1GJJozSEkSWcDyhNGtKFWUpJ+XtaLyQ1X3x7Mf6fWwWhDcpqlYEP+5WtAvfqcyEsyjP+ZhBQ==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "0.1.0" + } + }, + "@radix-ui/react-primitive": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz", + "integrity": "sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "0.1.2" + } + } } }, "@radix-ui/react-focus-guards": { @@ -9537,15 +9700,6 @@ "@radix-ui/react-use-controllable-state": "0.1.0" }, "dependencies": { - "@radix-ui/react-arrow": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-0.1.4.tgz", - "integrity": "sha512-BB6XzAb7Ml7+wwpFdYVtZpK1BlMgqyafSQNGzhIpSZ4uXvXOHPlR5GP8M449JkeQzgQjv9Mp1AsJxFC0KuOtuA==", - "requires": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-primitive": "0.1.4" - } - }, "@radix-ui/react-dismissable-layer": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-0.1.5.tgz", @@ -9560,22 +9714,6 @@ "@radix-ui/react-use-escape-keydown": "0.1.0" } }, - "@radix-ui/react-popper": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-0.1.4.tgz", - "integrity": "sha512-18gDYof97t8UQa7zwklG1Dr8jIdj3u+rVOQLzPi9f5i1YQak/pVGkaqw8aY+iDUknKKuZniTk/7jbAJUYlKyOw==", - "requires": { - "@babel/runtime": "^7.13.10", - "@radix-ui/popper": "0.1.0", - "@radix-ui/react-arrow": "0.1.4", - "@radix-ui/react-compose-refs": "0.1.0", - "@radix-ui/react-context": "0.1.1", - "@radix-ui/react-primitive": "0.1.4", - "@radix-ui/react-use-rect": "0.1.1", - "@radix-ui/react-use-size": "0.1.1", - "@radix-ui/rect": "0.1.1" - } - }, "@radix-ui/react-portal": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-0.1.4.tgz", @@ -9613,14 +9751,6 @@ "@babel/runtime": "^7.13.10", "@radix-ui/react-use-layout-effect": "0.1.0" } - }, - "@radix-ui/react-use-size": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-0.1.1.tgz", - "integrity": "sha512-pTgWM5qKBu6C7kfKxrKPoBI2zZYZmp2cSXzpUiGM3qEBQlMLtYhaY2JXdXUCxz+XmD1YEjc8oRwvyfsD4AG4WA==", - "requires": { - "@babel/runtime": "^7.13.10" - } } } }, @@ -9666,44 +9796,129 @@ } }, "@radix-ui/react-menu": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-0.1.4.tgz", - "integrity": "sha512-50HvBojjj2CrwIxcECRF9MdReoALRdpG7vtCAGbYs3eciIOLqtP6+Dx/sVz1YWe6Fsree/5vFQXZGImZYY/3TQ==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-0.1.6.tgz", + "integrity": "sha512-ho3+bhpr3oAFkOBJ8VkUb1BcGoiZBB3OmcWPqa6i5RTUKrzNX/d6rauochu2xDlWjiRtpVuiAcsTVOeIC4FbYQ==", "requires": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "0.1.0", - "@radix-ui/react-collection": "0.1.3", + "@radix-ui/react-collection": "0.1.4", "@radix-ui/react-compose-refs": "0.1.0", "@radix-ui/react-context": "0.1.1", - "@radix-ui/react-dismissable-layer": "0.1.3", + "@radix-ui/react-dismissable-layer": "0.1.5", "@radix-ui/react-focus-guards": "0.1.0", - "@radix-ui/react-focus-scope": "0.1.3", - "@radix-ui/react-id": "0.1.4", - "@radix-ui/react-popper": "0.1.3", - "@radix-ui/react-portal": "0.1.3", - "@radix-ui/react-presence": "0.1.1", - "@radix-ui/react-primitive": "0.1.3", - "@radix-ui/react-roving-focus": "0.1.4", + "@radix-ui/react-focus-scope": "0.1.4", + "@radix-ui/react-id": "0.1.5", + "@radix-ui/react-popper": "0.1.4", + "@radix-ui/react-portal": "0.1.4", + "@radix-ui/react-presence": "0.1.2", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-roving-focus": "0.1.5", "@radix-ui/react-use-callback-ref": "0.1.0", "@radix-ui/react-use-direction": "0.1.0", "aria-hidden": "^1.1.1", "react-remove-scroll": "^2.4.0" + }, + "dependencies": { + "@radix-ui/react-dismissable-layer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-0.1.5.tgz", + "integrity": "sha512-J+fYWijkX4M4QKwf9dtu1oC0U6e6CEl8WhBp3Ad23yz2Hia0XCo6Pk/mp5CAFy4QBtQedTSkhW05AdtSOEoajQ==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "0.1.0", + "@radix-ui/react-compose-refs": "0.1.0", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-use-body-pointer-events": "0.1.1", + "@radix-ui/react-use-callback-ref": "0.1.0", + "@radix-ui/react-use-escape-keydown": "0.1.0" + } + }, + "@radix-ui/react-focus-scope": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-0.1.4.tgz", + "integrity": "sha512-fbA4ES3H4Wkxp+OeLhvN6SwL7mXNn/aBtUf7DRYxY9+Akrf7dRxl2ck4lgcpPsSg3zSDsEwLcY+h5cmj5yvlug==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "0.1.0", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-use-callback-ref": "0.1.0" + } + }, + "@radix-ui/react-id": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-0.1.5.tgz", + "integrity": "sha512-IPc4H/63bes0IZ1GJJozSEkSWcDyhNGtKFWUpJ+XtaLyQ1X3x7Mf6fWwWhDcpqlYEP+5WtAvfqcyEsyjP+ZhBQ==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "0.1.0" + } + }, + "@radix-ui/react-portal": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-0.1.4.tgz", + "integrity": "sha512-MO0wRy2eYRTZ/CyOri9NANCAtAtq89DEtg90gicaTlkCfdqCLEBsLb+/q66BZQTr3xX/Vq01nnVfc/TkCqoqvw==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "0.1.4", + "@radix-ui/react-use-layout-effect": "0.1.0" + } + }, + "@radix-ui/react-presence": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-0.1.2.tgz", + "integrity": "sha512-3BRlFZraooIUfRlyN+b/Xs5hq1lanOOo/+3h6Pwu2GMFjkGKKa4Rd51fcqGqnVlbr3jYg+WLuGyAV4KlgqwrQw==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "0.1.0", + "@radix-ui/react-use-layout-effect": "0.1.0" + } + }, + "@radix-ui/react-primitive": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz", + "integrity": "sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "0.1.2" + } + }, + "@radix-ui/react-use-body-pointer-events": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-body-pointer-events/-/react-use-body-pointer-events-0.1.1.tgz", + "integrity": "sha512-R8leV2AWmJokTmERM8cMXFHWSiv/fzOLhG/JLmRBhLTAzOj37EQizssq4oW0Z29VcZy2tODMi9Pk/htxwb+xpA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "0.1.0" + } + } } }, "@radix-ui/react-popper": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-0.1.3.tgz", - "integrity": "sha512-2OV2YaJv7iTZexJY3HJ7B6Fs1A/3JXd3fRGU4JY0guACfGMD1C/jSgds505MKQOTiHE/quI6j3/q8yfzFjJR9g==", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-0.1.4.tgz", + "integrity": "sha512-18gDYof97t8UQa7zwklG1Dr8jIdj3u+rVOQLzPi9f5i1YQak/pVGkaqw8aY+iDUknKKuZniTk/7jbAJUYlKyOw==", "requires": { "@babel/runtime": "^7.13.10", "@radix-ui/popper": "0.1.0", - "@radix-ui/react-arrow": "0.1.3", + "@radix-ui/react-arrow": "0.1.4", "@radix-ui/react-compose-refs": "0.1.0", "@radix-ui/react-context": "0.1.1", - "@radix-ui/react-primitive": "0.1.3", + "@radix-ui/react-primitive": "0.1.4", "@radix-ui/react-use-rect": "0.1.1", - "@radix-ui/react-use-size": "0.1.0", + "@radix-ui/react-use-size": "0.1.1", "@radix-ui/rect": "0.1.1" + }, + "dependencies": { + "@radix-ui/react-primitive": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz", + "integrity": "sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "0.1.2" + } + } } }, "@radix-ui/react-portal": { @@ -9736,19 +9951,39 @@ } }, "@radix-ui/react-roving-focus": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-0.1.4.tgz", - "integrity": "sha512-zaixcAxRcWQliUSx6l9rdfJhvcbuY7Tb4Emb7H4DWCTx1kenXH8+n9mwa8gaSIJLLSSSMzBpQATlpFw9xv/bJQ==", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-0.1.5.tgz", + "integrity": "sha512-ClwKPS5JZE+PaHCoW7eu1onvE61pDv4kO8W4t5Ra3qMFQiTJLZMdpBQUhksN//DaVygoLirz4Samdr5Y1x1FSA==", "requires": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "0.1.0", - "@radix-ui/react-collection": "0.1.3", + "@radix-ui/react-collection": "0.1.4", "@radix-ui/react-compose-refs": "0.1.0", "@radix-ui/react-context": "0.1.1", - "@radix-ui/react-id": "0.1.4", - "@radix-ui/react-primitive": "0.1.3", + "@radix-ui/react-id": "0.1.5", + "@radix-ui/react-primitive": "0.1.4", "@radix-ui/react-use-callback-ref": "0.1.0", "@radix-ui/react-use-controllable-state": "0.1.0" + }, + "dependencies": { + "@radix-ui/react-id": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-0.1.5.tgz", + "integrity": "sha512-IPc4H/63bes0IZ1GJJozSEkSWcDyhNGtKFWUpJ+XtaLyQ1X3x7Mf6fWwWhDcpqlYEP+5WtAvfqcyEsyjP+ZhBQ==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "0.1.0" + } + }, + "@radix-ui/react-primitive": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz", + "integrity": "sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "0.1.2" + } + } } }, "@radix-ui/react-slot": { @@ -9784,14 +10019,6 @@ "@babel/runtime": "^7.13.10", "@radix-ui/react-slot": "0.1.2" } - }, - "@radix-ui/react-use-size": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-0.1.1.tgz", - "integrity": "sha512-pTgWM5qKBu6C7kfKxrKPoBI2zZYZmp2cSXzpUiGM3qEBQlMLtYhaY2JXdXUCxz+XmD1YEjc8oRwvyfsD4AG4WA==", - "requires": { - "@babel/runtime": "^7.13.10" - } } } }, @@ -9831,27 +10058,6 @@ "@radix-ui/react-use-controllable-state": "0.1.0" }, "dependencies": { - "@radix-ui/react-collection": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-0.1.4.tgz", - "integrity": "sha512-3muGI15IdgaDFjOcO7xX8a35HQRBRF6LH9pS6UCeZeRmbslkVeHyJRQr2rzICBUoX7zgIA0kXyMDbpQnJGyJTA==", - "requires": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "0.1.0", - "@radix-ui/react-context": "0.1.1", - "@radix-ui/react-primitive": "0.1.4", - "@radix-ui/react-slot": "0.1.2" - } - }, - "@radix-ui/react-id": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-0.1.5.tgz", - "integrity": "sha512-IPc4H/63bes0IZ1GJJozSEkSWcDyhNGtKFWUpJ+XtaLyQ1X3x7Mf6fWwWhDcpqlYEP+5WtAvfqcyEsyjP+ZhBQ==", - "requires": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-use-layout-effect": "0.1.0" - } - }, "@radix-ui/react-primitive": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz", @@ -9860,22 +10066,6 @@ "@babel/runtime": "^7.13.10", "@radix-ui/react-slot": "0.1.2" } - }, - "@radix-ui/react-roving-focus": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-0.1.5.tgz", - "integrity": "sha512-ClwKPS5JZE+PaHCoW7eu1onvE61pDv4kO8W4t5Ra3qMFQiTJLZMdpBQUhksN//DaVygoLirz4Samdr5Y1x1FSA==", - "requires": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "0.1.0", - "@radix-ui/react-collection": "0.1.4", - "@radix-ui/react-compose-refs": "0.1.0", - "@radix-ui/react-context": "0.1.1", - "@radix-ui/react-id": "0.1.5", - "@radix-ui/react-primitive": "0.1.4", - "@radix-ui/react-use-callback-ref": "0.1.0", - "@radix-ui/react-use-controllable-state": "0.1.0" - } } } }, @@ -9948,9 +10138,9 @@ } }, "@radix-ui/react-use-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-0.1.0.tgz", - "integrity": "sha512-TcZAsR+BYI46w/RbaSFCRACl+Jh6mDqhu6GS2r0iuJpIVrj8atff7qtTjmMmfGtEDNEjhl7DxN3pr1nTS/oruQ==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-0.1.1.tgz", + "integrity": "sha512-pTgWM5qKBu6C7kfKxrKPoBI2zZYZmp2cSXzpUiGM3qEBQlMLtYhaY2JXdXUCxz+XmD1YEjc8oRwvyfsD4AG4WA==", "requires": { "@babel/runtime": "^7.13.10" } @@ -10189,6 +10379,15 @@ "@types/react": "*" } }, + "@types/react-infinite-scroller": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/react-infinite-scroller/-/react-infinite-scroller-1.2.2.tgz", + "integrity": "sha512-3Tu/wspMKAOH/YkGmTrXgfYizL9DnMb4opksrl+m5jiESxGkRN4tiKf6lr7SN0FUgoFyQyK9o+yMKn1bWMTVmA==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/react-linkify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/react-linkify/-/react-linkify-1.0.1.tgz", @@ -12685,6 +12884,22 @@ "html-parse-stringify": "^3.0.1" } }, + "react-infinite-scroll-component": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-infinite-scroll-component/-/react-infinite-scroll-component-6.1.0.tgz", + "integrity": "sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==", + "requires": { + "throttle-debounce": "^2.1.0" + } + }, + "react-infinite-scroller": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/react-infinite-scroller/-/react-infinite-scroller-1.2.5.tgz", + "integrity": "sha512-2A+SFUliZhVcxr4R2kFBrW/naGSluNMLqT6wfgmXKCggN1u/H4AW7flBLWHcY/5n/KviVLnpQfaMfBb/pG/m7g==", + "requires": { + "prop-types": "^15.5.8" + } + }, "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -13170,6 +13385,11 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "throttle-debounce": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz", + "integrity": "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==" + }, "tlds": { "version": "1.230.0", "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.230.0.tgz", diff --git a/package.json b/package.json index 38659180..ce032969 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "dependencies": { "@radix-ui/react-alert-dialog": "^0.1.5", "@radix-ui/react-dialog": "^0.1.5", - "@radix-ui/react-dropdown-menu": "^0.1.4", + "@radix-ui/react-dropdown-menu": "^0.1.6", "@radix-ui/react-hover-card": "^0.1.5", "@radix-ui/react-label": "^0.1.4", "@radix-ui/react-switch": "^0.1.5", @@ -36,6 +36,8 @@ "react-cookie": "^4.1.1", "react-dom": "^17.0.2", "react-i18next": "^11.15.5", + "react-infinite-scroll-component": "^6.1.0", + "react-infinite-scroller": "^1.2.5", "react-linkify": "^1.0.0-alpha", "react-scroll": "^1.8.5", "sass": "^1.49.0", @@ -47,6 +49,7 @@ "@types/node": "17.0.11", "@types/react": "17.0.38", "@types/react-dom": "^17.0.11", + "@types/react-infinite-scroller": "^1.2.2", "@types/react-linkify": "^1.0.1", "@types/react-scroll": "^1.8.3", "eslint": "8.7.0", diff --git a/public/icons/Check.svg b/public/icons/Check.svg new file mode 100644 index 00000000..c7a39629 --- /dev/null +++ b/public/icons/Check.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 1fb29437..e03564e6 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -17,6 +17,18 @@ "new": "New", "wiki": "View more on gbf.wiki" }, + "filters": { + "labels": { + "element": "Element", + "series": "Series", + "proficiency": "Proficiency", + "rarity": "Rarity" + } + }, + "rarities": { + "sr": "SR", + "ssr": "SSR" + }, "elements": { "null": "Null", "wind": "Wind", @@ -36,6 +48,44 @@ "light": "Light" } }, + "proficiencies": { + "sabre": "Sabre", + "dagger": "Dagger", + "spear": "Spear", + "axe": "Axe", + "staff": "Staff", + "gun": "Gun", + "melee": "Melee", + "bow": "Bow", + "harp": "Harp", + "katana": "Katana" + }, + "series": { + "seraphic": "Seraphic", + "grand": "Grand", + "opus": "Dark Opus", + "draconic": "Draconic", + "primal": "Primal", + "olden_primal": "Olden Primal", + "beast": "Beast", + "omega": "Omega", + "militis": "Militis", + "xeno": "Xeno", + "astral": "Astral", + "rose": "Rose", + "hollowsky": "Hollowsky", + "ultima": "Ultima", + "bahamut": "Bahamut", + "epic": "Epic", + "ennead": "Ennead", + "cosmos": "Cosmos", + "ancestral": "Ancestral", + "superlative": "Superlative", + "vintage": "Vintage", + "class_champion": "Class Champion", + "sephira": "Sephira", + "new_world": "New World Foundation" + }, "recency": { "all_time": "All time", "last_day": "Last day", @@ -158,10 +208,12 @@ "not_found": "You haven't saved any teams" }, "search": { + "result_count": "{{record_count}} results", "errors": { "start_typing": "Start typing the name of a {{object}}", "min_length": "Type at least 3 characters", - "no_results": "No results found for '{{query}}'" + "no_results": "No results found for '{{query}}'", + "end_results": "No more results" }, "placeholders": { "weapon": "Search for a weapon...", diff --git a/public/locales/ja/common.json b/public/locales/ja/common.json index 721ee4f8..baf3cf3f 100644 --- a/public/locales/ja/common.json +++ b/public/locales/ja/common.json @@ -17,6 +17,18 @@ "new": "作成", "wiki": "gbf.wikiで詳しく見る" }, + "filters": { + "labels": { + "element": "属性", + "series": "シリーズ", + "proficiency": "武器種", + "rarity": "レアリティ" + } + }, + "rarities": { + "sr": "SR", + "ssr": "SSR" + }, "elements": { "null": "無", "wind": "風", @@ -36,6 +48,44 @@ "light": "光属性" } }, + "proficiencies": { + "sabre": "剣", + "dagger": "短剣", + "spear": "槍", + "axe": "斧", + "staff": "杖", + "gun": "銃", + "melee": "拳", + "bow": "弓", + "harp": "琴", + "katana": "刀" + }, + "series": { + "seraphic": "セラフィックウェポン", + "grand": "リミテッドシリーズ", + "opus": "終末の神器", + "draconic": "ドラコニックウェポン", + "primal": "プライマルシリーズ", + "olden_primal": "オールド・プライマルシリーズ", + "beast": "四象武器", + "omega": "マグナシリーズ", + "militis": "ミーレスシリーズ", + "xeno": "六道武器", + "astral": "アストラルウェポン", + "rose": "ローズシリーズ", + "hollowsky": "虚ろなる神器", + "ultima": "オメガウェポン", + "bahamut": "バハムートウェポン", + "epic": "エピックウェポン", + "ennead": "エニアドシリーズ", + "cosmos": "コスモスシリーズ", + "ancestral": "アンセスタルシリーズ", + "superlative": "スペリオシリーズ", + "vintage": "ヴィンテージシリーズ", + "class_champion": "英雄武器", + "sephira": "セフィラン・オールドウェポン", + "new_world": "新世界の礎" + }, "recency": { "all_time": "全ての期間", "last_day": "1日", @@ -159,10 +209,12 @@ "not_found": "編成はまだ保存していません" }, "search": { + "result_count": "{{record_count}}件", "errors": { "start_typing": "{{object}}名を入力してください", "min_length": "3文字以上を入力してください", - "no_results": "'{{query}}'の検索結果が見つかりませんでした" + "no_results": "'{{query}}'の検索結果が見つかりませんでした", + "end_results": "検索結果これ以上ありません" }, "placeholders": { "weapon": "武器を検索...", diff --git a/styles/globals.scss b/styles/globals.scss index 5f7e84fa..23837dbf 100644 --- a/styles/globals.scss +++ b/styles/globals.scss @@ -327,6 +327,16 @@ i.tag { text-transform: uppercase; } +.infinite-scroll-component { + overflow: hidden !important; +} + +.SearchFilterBar { + display: flex; + gap: $unit; + padding: 0 ($unit * 3); +} + @keyframes openModal { 0% { opacity: 0; diff --git a/types/CheckedState.d.ts b/types/CheckedState.d.ts new file mode 100644 index 00000000..9799ce7c --- /dev/null +++ b/types/CheckedState.d.ts @@ -0,0 +1,4 @@ +interface CheckedState { + id: number + checked: boolean +} \ No newline at end of file diff --git a/types/ElementState.d.ts b/types/ElementState.d.ts new file mode 100644 index 00000000..20628908 --- /dev/null +++ b/types/ElementState.d.ts @@ -0,0 +1,10 @@ +interface ElementState { + [key: string]: CheckedState + null: CheckedState + wind: CheckedState + fire: CheckedState + water: CheckedState + earth: CheckedState + dark: CheckedState + light: CheckedState +} \ No newline at end of file diff --git a/types/ProficiencyState.d.ts b/types/ProficiencyState.d.ts new file mode 100644 index 00000000..d694dd10 --- /dev/null +++ b/types/ProficiencyState.d.ts @@ -0,0 +1,13 @@ +interface ProficiencyState { + [key: string]: CheckedState + sabre: CheckedState + dagger: CheckedState + spear: CheckedState + axe: CheckedState + staff: CheckedState + melee: CheckedState + gun: CheckedState + bow: CheckedState + harp: CheckedState + katana: CheckedState +} \ No newline at end of file diff --git a/types/RarityState.d.ts b/types/RarityState.d.ts new file mode 100644 index 00000000..a5dd2593 --- /dev/null +++ b/types/RarityState.d.ts @@ -0,0 +1,5 @@ +interface RarityState { + [key: string]: CheckedState + sr: CheckedState + ssr: CheckedState +} \ No newline at end of file diff --git a/types/WeaponSeries.d.ts b/types/WeaponSeries.d.ts new file mode 100644 index 00000000..14bd1041 --- /dev/null +++ b/types/WeaponSeries.d.ts @@ -0,0 +1,27 @@ +interface WeaponSeriesState { + [key: string]: CheckedState + seraphic: CheckedState + grand: CheckedState + opus: CheckedState + draconic: CheckedState + ultima: CheckedState + bahamut: CheckedState + omega: CheckedState + primal: CheckedState + olden_primal: CheckedState + militis: CheckedState + beast: CheckedState + rose: CheckedState + xeno: CheckedState + hollowsky: CheckedState + astral: CheckedState + epic: CheckedState + ennead: CheckedState + cosmos: CheckedState + ancestral: CheckedState + superlative: CheckedState + vintage: CheckedState + class_champion: CheckedState + sephira: CheckedState + new_world: CheckedState +} \ No newline at end of file diff --git a/utils/api.tsx b/utils/api.tsx index 4367f88a..a6f66471 100644 --- a/utils/api.tsx +++ b/utils/api.tsx @@ -55,12 +55,17 @@ class Api { return axios.post(`${ oauthUrl }/token`, object) } - search(object: string, query: string, excludes: string, locale: string = 'en') { + search({ object, query, filters, locale = "en", page = 0 }: + { object: string, query: string, filters?: { [key: string]: number[] }, locale?: string, page?: number }) { const resourceUrl = `${this.url}/${name}` - const url = (excludes.length > 0) ? - `${resourceUrl}search/${object}?query=${query}&locale=${locale}&excludes=${excludes}` : - `${resourceUrl}search/${object}?query=${query}&locale=${locale}` - return axios.get(url) + return axios.post(`${resourceUrl}search/${object}`, { + search: { + query: query, + filters: filters, + locale: locale, + page: page + } + }) } check(resource: string, value: string) { diff --git a/utils/emptyStates.tsx b/utils/emptyStates.tsx new file mode 100644 index 00000000..4096fd44 --- /dev/null +++ b/utils/emptyStates.tsx @@ -0,0 +1,187 @@ +export const emptyRarityState: RarityState = { + sr: { + id: 2, + checked: false + }, + ssr: { + id: 3, + checked: true + } +} + +export const emptyElementState: ElementState = { + null: { + id: 0, + checked: false + }, + wind: { + id: 1, + checked: false + }, + fire: { + id: 2, + checked: false + }, + water: { + id: 3, + checked: false + }, + earth: { + id: 4, + checked: false + }, + dark: { + id: 5, + checked: false + }, + light: { + id: 6, + checked: false + } +} + +export const emptyProficiencyState: ProficiencyState = { + sabre: { + id: 1, + checked: false + }, + dagger: { + id: 2, + checked: false + }, + axe: { + id: 3, + checked: false + }, + spear: { + id: 4, + checked: false + }, + bow: { + id: 5, + checked: false + }, + staff: { + id: 6, + checked: false + }, + melee: { + id: 7, + checked: false + }, + harp: { + id: 8, + checked: false + }, + gun: { + id: 9, + checked: false + }, + katana: { + id: 10, + checked: false + } +} + +export const emptyWeaponSeriesState: WeaponSeriesState = { + seraphic: { + id: 0, + checked: false + }, + grand: { + id: 1, + checked: false + }, + opus: { + id: 2, + checked: false + }, + draconic: { + id: 3, + checked: false + }, + ultima: { + id: 17, + checked: false + }, + bahamut: { + id: 16, + checked: false + }, + regalia: { + id: 8, + checked: false + }, + omega: { + id: 9, + checked: false + }, + primal: { + id: 6, + checked: false + }, + olden_primal: { + id: 10, + checked: false + }, + militis: { + id: 11, + checked: false + }, + beast: { + id: 7, + checked: false + }, + rose: { + id: 15, + checked: false + }, + xeno: { + id: 13, + checked: false + }, + hollowsky: { + id: 12, + checked: false + }, + astral: { + id: 14, + checked: false + }, + epic: { + id: 18, + checked: false + }, + ennead: { + id: 19, + checked: false + }, + cosmos: { + id: 20, + checked: false + }, + ancestral: { + id: 21, + checked: false + }, + superlative: { + id: 22, + checked: false + }, + vintage: { + id: 23, + checked: false + }, + class_champion: { + id: 24, + checked: false + }, + sephira: { + id: 28, + checked: false + }, + new_world: { + id: 29, + checked: false + } +} \ No newline at end of file diff --git a/utils/stateValues.tsx b/utils/stateValues.tsx new file mode 100644 index 00000000..f74aac0c --- /dev/null +++ b/utils/stateValues.tsx @@ -0,0 +1,16 @@ +export const rarities = ["sr", "ssr"] + +export const elements = ["null", "wind", "fire", "water", "earth", "dark", "light"] + +export const proficiencies = [ + "sabre", "dagger", "spear", "axe", "staff", + "melee", "gun", "bow", "harp", "katana" +] + +export const weaponSeries = [ + "seraphic", "grand", "opus", "draconic", "ultima", + "bahamut", "omega", "primal", "olden_primal", "militis", + "beast", "rose", "xeno", "hollowsky", "astral", + "epic", "ennead", "cosmos", "ancestral", "superlative", + "vintage", "class_champion", "sephira", "new_world" +] \ No newline at end of file