Added quest (and POC for categories) filter

This commit is contained in:
Alexis
2023-12-09 18:46:23 +01:00
parent 2b28687ff1
commit 67add2baa9
3 changed files with 292 additions and 199 deletions

View File

@@ -19,7 +19,7 @@
} }
strong.title { strong.title {
color: #16a34a; color: var(--green-500);
} }
a.title { a.title {
@@ -28,7 +28,7 @@
&:hover { &:hover {
text-decoration: none; text-decoration: none;
color: #16a34a; color: var(--green-500);
} }
} }

View File

@@ -4,6 +4,8 @@
@use 'leaflet'; @use 'leaflet';
:root { :root {
--white: #fff;
--black: #111;
--slate-50: #f8fafc; --slate-50: #f8fafc;
--slate-100: #f1f5f9; --slate-100: #f1f5f9;
--slate-200: #e2e8f0; --slate-200: #e2e8f0;
@@ -16,6 +18,8 @@
--slate-900: #0f172a; --slate-900: #0f172a;
--slate-950: #020617; --slate-950: #020617;
--red-500: #dc2626; --red-500: #dc2626;
--red-700: #b60909;
--green-500: #16a34a;
} }
html { html {

View File

@@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import type { MapMarker, PlayerMarker } from '@/types/Leaflet'; import type { MapMarker, MapMarkerGroup, PlayerMarker } from '@/types/Leaflet';
import { useFocus, useMagicKeys, whenever } from '@vueuse/core'; import { useFocus, useMagicKeys, whenever } from '@vueuse/core';
import { computed, onMounted, ref, onUpdated } from 'vue'; import { computed, onMounted, ref, onUpdated, watch } from 'vue';
const props = defineProps<{ const props = defineProps<{
markers: MapMarker[], markers: MapMarker[],
@@ -18,13 +18,14 @@ onMounted(() => {
isFocused.value = true isFocused.value = true
}) })
const shouldBeActive = computed(() => q.value.length > 0) const shouldBeActive = computed(() => q.value.length > 0 || currentSearchMode.value !== "query")
const q = ref<string>("") const q = ref<string>("")
const unifier = new RegExp(/[^a-zA-Z0-9\-\'']/g) const unifier = new RegExp(/[^a-zA-Z0-9\-\'']/g)
const filteredMarkers = computed(() => { const filteredMarkers = computed(() => {
if (currentSearchMode.value === "query") {
return markers?.filter(m => { return markers?.filter(m => {
const queryString = new String(q.value).replace(unifier, "").toLocaleLowerCase() const queryString = new String(q.value).replace(unifier, "").toLocaleLowerCase()
const hitTitle = m.title.replace(unifier, "").toLocaleLowerCase().includes(queryString) const hitTitle = m.title.replace(unifier, "").toLocaleLowerCase().includes(queryString)
@@ -32,6 +33,11 @@ const filteredMarkers = computed(() => {
return hitTitle || hitDesc return hitTitle || hitDesc
}) })
}
return markers?.filter(m => {
return m.group === currentSearchMode.value
})
}) })
// Key Combos // Key Combos
@@ -43,10 +49,14 @@ whenever(shortcutKeyCombo, () => {
isFocused.value = true isFocused.value = true
}) })
whenever(eraseKeyCombo, () => { whenever(eraseKeyCombo, () => {
q.value = "" resetQueryValue()
isFocused.value = true isFocused.value = true
}) })
watch(q, (n, o) => {
if (n) setSearchMode('query');
})
/** /**
* Player geolocation * Player geolocation
* Uses native JS to avoid changing leaflet library * Uses native JS to avoid changing leaflet library
@@ -77,9 +87,32 @@ onUpdated(() => {
btn.addEventListener('click', () => btn.dispatchEvent(flyToMarker)) btn.addEventListener('click', () => btn.dispatchEvent(flyToMarker))
}) })
}) })
type SearchMode = "query" | MapMarkerGroup;
const currentSearchMode = ref<SearchMode>('query');
const currentLimit = computed(() => {
if (currentSearchMode.value === "query") return 10
return 20;
})
function setSearchMode(m: SearchMode) {
currentSearchMode.value = m;
}
function setActiveCategory(g: MapMarkerGroup) {
resetQueryValue()
currentSearchMode.value = g;
}
function resetQueryValue() {
q.value = "";
}
</script> </script>
<template> <template>
<nav class="toolbar">
<div ref="searchBar" class="search-w" :data-focused="shouldBeActive"> <div ref="searchBar" class="search-w" :data-focused="shouldBeActive">
<div class="input-w"> <div class="input-w">
<i class="search-icon ph-fill ph-magnifying-glass"></i> <i class="search-icon ph-fill ph-magnifying-glass"></i>
@@ -91,7 +124,7 @@ onUpdated(() => {
</div> </div>
<ul class="search-results" v-if="shouldBeActive"> <ul class="search-results" v-if="shouldBeActive">
<li v-for="m in filteredMarkers?.slice(0, 10)" :key="m.title"> <li v-for="m in filteredMarkers?.slice(0, currentLimit)" :key="m.title">
<button <button
class="search-item" class="search-item"
:class="`group-${m.group}`" :class="`group-${m.group}`"
@@ -110,14 +143,32 @@ onUpdated(() => {
</li> </li>
</ul> </ul>
</div> </div>
<menu class="tag-list">
<li>
<button @click="setActiveCategory('quests')">
<span class="icon">
<i class="ph-fill ph-flag-banner"></i>
</span>
<span class="label">
Quêtes
</span>
</button>
</li>
</menu>
</nav>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.search-w { .toolbar {
margin-bottom: 1em; display: flex;
gap: 1.5rem;
align-items: start;
.search-w {
padding: .5rem 1.2rem; padding: .5rem 1.2rem;
width: calc(100% - 3rem); width: calc(100% - 3rem);
background: #fff; background: var(--white);
border: 1px solid var(--slate-400); border: 1px solid var(--slate-400);
border-radius: 25px; border-radius: 25px;
box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px; box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;
@@ -160,7 +211,7 @@ onUpdated(() => {
aspect-ratio: 1 / 1; aspect-ratio: 1 / 1;
line-height: 1; line-height: 1;
font-size: 1.5em; font-size: 1.5em;
color: #dc2626; color: var(--red-500);
border-radius: 50%; border-radius: 50%;
cursor: pointer; cursor: pointer;
@@ -175,7 +226,7 @@ onUpdated(() => {
outline-offset: -.2rem; outline-offset: -.2rem;
transition-property: background-color; transition-property: background-color;
transition-duration: .2s; transition-duration: .2s;
transition-timing-function: ease-in-out; transition-timing-function: cubic-bezier(0.445, 0.05, 0.55, 0.95);
} }
&:hover { &:hover {
@@ -241,7 +292,7 @@ onUpdated(() => {
text-decoration: underline; text-decoration: underline;
&:hover { &:hover {
color: #16a34a; color: var(--green-500);
} }
} }
} }
@@ -291,6 +342,7 @@ onUpdated(() => {
} }
&[data-focused="true"] { &[data-focused="true"] {
margin-bottom: 1em;
.input-w { .input-w {
border-bottom: 1px solid var(--slate-200); border-bottom: 1px solid var(--slate-200);
margin-bottom: .5rem; margin-bottom: .5rem;
@@ -301,11 +353,48 @@ onUpdated(() => {
} }
} }
} }
} }
@media screen and (width >= 900px) { @media screen and (width >= 900px) {
.search-w { .search-w {
width: 29%; width: 29%;
} }
}
/**
* TAG LIST
*/
.tag-list {
margin-top: .5rem;
button {
display: inline-flex;
align-items: center;
gap: .5ch;
padding-block: .25rem;
padding-inline: .8rem;
font-weight: 600;
font-size: .85em;
background: var(--white);
border: 1px solid var(--slate-400);
border-radius: 100vmax;
box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;
pointer-events: all;
cursor: pointer;
transition-property: color, background-color, border-color;
transition-duration: .15s;
transition-timing-function: cubic-bezier(0.445, 0.05, 0.55, 0.95);
.icon {
font-size: 1.1em;
}
&:hover {
color: var(--white);
background-color: var(--red-500);
border-color: var(--red-700);
}
}
}
} }
</style> </style>