mirror of
https://github.com/web3privacy/explorer-app.git
synced 2024-10-15 16:46:26 +02:00
feat(explorer): redesign grid header according to v2 design
This commit is contained in:
parent
8b9a1e0071
commit
441bff9017
6 changed files with 187 additions and 69 deletions
|
@ -5,6 +5,7 @@ const props = defineProps<{
|
|||
options: InputOption[]
|
||||
modelValue: string
|
||||
count?: number
|
||||
titleShowCount?: boolean
|
||||
}>()
|
||||
|
||||
const emits = defineEmits(['update:modelValue', 'selected'])
|
||||
|
@ -23,15 +24,18 @@ function onOptionSelected(value: string) {
|
|||
v-model="selectedValue"
|
||||
as="div"
|
||||
>
|
||||
<div class="relative mt-2 font-700 font-24px">
|
||||
<div class="relative font-700 font-24px">
|
||||
<HeadlessListboxButton
|
||||
class="relative w-full cursor-pointer py-8px p-16px text-left border-2px text-app-white sm:text-sm sm:leading-6"
|
||||
class="relative cursor-pointer py-6px px-14px text-left border-2px bg-app-white text-app-black sm:text-sm sm:leading-6"
|
||||
>
|
||||
<span class="block truncate mr-8px">{{ isOptionSelected?.label }} <span opacity-50>({{ isOptionSelected?.count }})</span></span>
|
||||
<span class="block truncate mr-8px font">{{ isOptionSelected?.label }} <span
|
||||
v-if="titleShowCount"
|
||||
opacity-50
|
||||
>({{ isOptionSelected?.count }})</span></span>
|
||||
<span class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
||||
<UnoIcon
|
||||
i-heroicons-solid-chevron-down
|
||||
text-app-white
|
||||
text-app-black
|
||||
/>
|
||||
</span>
|
||||
</HeadlessListboxButton>
|
||||
|
@ -42,7 +46,7 @@ function onOptionSelected(value: string) {
|
|||
leave-to-class="opacity-0"
|
||||
>
|
||||
<HeadlessListboxOptions
|
||||
class="absolute z-100 max-h-60 w-full divide-y-2px border-2px border-t-0 overflow-auto bg-app-black text-app-white focus:outline-none sm:text-sm"
|
||||
class="absolute z-100 max-h-60 w-auto border-2px border-t-0 overflow-auto bg-app-black text-app-white focus:outline-none sm:text-sm"
|
||||
>
|
||||
<HeadlessListboxOption
|
||||
v-for="option in props.options"
|
||||
|
@ -53,15 +57,15 @@ function onOptionSelected(value: string) {
|
|||
@click="onOptionSelected(option.value)"
|
||||
>
|
||||
<li
|
||||
class="w-full relative cursor-pointer select-none py-8px p-16px"
|
||||
:class="[active ? 'bg-#ffffff1a' : 'text-white']"
|
||||
class="w-full relative cursor-pointer select-none py-8px p-16px bg-app-black text-app-white"
|
||||
:class="[active ? 'text-app-white' : 'text-app-white']"
|
||||
>
|
||||
<span
|
||||
class="block truncate"
|
||||
:class="[selected ? 'font-semibold' : 'font-normal']"
|
||||
>
|
||||
{{ option.label }}
|
||||
<span opacity-50>({{ option.count }})</span>
|
||||
<span v-if="titleShowCount" opacity-50>({{ option.count }})</span>
|
||||
</span>
|
||||
</li>
|
||||
</HeadlessListboxOption>
|
||||
|
|
|
@ -11,6 +11,16 @@ const displayedProjects = computed(() => props.projects.slice(0, displayCount.va
|
|||
function showMoreProjects() {
|
||||
displayCount.value += 50
|
||||
}
|
||||
|
||||
const cardTitles = ref< { label: string, togglable?: boolean, toggled?: boolean }[]>([
|
||||
{ label: 'Usecase' },
|
||||
{ label: 'Openess', togglable: true },
|
||||
{ label: 'Technology', togglable: true },
|
||||
{ label: 'Privacy', togglable: true },
|
||||
{ label: 'Ecosystem' },
|
||||
{ label: 'Links' },
|
||||
{ label: 'W3PN Score', togglable: true },
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -19,6 +29,118 @@ function showMoreProjects() {
|
|||
flex-col
|
||||
items-start
|
||||
>
|
||||
<div
|
||||
v-if="displayedProjects.length"
|
||||
flex
|
||||
items-center
|
||||
gap-x-12px
|
||||
w-full
|
||||
mb="8px md:16px"
|
||||
>
|
||||
<h2
|
||||
text="app-white 16px md:24px"
|
||||
font-700
|
||||
leading="24px md:32px"
|
||||
whitespace-nowrap
|
||||
>
|
||||
24 Defi
|
||||
</h2>
|
||||
<div
|
||||
h-2px
|
||||
w-full
|
||||
bg-app-white
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
i-heroicons-solid-chevron-down
|
||||
text="app-white 24px"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="displayedProjects.length"
|
||||
flex
|
||||
items-center
|
||||
justify-between
|
||||
w-full
|
||||
mb-16px
|
||||
>
|
||||
<div
|
||||
flex
|
||||
items-center
|
||||
gap-4px
|
||||
>
|
||||
<p
|
||||
text="12px md:14px"
|
||||
leading="16px md:24px"
|
||||
whitespace-nowrap
|
||||
>
|
||||
Project name
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
i-heroicons-solid-chevron-down
|
||||
text="app-white 20px"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
hidden
|
||||
md:flex
|
||||
items-center
|
||||
justify-end
|
||||
gap-48px
|
||||
w-full
|
||||
>
|
||||
<div
|
||||
v-for="title in cardTitles"
|
||||
:key="title.label"
|
||||
flex
|
||||
items-center
|
||||
gap-4px
|
||||
>
|
||||
<p
|
||||
text="12px md:14px"
|
||||
leading="16px md:24px"
|
||||
whitespace-nowrap
|
||||
>
|
||||
{{ title.label }}
|
||||
</p>
|
||||
<button
|
||||
v-if="title.togglable"
|
||||
type="button"
|
||||
:class="[title.toggled
|
||||
? 'i-heroicons-solid-chevron-up'
|
||||
: 'i-heroicons-solid-chevron-down']"
|
||||
text="app-white 20px"
|
||||
@click="title.toggled = !title.toggled"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
flex
|
||||
items-center
|
||||
gap-4px
|
||||
md:hidden
|
||||
>
|
||||
<p
|
||||
text="12px md:14px"
|
||||
leading="16px md:24px"
|
||||
>
|
||||
Sort by:
|
||||
</p>
|
||||
<p
|
||||
text="12px md:14px"
|
||||
leading="16px md:24px"
|
||||
font-700
|
||||
>
|
||||
Score
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
i-heroicons-solid-chevron-down
|
||||
text="app-white 20px"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="displayedProjects.length"
|
||||
grid
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import type { InputOption } from '~/types'
|
||||
|
||||
defineProps<{ placeholder?: string, includeSort?: boolean }>()
|
||||
|
||||
const { filter, switcher } = storeToRefs(useData())
|
||||
const options: InputOption[] = [
|
||||
{ label: 'A to Z', value: 'atoz' },
|
||||
|
@ -22,8 +24,8 @@ const isSearchFocused = ref(false)
|
|||
border-2px
|
||||
flex
|
||||
items-center
|
||||
max-w-320px
|
||||
w-full
|
||||
h-40px
|
||||
hover:opacity-100
|
||||
:class="isSearchFocused ? 'opacity-100' : 'opacity-25'"
|
||||
>
|
||||
|
@ -34,7 +36,7 @@ const isSearchFocused = ref(false)
|
|||
w-fit
|
||||
>
|
||||
<UnoIcon
|
||||
i-web-search
|
||||
i-heroicons-solid-magnifying-glass
|
||||
text-16px
|
||||
:class="isSearchFocused ? 'opacity-100' : 'opacity-50' "
|
||||
class="uno-icon"
|
||||
|
@ -42,6 +44,7 @@ const isSearchFocused = ref(false)
|
|||
</div>
|
||||
<input
|
||||
v-model="filter.query"
|
||||
:placeholder="placeholder"
|
||||
type="text"
|
||||
bg-transparent
|
||||
border-transparent
|
||||
|
@ -54,7 +57,7 @@ const isSearchFocused = ref(false)
|
|||
@blur="isSearchFocused = false"
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<div v-if="includeSort">
|
||||
<div
|
||||
flex
|
||||
gap-24px
|
||||
|
|
|
@ -3,7 +3,7 @@ import type { Category, Project, ProjectShallow } from '~/types'
|
|||
export const useData = defineStore('data', () => {
|
||||
const categories = useState<Category[]>('categories')
|
||||
const projects = useState<Project[]>('projects')
|
||||
const selectedCategoryId = useState(() => 'defi')
|
||||
const selectedCategoryId = useState(() => 'all')
|
||||
const filter = reactive({
|
||||
query: '',
|
||||
sortby: 'atoz',
|
||||
|
|
|
@ -3,8 +3,14 @@ import type { InputOption } from '~/types'
|
|||
|
||||
const { categories, filteredProjectsCount, selectedCategoryId } = storeToRefs(useData())
|
||||
|
||||
const selectedUsecaseId = ref('usecase')
|
||||
const selectedEcosystemId = ref('ecosystem')
|
||||
const selectedAssetsUsedId = ref('assetsUsed')
|
||||
const selectedFeaturesId = ref('features')
|
||||
|
||||
const categoriesOptions = ref(categories.value ? categories.value.map(c => ({ label: c.name, value: c.id, count: c.projectsCount })) : [])
|
||||
const extendedOptions: InputOption[] = [
|
||||
{ label: 'Category', value: 'all' },
|
||||
...categoriesOptions.value,
|
||||
]
|
||||
|
||||
|
@ -56,77 +62,58 @@ watch([scrollY, top, y], (newValues, oldValues) => {
|
|||
w-full
|
||||
xl:gap-32px
|
||||
>
|
||||
<div w-fit>
|
||||
<div
|
||||
ref="scrollEl"
|
||||
class="no-scrollbar"
|
||||
h-100vh
|
||||
overflow-y-auto
|
||||
sticky
|
||||
top-32px
|
||||
hidden
|
||||
xl:block
|
||||
min-w-234px
|
||||
pb-48px
|
||||
>
|
||||
<Category
|
||||
v-for="category in sortedFilteredCategories"
|
||||
:key="category.id"
|
||||
:title="category.name"
|
||||
:count="category.projectsCount"
|
||||
:selected="selectedCategoryId === category.id"
|
||||
@click="[navigateTo(`/category/${category.id}`), selectedCategoryId = category.id]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div w-full>
|
||||
<div
|
||||
flex
|
||||
flex-col
|
||||
w-full
|
||||
>
|
||||
<div
|
||||
flex
|
||||
flex-col
|
||||
md:flex-row
|
||||
md:justify-between
|
||||
md:items-center
|
||||
gap-16px
|
||||
w-full
|
||||
mb="16px md:32px"
|
||||
>
|
||||
<SearchBox
|
||||
flex-1
|
||||
:placeholder="`Search in ${filteredProjectsCount} Projects`"
|
||||
/>
|
||||
<div
|
||||
xl:hidden
|
||||
block
|
||||
md:flex-2
|
||||
flex
|
||||
items-center
|
||||
gap-16px
|
||||
overflow-x-auto
|
||||
>
|
||||
<h2
|
||||
text-14px
|
||||
font-700
|
||||
>
|
||||
Choose category
|
||||
</h2>
|
||||
<CategorySelectBox
|
||||
v-model="selectedCategoryId"
|
||||
:options="extendedOptions"
|
||||
w-full
|
||||
@selected="selectedCategoryId === 'all' ? navigateTo(`/`) : navigateTo(`/category/${selectedCategoryId}`)"
|
||||
/>
|
||||
<CategorySelectBox
|
||||
v-model="selectedUsecaseId"
|
||||
:options="[{ label: 'Usecase', value: 'usecase' }]"
|
||||
w-full
|
||||
/>
|
||||
<CategorySelectBox
|
||||
v-model="selectedEcosystemId"
|
||||
:options="[{ label: 'Ecosystem', value: 'ecosystem' }]"
|
||||
w-full
|
||||
/>
|
||||
<CategorySelectBox
|
||||
v-model="selectedAssetsUsedId"
|
||||
:options="[{ label: 'Assets used', value: 'assetsUsed' }]"
|
||||
w-full
|
||||
/>
|
||||
<CategorySelectBox
|
||||
v-model="selectedFeaturesId"
|
||||
:options="[{ label: 'Features', value: 'features' }]"
|
||||
w-full
|
||||
/>
|
||||
</div>
|
||||
<SearchBox />
|
||||
</div>
|
||||
<div
|
||||
flex
|
||||
gap-28px
|
||||
items-center
|
||||
my-24px
|
||||
mt-28px
|
||||
>
|
||||
<h2
|
||||
v-if="selectedCategoryId"
|
||||
w-max
|
||||
font-700
|
||||
text-18px
|
||||
sm:text-28px
|
||||
whitespace-nowrap
|
||||
>
|
||||
{{ selectedCategoryId === 'all' ? `${filteredProjectsCount} All Projects` : `${filteredProjectsCount ?? 0} ${selectedCategory?.name}` }}
|
||||
</h2>
|
||||
<div
|
||||
h-2px
|
||||
w="full"
|
||||
bg-white
|
||||
/>
|
||||
</div>
|
||||
<slot />
|
||||
</div>
|
||||
|
|
|
@ -35,5 +35,7 @@ export const collections = {
|
|||
open1: '<svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="gray" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"/></svg>',
|
||||
matrix: '<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none"><path d="M1.266 1.10241V46.8989H4.5615V48.0014H0V0.00141309H4.5615V1.10391L1.266 1.10241ZM15.3525 15.6179V17.9384H15.414C16.032 17.0459 16.782 16.3679 17.6475 15.8819C18.516 15.3974 19.524 15.1559 20.6475 15.1559C21.726 15.1559 22.7175 15.3674 23.61 15.7814C24.5085 16.2029 25.1805 16.9454 25.6485 17.9999C26.157 17.2499 26.853 16.5854 27.7185 16.0154C28.587 15.4454 29.619 15.1559 30.813 15.1559C31.719 15.1559 32.5545 15.2654 33.3285 15.4919C34.11 15.7094 34.767 16.0619 35.3205 16.5464C35.868 17.0399 36.297 17.6729 36.6105 18.4544C36.915 19.2344 37.071 20.1809 37.071 21.2909V32.7434H32.3775V23.0414C32.3775 22.4699 32.3535 21.9239 32.3055 21.4154C32.2755 20.9549 32.157 20.5094 31.947 20.0954C31.7505 19.7189 31.4475 19.4069 31.071 19.2059C30.6885 18.9779 30.1575 18.8699 29.5005 18.8699C28.836 18.8699 28.305 18.9944 27.8985 19.2434C27.501 19.4939 27.165 19.8374 26.9385 20.2439C26.697 20.6744 26.541 21.1499 26.4765 21.6344C26.3985 22.1579 26.361 22.6829 26.352 23.2064V32.7449H21.6555V23.1434C21.6555 22.6349 21.648 22.1354 21.618 21.6434C21.6015 21.1679 21.5085 20.7074 21.3285 20.2694C21.1725 19.8479 20.877 19.4954 20.5005 19.2614C20.118 19.0109 19.5465 18.8789 18.7965 18.8789C18.57 18.8789 18.2745 18.9254 17.9145 19.0274C17.5545 19.1279 17.196 19.3154 16.86 19.5899C16.5165 19.8719 16.218 20.2694 15.9765 20.7854C15.735 21.2999 15.618 21.9794 15.618 22.8239V32.7539H10.9215V15.6224L15.3525 15.6179ZM46.734 46.8974V1.10091H43.4385V-0.00158691H48V47.9984H43.4385V46.8959L46.734 46.8974Z" fill="white"/></svg>',
|
||||
news: '<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 28 28" fill="none"><g opacity="1"><mask id="mask0_2258_10849" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="28" height="28"><rect width="28" height="28" fill="#D9D9D9"/></mask><g mask="url(#mask0_2258_10849)"><path d="M4.66146 24.5C4.01979 24.5 3.47049 24.2715 3.01354 23.8146C2.5566 23.3576 2.32812 22.8083 2.32812 22.1667V5.83333C2.32812 5.19167 2.5566 4.64236 3.01354 4.18542C3.47049 3.72847 4.01979 3.5 4.66146 3.5H23.3281C23.9698 3.5 24.5191 3.72847 24.976 4.18542C25.433 4.64236 25.6615 5.19167 25.6615 5.83333V22.1667C25.6615 22.8083 25.433 23.3576 24.976 23.8146C24.5191 24.2715 23.9698 24.5 23.3281 24.5H4.66146ZM4.66146 22.1667H23.3281V5.83333H4.66146V22.1667ZM6.99479 19.8333H20.9948V17.5H6.99479V19.8333ZM6.99479 15.1667H11.6615V8.16667H6.99479V15.1667ZM13.9948 15.1667H20.9948V12.8333H13.9948V15.1667ZM13.9948 10.5H20.9948V8.16667H13.9948V10.5Z" fill="white"/></g></g></svg>',
|
||||
solid_arrow_down: '<svg width="10" height="5" viewBox="0 0 10 5" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5 5L0 0H10L5 5Z" fill="black"/></svg>',
|
||||
solid_arrow_up: '<svg width="10" height="5" viewBox="0 0 10 5" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5 -4.37114e-07L10 5L0 5L5 -4.37114e-07Z" fill="white"/></svg>',
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue