Added search suggestions
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { get } from 'svelte/store';
|
||||
import { invidiousInstance, returnYTDislikesInstance } from '../../store';
|
||||
import type { Channel, Comments, ReturnYTDislikes, Video, VideoPlay } from './model';
|
||||
import type { Channel, Comments, ReturnYTDislikes, SearchSuggestion, Video, VideoPlay } from './model';
|
||||
|
||||
export function buildPath(path: string): string {
|
||||
return `${get(invidiousInstance)}/api/v1/${path}`;
|
||||
@@ -31,4 +31,11 @@ export async function getComments(videoId: string, parameters: { sortBy: "top" |
|
||||
export async function getChannel(channelId: string): Promise<Channel> {
|
||||
const resp = await fetch(buildPath(`channels/${channelId}`));
|
||||
return await resp.json();
|
||||
}
|
||||
|
||||
export async function getSearchSuggestions(search: string): Promise<SearchSuggestion> {
|
||||
const path = new URL(buildPath("search/suggestions"));
|
||||
path.search = new URLSearchParams({ q: search }).toString();
|
||||
const resp = await fetch(path);
|
||||
return await resp.json();
|
||||
}
|
||||
@@ -149,4 +149,9 @@ export interface Channel {
|
||||
allowedRegions: string[];
|
||||
tabs: string[];
|
||||
latestVideos: Video[];
|
||||
}
|
||||
|
||||
export interface SearchSuggestion {
|
||||
query: string;
|
||||
suggestions: string[];
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { getSearchSuggestions } from '$lib/Api/index';
|
||||
import Logo from '$lib/Logo.svelte';
|
||||
import 'beercss';
|
||||
import 'material-dynamic-colors';
|
||||
@@ -7,6 +8,7 @@
|
||||
import {
|
||||
activePage,
|
||||
darkMode,
|
||||
interfaceSearchSuggestions,
|
||||
playerAlwaysLoop,
|
||||
playerAutoPlay,
|
||||
playerDash,
|
||||
@@ -33,6 +35,21 @@
|
||||
playerDash.subscribe((value) => (dash = value));
|
||||
playerListenByDefault.subscribe((value) => (listenByDefault = value));
|
||||
|
||||
let searchSuggestions = false;
|
||||
interfaceSearchSuggestions.subscribe((value) => (searchSuggestions = value));
|
||||
|
||||
let suggestionsForSearch: string[] = [];
|
||||
|
||||
let debounceTimer = 0;
|
||||
const debouncedSearch = (event: any) => {
|
||||
if (!searchSuggestions) return;
|
||||
|
||||
clearTimeout(debounceTimer);
|
||||
debounceTimer = setTimeout(async () => {
|
||||
suggestionsForSearch = (await getSearchSuggestions(event.target.value)).suggestions;
|
||||
}, 250);
|
||||
};
|
||||
|
||||
const pages = [
|
||||
{
|
||||
icon: 'home',
|
||||
@@ -134,7 +151,24 @@
|
||||
|
||||
<div class="max"></div>
|
||||
<div class="max field round suffix prefix small no-margin m l white black-text">
|
||||
<i class="front">search</i><input type="text" placeholder="Search..." />
|
||||
<i class="front">search</i><input
|
||||
data-ui="search-suggestions"
|
||||
type="text"
|
||||
placeholder="Search..."
|
||||
on:keyup={(target) => debouncedSearch(target)}
|
||||
/>
|
||||
{#if searchSuggestions}
|
||||
<menu
|
||||
class="no-wrap"
|
||||
style="width: 100%;"
|
||||
id="search-suggestions"
|
||||
data-ui="#search-suggestions"
|
||||
>
|
||||
{#each suggestionsForSearch as suggestion}
|
||||
<a href={`/search/${suggestion}`}>{suggestion}</a>
|
||||
{/each}
|
||||
</menu>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="max"></div>
|
||||
<button class="circle large transparent" data-ui="#dialog-notifications"
|
||||
@@ -169,6 +203,25 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="settings">
|
||||
<h6>Interface</h6>
|
||||
<div class="field no-margin">
|
||||
<nav class="no-padding">
|
||||
<div class="max">
|
||||
<div>Search suggestions</div>
|
||||
</div>
|
||||
<label class="switch">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={searchSuggestions}
|
||||
on:click={() => interfaceSearchSuggestions.set(!searchSuggestions)}
|
||||
/>
|
||||
<span></span>
|
||||
</label>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings">
|
||||
<h6>Player</h6>
|
||||
<div class="field no-margin">
|
||||
@@ -284,7 +337,11 @@
|
||||
</nav>
|
||||
</header>
|
||||
{#each pages as page}
|
||||
<a class="row round" data-ui="#dialog-expanded" href={page.href}
|
||||
<a
|
||||
class="row round"
|
||||
data-ui="#dialog-expanded"
|
||||
href={page.href}
|
||||
class:active={currentPage === page.name.toLowerCase()}
|
||||
><i>{page.icon}</i>
|
||||
<div>{page.name}</div></a
|
||||
>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { activePage } from '../store';
|
||||
|
||||
activePage.set('home');
|
||||
</script>
|
||||
@@ -14,3 +14,7 @@ export const playerProxyVideos = persisted("proxyVideos", false);
|
||||
export const playerListenByDefault = persisted("listenByDefault", false);
|
||||
export const playerSavePlaybackPosition = persisted("savePlaybackPosition", true);
|
||||
export const playerDash = persisted("dash", true);
|
||||
|
||||
export const interfaceSearchSuggestions = persisted("searchSuggestions", true);
|
||||
|
||||
export const authToken = persisted("authToken", "");
|
||||
Reference in New Issue
Block a user