Added search to tags page.
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
<input
|
||||
v-model="query"
|
||||
type="search"
|
||||
placeholder="Search channel"
|
||||
placeholder="Search channels"
|
||||
class="search input"
|
||||
@search="search"
|
||||
>
|
||||
@@ -118,6 +118,10 @@ async function search() {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.search-container {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
|
||||
@@ -2,8 +2,19 @@
|
||||
<div class="page">
|
||||
<ul
|
||||
ref="categories"
|
||||
class="categories nolist"
|
||||
class="categories nolist nobar"
|
||||
>
|
||||
<li>
|
||||
<div
|
||||
class="search noselect"
|
||||
@click="focusSearch"
|
||||
>
|
||||
<Icon
|
||||
icon="search"
|
||||
/>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li
|
||||
v-for="(tags, category) in showcase"
|
||||
:key="`category-${category}`"
|
||||
@@ -12,7 +23,7 @@
|
||||
:href="`#${category}`"
|
||||
class="category nolink"
|
||||
:class="{ active: activeCategory === category }"
|
||||
>{{ category }}</a>
|
||||
>{{ categoryTitles[category] || category }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -20,6 +31,25 @@
|
||||
ref="content"
|
||||
class="content"
|
||||
>
|
||||
<form
|
||||
class="search-container"
|
||||
@submit.prevent="search"
|
||||
>
|
||||
<input
|
||||
ref="searchInput"
|
||||
v-model="query"
|
||||
type="search"
|
||||
placeholder="Search tags"
|
||||
class="search input"
|
||||
@search="search"
|
||||
>
|
||||
|
||||
<Icon
|
||||
icon="search"
|
||||
@click="search"
|
||||
/>
|
||||
</form>
|
||||
|
||||
<div
|
||||
v-for="(tags, category) in showcase"
|
||||
:key="`tags-${category}`"
|
||||
@@ -41,7 +71,7 @@
|
||||
<div class="thumb-container">
|
||||
<a
|
||||
:href="`/tag/${tag.slug}`"
|
||||
class="tag nolink"
|
||||
class="thumb-link nolink"
|
||||
>
|
||||
<img
|
||||
v-if="tag.poster"
|
||||
@@ -51,6 +81,12 @@
|
||||
class="thumb"
|
||||
loading="lazy"
|
||||
>
|
||||
|
||||
<img
|
||||
v-else
|
||||
src="/img/icons/price-tag2.svg"
|
||||
class="nophoto"
|
||||
>
|
||||
</a>
|
||||
|
||||
<a
|
||||
@@ -80,13 +116,17 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, inject } from 'vue';
|
||||
|
||||
import navigate from '#/src/navigate.js';
|
||||
import events from '#/src/events.js';
|
||||
|
||||
const pageContext = inject('pageContext');
|
||||
const showcase = pageContext.pageProps.tagShowcase;
|
||||
|
||||
const categories = ref(null);
|
||||
const content = ref(null);
|
||||
const searchInput = ref(null);
|
||||
const query = ref(pageContext.urlParsed.search.q);
|
||||
|
||||
const categoryTitles = {
|
||||
lgbt: 'LGBT',
|
||||
@@ -120,15 +160,16 @@ function calculateActiveCategory() {
|
||||
navigate(`#${activeCategory.value}`, null, { replace: true });
|
||||
}
|
||||
|
||||
async function search() {
|
||||
navigate('/tags', { q: query.value || undefined }, { redirect: true });
|
||||
}
|
||||
|
||||
function focusSearch() {
|
||||
events.emit('scrollUp'); // scrollIntoView on search input does not reveal it fully
|
||||
searchInput.value?.focus();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// div doesn't scroll automatically on page load, reset hash to scroll
|
||||
if (window.location.hash) {
|
||||
const hash = window.location.hash;
|
||||
|
||||
window.location.hash = undefined;
|
||||
window.location.hash = hash;
|
||||
}
|
||||
|
||||
categories.value.addEventListener('wheel', (event) => {
|
||||
categories.value.scrollLeft += event.deltaY;
|
||||
});
|
||||
@@ -144,7 +185,15 @@ onMounted(() => {
|
||||
}
|
||||
});
|
||||
|
||||
calculateActiveCategory();
|
||||
// div doesn't scroll automatically on page load, reset hash to scroll
|
||||
if (window.location.hash) {
|
||||
const hash = window.location.hash;
|
||||
|
||||
window.location.hash = undefined;
|
||||
window.location.hash = hash;
|
||||
|
||||
calculateActiveCategory();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -152,6 +201,7 @@ onMounted(() => {
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow:1 ;
|
||||
}
|
||||
|
||||
.content {
|
||||
@@ -162,16 +212,26 @@ onMounted(() => {
|
||||
display: flex;
|
||||
gap: .25rem;
|
||||
flex-shrink: 0;
|
||||
padding: .5rem 1rem;
|
||||
padding: .5rem 1rem .5rem 0;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
background: var(--grey-dark-40);
|
||||
overflow-x: auto;
|
||||
scrollbar-width: none;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
.search {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.icon {
|
||||
fill: var(--highlight-strong-20);
|
||||
padding: 0 .5rem 0 1rem;
|
||||
}
|
||||
|
||||
&:hover .icon {
|
||||
fill: var(--text-light);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,6 +250,27 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.search-container {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
padding: 1rem 1rem 0 1rem;
|
||||
|
||||
.icon {
|
||||
padding: 0 1rem;
|
||||
height: auto;
|
||||
fill: var(--shadow);
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
fill: var(--primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.tags {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
|
||||
@@ -205,6 +286,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.tag {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -220,7 +302,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.name {
|
||||
padding: .25rem .5rem 0 .5rem;
|
||||
padding: .4rem .5rem 0 .5rem;
|
||||
text-transform: capitalize;
|
||||
font-size: .9rem;
|
||||
font-weight: bold;
|
||||
@@ -229,17 +311,31 @@ onMounted(() => {
|
||||
|
||||
.thumb-container {
|
||||
position: relative;
|
||||
aspect-ratio: 5/3;
|
||||
background: var(--background-base-20);
|
||||
box-shadow: 0 0 3px var(--shadow-weak-20);
|
||||
}
|
||||
|
||||
.thumb-link {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.thumb {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
aspect-ratio: 5/3;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: .25rem;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
box-shadow: 0 0 3px var(--shadow-weak-20);
|
||||
}
|
||||
|
||||
.nophoto {
|
||||
width: 10%;
|
||||
opacity: .1;
|
||||
}
|
||||
|
||||
.favicon-link {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { fetchTagsById } from '#/src/tags.js';
|
||||
import { fetchTags, fetchTagsById } from '#/src/tags.js';
|
||||
|
||||
const tagSlugs = {
|
||||
popular: [
|
||||
@@ -116,8 +116,28 @@ const tagSlugs = {
|
||||
],
|
||||
};
|
||||
|
||||
async function searchTags(pageContext) {
|
||||
const tags = await fetchTags({ query: pageContext.urlParsed.search.q });
|
||||
|
||||
return {
|
||||
pageContext: {
|
||||
title: 'Tags',
|
||||
pageProps: {
|
||||
tagShowcase: {
|
||||
results: tags,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export async function onBeforeRender(pageContext) {
|
||||
if (pageContext.urlParsed.search.q) {
|
||||
return searchTags(pageContext);
|
||||
}
|
||||
|
||||
const tags = await fetchTagsById(Object.values(tagSlugs).flat());
|
||||
|
||||
const filteredTags = tags.filter((tag) => !pageContext.tagFilter.includes(tag.name) && !pageContext.tagFilter.includes(tag.slug));
|
||||
const tagsBySlug = Object.fromEntries(filteredTags.map((tag) => [tag.slug, tag]));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user