diff --git a/common/components/Search.svelte b/common/components/Search.svelte index f5d3175..a920814 100644 --- a/common/components/Search.svelte +++ b/common/components/Search.svelte @@ -3,9 +3,9 @@ const badgeDisplayNames = { title: 'List:', search: 'Title:', genre: 'Genre:', tag: 'Tag:', season: 'Season:', year: 'Year:', format: 'Format:', status: 'Status:', sort: 'Sort:', hideMyAnime: 'Hide My Anime'} const sortOptions = { START_DATE_DESC: 'Release Date', SCORE_DESC: 'Score', POPULARITY_DESC: 'Popularity', TRENDING_DESC: 'Trending', UPDATED_TIME_DESC: 'Last Updated', STARTED_ON_DESC: 'Started On', FINISHED_ON_DESC: 'Finished On', PROGRESS_DESC: 'Your Progress', USER_SCORE_DESC: 'Your Score' } - export function searchCleanup (search) { + export function searchCleanup (search, badge) { return Object.fromEntries(Object.entries(search).map((entry) => { - return badgeKeys.includes(entry[0]) && entry + return (!badge || badgeKeys.includes(entry[0])) && entry }).filter(a => a?.[1])) } @@ -26,32 +26,6 @@ } let form - const tagList = [ - 'Boys\' Love', - 'Demons', - 'Yuri', - 'Food', - 'Isekai', - 'Iyashikei', - 'Josei', - 'Magic', - 'Martial Arts', - 'Military', - 'Parody', - 'Female Harem', - 'Male Harem', - 'Mixed Gender Harem', - 'Parody', - 'School', - 'Seinen', - 'Shoujo', - 'Shounen', - 'Space', - 'Super Power', - 'Vampire', - 'Kids' - ] - const genreList = [ 'Action', 'Adventure', @@ -73,7 +47,182 @@ 'Thriller' ] - $: sanitisedSearch = Object.entries(searchCleanup(search)).flatMap( + const tagList = [ + 'Chuunibyou', + 'Demons', + 'Food', + 'Heterosexual', + 'Isekai', + 'Iyashikei', + 'Josei', + 'Magic', + 'Yuri', + 'Love Triangle', + 'Female Harem', + 'Male Harem', + 'Mixed Gender Harem', + 'Arranged Marriage', + 'Marriage', + 'Martial Arts', + 'Military', + 'Nudity', + 'Parody', + 'Reincarnation', + 'Satire', + 'School', + 'Seinen', + 'Shoujo', + 'Shounen', + 'Slavery', + 'Space', + 'Super Power', + 'Superhero', + 'Teens\' Love', + 'Unrequited Love', + 'Vampire', + 'Kids', + 'Gender Bending', + 'Body Swapping', + 'Boys\' Love', + 'Cute Boys Doing Cute Things', + 'Cute Girls Doing Cute Things', + 'Acting', + 'Afterlife', + 'Age Gap', + 'Age Regression', + 'Aliens', + 'Alternate Universe', + 'Amnesia', + 'Angels', + 'Anti-Hero', + 'Archery', + 'Artificial Intelligence', + 'Assassins', + 'Asexual', + 'Augmented Reality', + 'Band', + 'Bar', + 'Battle Royale', + 'Board Game', + 'Boarding School', + 'Bullying', + 'Calligraphy', + 'CGI', + 'Classic Literature', + 'College', + 'Cosplay', + 'Crime', + 'Crossdressing', + 'Cult', + 'Dancing', + 'Death Game', + 'Desert', + 'Disability', + 'Drawing', + 'Dragons', + 'Dungeon', + 'Elf', + 'Espionage', + 'Fairy', + 'Femboy', + 'Female Protagonist', + 'Fashion', + 'Foreign', + 'Full CGI', + 'Fugitive', + 'Gambling', + 'Ghost', + 'Gods', + 'Goblin', + 'Guns', + 'Gyaru', + 'Hikikomori', + 'Historical', + 'Homeless', + 'Idol', + 'Inn', + 'Kaiju', + 'Konbini', + 'Kuudere', + 'Language Barrier', + 'Makeup', + 'Maids', + 'Male Protagonist', + 'Matriarchy', + 'Matchmaking', + 'Mermaid', + 'Monster Boy', + 'Monster Girl', + 'Natural Disaster', + 'Necromancy', + 'Ninja', + 'Nun', + 'Office', + 'Office Lady', + 'Omegaverse', + 'Orphan', + 'Outdoor', + 'Photography', + 'Pirates', + 'Polyamorous', + 'Post-Apocalyptic', + 'Primarily Adult Cast', + 'Primarily Female Cast', + 'Primarily Male Cast', + 'Primarily Teen Cast', + 'Prison', + 'Rakugo', + 'Restaurant', + 'Robots', + 'Rural', + 'Samurai', + 'School Club', + 'Shapeshifting', + 'Shrine Maiden', + 'Skeleton', + 'Slapstick', + 'Snowscape', + 'Space', + 'Spearplay', + 'Succubus', + 'Surreal Comedy', + 'Survival', + 'Swordplay', + 'Teacher', + 'Time Loop', + 'Time Manipulation', + 'Time Skip', + 'Transgender', + 'Tsundere', + 'Twins', + 'Urban', + 'Urban Fantasy', + 'Video Games', + 'Villainess', + 'Virtual World', + 'VTuber', + 'War', + 'Werewolf', + 'Witch', + 'Work', + 'Writing', + 'Wuxia', + 'Yakuza', + 'Yandere', + 'Youkai', + 'Zombie' + ] + let filteredTags = [] + + $: { + const searchInput = (searchTextInput.tag ? searchTextInput.tag.toLowerCase() : null) + filteredTags = tagList.filter(tag => + (!search.tag || !search.tag.includes(tag)) && (!searchInput || + tag.toLowerCase().includes(searchInput)) + ).slice(0, 20) + } + + $: sanitisedSearch = Object.entries(searchCleanup(search, true)).flatMap( ([key, value]) => { if (Array.isArray(value)) { return value.map((item) => ({ key, value: item })) @@ -117,7 +266,9 @@ delete search.userList delete search.continueWatching delete search.completedList - search.sort = '' + if (Helper.isUserSort(search)) { + search.sort = '' + } } else if ((badge.key === 'genre' || badge.key === 'tag') && !search.userList) { delete search.title } else if (badge.key === 'hideMyAnime') { @@ -138,17 +289,24 @@ function toggleHideMyAnime() { search.hideMyAnime = !search.hideMyAnime - search.hideStatus = search.hideMyAnime ? ['CURRENT', 'PLANNING', 'COMPLETED', 'DROPPED', 'PAUSED', 'REPEATING'] : '' + search.hideStatus = search.hideMyAnime ? ['CURRENT', 'COMPLETED', 'DROPPED', 'PAUSED', 'REPEATING'] : '' form.dispatchEvent(new Event('input', { bubbles: true })) } - function filterList(event, type) { const list = type === 'tag' ? tagList : genreList const searchKey = type === 'tag' ? 'tag' : 'genre' - const selectedValue = event.target.value - if (list.includes(selectedValue) && (!search[searchKey] || !search[searchKey].includes(selectedValue))) { - search[searchKey] = search[searchKey] ? [...search[searchKey], selectedValue] : [selectedValue] + const inputValue = event.target.value + let bestMatch = list.find(item => item.toLowerCase() === inputValue.toLowerCase()) + if (!bestMatch) { + bestMatch = list.find(item => item.toLowerCase().startsWith(inputValue.toLowerCase())) + } + if (bestMatch && (!search[searchKey] || !search[searchKey].includes(bestMatch))) { + search[searchKey] = search[searchKey] ? [...search[searchKey], bestMatch] : [bestMatch] searchTextInput[searchKey] = null + form.dispatchEvent(new Event('input', { bubbles: true })) + } + } + function clearTags() { // cannot specify genre and tag filtering with user specific sorting options when using alternative authentication. if (!Helper.isAniAuth() && Helper.isUserSort(search)) { search.genre = '' @@ -205,11 +363,13 @@
filterList(event, 'genre')} + on:change={(event) => filterTags(event, 'genre')} data-option='search' disabled={search.disableSearch || (!Helper.isAniAuth() && Helper.isUserSort(search))} placeholder='Any' @@ -217,7 +377,9 @@
{#each genreList as genre} - + {#if !search.genre || !search.genre.includes(genre) } + + {/if} {/each} @@ -228,18 +390,20 @@
filterList(event, 'tag')} + on:change={(event) => filterTags(event, 'tag')} data-option='search' disabled={search.disableSearch || (!Helper.isAniAuth() && Helper.isUserSort(search))} placeholder='Any' list='search-tag'/>
- {#each tagList as tag} + {#each filteredTags as tag} {/each} @@ -303,7 +467,7 @@ Sort
- @@ -322,13 +486,15 @@
+ {#if Helper.isAuthorized()}
@@ -337,7 +503,7 @@
-
-
@@ -361,13 +527,11 @@ >sell {#each badgeKeys as key} {#each sanitisedSearch as badge} - {#if badge.key === key} - {#if badge.key !== 'hideStatus' && (search.userList || badge.key !== 'title') } - - {badge.key === 'sort' ? 'Sort: ' : getBadgeDisplayName(badge.key)} {badge.key === 'sort' ? getSortDisplayName(badge.value) : (badge.key !== 'hideMyAnime' ? ('' + badge.value).replace(/_/g, ' ').toLowerCase() : '')} - - - {/if} + {#if badge.key === key && (badge.key !== 'hideStatus' && (search.userList || badge.key !== 'title')) } + + {badge.key === 'sort' ? 'Sort: ' : getBadgeDisplayName(badge.key)} {badge.key === 'sort' ? getSortDisplayName(badge.value) : (badge.key !== 'hideMyAnime' && badge.key !== 'hideSubs' ? ('' + badge.value).replace(/_/g, ' ').toLowerCase() : '')} + + {/if} {/each} {/each} diff --git a/common/views/Search.svelte b/common/views/Search.svelte index c61ab59..700c2ab 100644 --- a/common/views/Search.svelte +++ b/common/views/Search.svelte @@ -27,8 +27,10 @@ $items = [...$items, ...nextData] return nextData[nextData.length - 1].data } - const update = debounce(() => { - $key = {} + const update = debounce((event) => { + if (event.target.id !== 'genre' && event.target.id !== 'tag') { + $key = {} + } }, 300) $: loadTillFull($key)