mirror of
https://github.com/web3privacy/explorer-app.git
synced 2024-10-15 16:46:26 +02:00
Merge pull request #19 from web3privacy/dk/dashboard-redesign
Dk/dashboard redesign
This commit is contained in:
commit
75f5e2c57b
37 changed files with 1940 additions and 1258 deletions
|
@ -1,10 +1,14 @@
|
|||
<script lang="ts" setup>
|
||||
import type { ProjectShallow } from '~/types'
|
||||
import type { ProjectRating, ProjectShallow } from '~/types'
|
||||
|
||||
defineProps<{
|
||||
const props = defineProps<{
|
||||
project: ProjectShallow
|
||||
}>()
|
||||
const { switcher } = storeToRefs(useData())
|
||||
const { switcher, ecosystems } = storeToRefs(useData())
|
||||
|
||||
const ratings: { label: string, type: string, rating: ProjectRating }[] = (props.project.ratings || []).map(rating => ({ label: rating.name, type: 'rating', rating: rating }))
|
||||
const ecosystem: { label: string[], type: string } = { label: ecosystems.value.filter(e => (props.project.ecosystem || []).includes(e.id)).map(e => e.icon!), type: 'ecosystem' }
|
||||
const projectItems: { label: string | string[], type: string, rating?: ProjectRating }[] = [{ label: props.project.usecases || [], type: 'array' }, ...ratings, ecosystem, { label: [props.project.website || '', props.project.github || '', props.project.twitter || ''], type: 'links' }]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -18,230 +22,179 @@ const { switcher } = storeToRefs(useData())
|
|||
transition-all
|
||||
>
|
||||
<div
|
||||
relative
|
||||
max-w="96px lg:200px"
|
||||
grid
|
||||
grid-cols="2 lg:10"
|
||||
w-full
|
||||
h="96px lg:200px"
|
||||
:class="switcher ? '' : 'lg:max-w-full! lg:w-full '"
|
||||
>
|
||||
|
||||
<div
|
||||
col-span="1 lg:2"
|
||||
flex
|
||||
items-center
|
||||
justify-center
|
||||
gap="12px lg:16px"
|
||||
relative
|
||||
w-full
|
||||
my-auto
|
||||
h-full
|
||||
h="48px lg:64px"
|
||||
:class="switcher ? '' : 'lg:max-w-full! lg:w-full '"
|
||||
>
|
||||
<NuxtImg
|
||||
:src="project?.image || '/no-image-1-1.svg'"
|
||||
class="w-full h-auto"
|
||||
max-h="md:196px 96px"
|
||||
max-h="md:64px 48px"
|
||||
max-w="md:64px 48px"
|
||||
self-center
|
||||
z-10
|
||||
object-fit
|
||||
bg="#121212"
|
||||
/>
|
||||
<div
|
||||
flex
|
||||
flex-col
|
||||
gap-y-4px
|
||||
lg:flex-row
|
||||
justify-center
|
||||
>
|
||||
<div
|
||||
w-fit
|
||||
flex
|
||||
items-center
|
||||
gap-8px
|
||||
@click.prevent="navigateTo(project.website, { external: true, open: { target: '_blank' } })"
|
||||
>
|
||||
<h1
|
||||
text="14px app-white"
|
||||
font-700
|
||||
line-clamp-1
|
||||
hover:underline
|
||||
underline-offset-3
|
||||
leading="20px lg:32px"
|
||||
>
|
||||
{{ project.title1 }}
|
||||
</h1>
|
||||
</div>
|
||||
<p
|
||||
text-12px
|
||||
leading-16px
|
||||
lg:hidden
|
||||
>
|
||||
{{ project.usecases?.join(', ') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<ClientOnly>
|
||||
<Badge
|
||||
v-if="project.percentage"
|
||||
absolute
|
||||
bottom-0.5
|
||||
lg:bottom-0
|
||||
right-0.5
|
||||
lg:right-0
|
||||
mr-2px
|
||||
mb-2px
|
||||
:text="`${project.percentage}%`"
|
||||
class="leading-12px! text-12px! lg:text-18px! border-0!"
|
||||
px="4px! lg:16px!"
|
||||
py="4px! lg:8px!"
|
||||
/>
|
||||
</ClientOnly>
|
||||
</div>
|
||||
<div
|
||||
h="96px lg:200px"
|
||||
lg:py-24px
|
||||
lg:pr-24px
|
||||
flex
|
||||
flex-col
|
||||
justify-center
|
||||
lg:justify-between
|
||||
lg:gap-24px
|
||||
w-full
|
||||
text-white
|
||||
:class="switcher ? '' : 'lg:p-16px! lg:py-16px!'"
|
||||
>
|
||||
<div
|
||||
w-full
|
||||
h-fit
|
||||
flex
|
||||
flex-col
|
||||
gap-8px
|
||||
>
|
||||
<div
|
||||
w-fit
|
||||
flex
|
||||
items-center
|
||||
gap-8px
|
||||
@click.prevent="navigateTo(project.website, { external: true, open: { target: '_blank' } })"
|
||||
>
|
||||
<h1
|
||||
text="18px lg:24px app-white"
|
||||
font-700
|
||||
line-clamp-1
|
||||
hover:underline
|
||||
underline-offset-3
|
||||
>
|
||||
{{ project.title1 }}
|
||||
</h1>
|
||||
<UnoIcon
|
||||
i-web-open
|
||||
text-16px
|
||||
/>
|
||||
</div>
|
||||
<h2
|
||||
text="14px app-text-grey"
|
||||
overflow-hidden
|
||||
text-ellipsis
|
||||
line-clamp-2
|
||||
lg:line-clamp-2
|
||||
>
|
||||
{{ project.description }}
|
||||
</h2>
|
||||
</div>
|
||||
<div
|
||||
w-full
|
||||
flex
|
||||
justify-between
|
||||
>
|
||||
<div
|
||||
w-full
|
||||
max-w-692px
|
||||
grid
|
||||
whitespace-nowrap
|
||||
:class="switcher ? 'grid-cols-5' : 'grid-cols-3'"
|
||||
gap-24px
|
||||
lg:grid
|
||||
hidden
|
||||
>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project?.github"
|
||||
:link="project?.github"
|
||||
title="Github"
|
||||
bold
|
||||
text-size="18px"
|
||||
>
|
||||
<div
|
||||
flex
|
||||
items-center
|
||||
gap-8px
|
||||
>
|
||||
<UnoIcon
|
||||
i-web-github
|
||||
text-16px
|
||||
/>
|
||||
<span>{{ project?.github ? 'YES' : 'NO' }}</span>
|
||||
</div>
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.readyness"
|
||||
title="Readyness"
|
||||
text-size="18px"
|
||||
>
|
||||
<div
|
||||
flex
|
||||
items-center
|
||||
gap-12px
|
||||
>
|
||||
<UnoIcon
|
||||
i-web-live
|
||||
text-10px
|
||||
:class="(project.readyness === 'Mainnet') ? 'color-#18FF2F' : (project.readyness === 'Testnet') ? 'color-#FFA800' : (project.readyness === 'Alpha') ? 'color-#FF0000' : ''"
|
||||
/>
|
||||
<span :class="(project.readyness === 'Alpha') ? 'color-#FFA800' : 'color-white'">{{ project.readyness }}</span>
|
||||
</div>
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="true"
|
||||
title="Team"
|
||||
text-size="18px"
|
||||
>
|
||||
<span v-if="project.team?.length">{{ `${project.team?.length} members` }}</span>
|
||||
<span
|
||||
v-else
|
||||
color="#FF0000"
|
||||
>{{ 'Anonymous' }}</span>
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project?.docs"
|
||||
:link="project?.docs"
|
||||
:color="project?.docs ? '#18FF2F' : '#FF0000'"
|
||||
title="Docs"
|
||||
bold
|
||||
text-size="18px"
|
||||
>
|
||||
{{ project?.docs ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.audits"
|
||||
:link="project?.audits?.[0]?.link ?? undefined"
|
||||
:color="project?.audits ? '#18FF2F' : '#FF0000'"
|
||||
title="Audit"
|
||||
bold
|
||||
text-size="18px"
|
||||
>
|
||||
{{ project.audits ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
</div>
|
||||
<div
|
||||
v-for="(projectItem, index) of projectItems"
|
||||
:key="projectItem.label.toString()"
|
||||
hidden
|
||||
lg:flex
|
||||
items-center
|
||||
text-14px
|
||||
leading-24px
|
||||
:class="{ 'col-span-1 lg:col-span-2': index === 0 }"
|
||||
>
|
||||
<p
|
||||
v-if="projectItem.type === 'array'"
|
||||
text-app-text-grey
|
||||
>
|
||||
{{ (projectItem.label as string[] || []).join(', ') }}
|
||||
</p>
|
||||
<div
|
||||
v-if="projectItem.type === 'links'"
|
||||
flex
|
||||
items-center
|
||||
justify-start
|
||||
gap-16px
|
||||
>
|
||||
<NuxtLink
|
||||
v-if="projectItem.label[1]"
|
||||
:to="projectItem.label[1]"
|
||||
external
|
||||
target="_blank"
|
||||
>
|
||||
<UnoIcon
|
||||
i-ic-baseline-language
|
||||
text="24px app-text-grey"
|
||||
/>
|
||||
</NuxtLink>
|
||||
<NuxtLink
|
||||
v-if="projectItem.label[2]"
|
||||
:to="projectItem.label[2]"
|
||||
external
|
||||
target="_blank"
|
||||
>
|
||||
<UnoIcon
|
||||
i-mdi-github
|
||||
text="24px app-text-grey"
|
||||
text-27px
|
||||
/>
|
||||
</NuxtLink>
|
||||
<NuxtLink
|
||||
v-if="projectItem.label[0]"
|
||||
:to="projectItem.label[0]"
|
||||
external
|
||||
target="_blank"
|
||||
>
|
||||
<UnoIcon
|
||||
i-bi-twitter-x
|
||||
text="24px app-text-grey"
|
||||
/>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<div
|
||||
v-if="projectItem.type === 'ecosystem'"
|
||||
flex
|
||||
items-center
|
||||
justify-start
|
||||
gap-2px
|
||||
>
|
||||
<NuxtImg
|
||||
v-for="ecosystem of projectItem.label"
|
||||
:key="ecosystem"
|
||||
:src="ecosystem"
|
||||
w-24px
|
||||
h-24px
|
||||
rounded-full
|
||||
/>
|
||||
</div>
|
||||
<ProjectRating
|
||||
v-if="projectItem.type! === 'rating' && projectItem.rating"
|
||||
:percentage="projectItem.rating.points"
|
||||
:rating="projectItem.rating"
|
||||
:type="projectItem.rating.type"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
flex
|
||||
items-center
|
||||
justify-end
|
||||
w-full
|
||||
gap-16px
|
||||
>
|
||||
<UnoIcon
|
||||
v-if="project.forum"
|
||||
i-web-forum
|
||||
text-28px
|
||||
opacity-50
|
||||
hover:opacity-100
|
||||
@click.prevent="navigateTo(project.forum, { external: true, open: { target: '_blank' } })"
|
||||
/>
|
||||
<UnoIcon
|
||||
v-if="project.explorer"
|
||||
i-web-explorer
|
||||
text-32px
|
||||
opacity-50
|
||||
hover:opacity-100
|
||||
@click.prevent="navigateTo(project.explorer, { external: true, open: { target: '_blank' } })"
|
||||
/>
|
||||
<UnoIcon
|
||||
v-if="project.twitter"
|
||||
i-web-twitter_x
|
||||
text-22px
|
||||
opacity-50
|
||||
hover:opacity-100
|
||||
@click.prevent="navigateTo(project.twitter, { external: true, open: { target: '_blank' } })"
|
||||
/>
|
||||
<UnoIcon
|
||||
v-if="project.coingecko"
|
||||
i-web-coingecko
|
||||
text-24px
|
||||
opacity-50
|
||||
hover:opacity-100
|
||||
@click.prevent="navigateTo(project.coingecko, { external: true, open: { target: '_blank' } })"
|
||||
/>
|
||||
<UnoIcon
|
||||
v-if="project.newsletter"
|
||||
i-web-news
|
||||
text-28px
|
||||
opacity-50
|
||||
hover:opacity-100
|
||||
@click.prevent="navigateTo(project.newsletter, { external: true, open: { target: '_blank' } })"
|
||||
block
|
||||
lg:hidden
|
||||
i-iconoir-internet
|
||||
text="24px"
|
||||
/>
|
||||
<div
|
||||
flex
|
||||
items-center
|
||||
justify-center
|
||||
border="2px app-white"
|
||||
text="14px md:18px"
|
||||
leading="24px md:32px"
|
||||
max-h-="28px md:32px"
|
||||
max-w="48px md:56px"
|
||||
w-full
|
||||
font-700
|
||||
whitespace-nowrap
|
||||
>
|
||||
{{ project.percentage }} %
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ClientOnly>
|
||||
</div>
|
||||
|
||||
</NuxtLink>
|
||||
</template>
|
||||
|
|
|
@ -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
|
||||
i-ic-baseline-arrow-drop-down
|
||||
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,18 @@ 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>
|
||||
|
|
|
@ -13,6 +13,7 @@ defineProps<{
|
|||
>
|
||||
<UnoIcon
|
||||
i-heroicons-solid-pencil
|
||||
text-app-text-grey
|
||||
text-24px
|
||||
/>
|
||||
<slot />
|
||||
|
|
|
@ -20,9 +20,6 @@ defineProps<{
|
|||
gap-8px
|
||||
text-16px
|
||||
font-700
|
||||
lg:max-w-320px
|
||||
lg:w-full
|
||||
lg:justify-end
|
||||
>
|
||||
<slot />
|
||||
{{ title }}
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
<div
|
||||
hidden
|
||||
w-full
|
||||
max-w-320px
|
||||
lg:block
|
||||
/>
|
||||
<div w-full>
|
||||
<slot />
|
||||
|
|
|
@ -2,15 +2,35 @@
|
|||
import type { ProjectShallow } from '~/types'
|
||||
|
||||
const props = defineProps<{
|
||||
projects: ProjectShallow[]
|
||||
projects: { title: string, projects: ProjectShallow[] }[]
|
||||
}>()
|
||||
const { switcher } = storeToRefs(useData())
|
||||
const { switcher, filter } = storeToRefs(useData())
|
||||
|
||||
const displayCount = ref(100)
|
||||
const displayedProjects = computed(() => props.projects.slice(0, displayCount.value))
|
||||
function showMoreProjects() {
|
||||
displayCount.value += 50
|
||||
const totalProjectsCount = props.projects.map(g => g.projects.length).reduce((a, b) => a + b, 0)
|
||||
|
||||
function onChangeSort(sortKey: string) {
|
||||
if (filter.value.sortby === sortKey) {
|
||||
if (filter.value.sortDirection === 'desc' && filter.value.sortby !== 'score') {
|
||||
filter.value.sortby = 'score'
|
||||
filter.value.sortDirection = 'desc'
|
||||
return
|
||||
}
|
||||
filter.value.sortDirection = filter.value.sortDirection === 'asc' ? 'desc' : 'asc'
|
||||
return
|
||||
}
|
||||
filter.value.sortby = sortKey
|
||||
filter.value.sortDirection = sortKey === 'score' ? 'desc' : 'asc'
|
||||
}
|
||||
|
||||
const cardTitles = ref< { label: string, sortKey: string, togglable?: boolean }[]>([
|
||||
{ label: 'Usecase', sortKey: 'usecase' },
|
||||
{ label: 'Openess', sortKey: 'openess', togglable: true },
|
||||
{ label: 'Technology', sortKey: 'technology', togglable: true },
|
||||
{ label: 'Privacy', sortKey: 'privacy', togglable: true },
|
||||
{ label: 'Ecosystem', sortKey: 'ecosystem' },
|
||||
{ label: 'Links', sortKey: 'links' },
|
||||
{ label: 'W3PN Score', sortKey: 'score', togglable: true },
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -19,36 +39,138 @@ function showMoreProjects() {
|
|||
flex-col
|
||||
items-start
|
||||
>
|
||||
<div
|
||||
v-if="displayedProjects.length"
|
||||
grid
|
||||
:class="switcher ? 'grid-cols-1 lg:grid-cols-1' : 'xl:grid-cols-3 lg:grid-cols-3 sm:grid-cols-2 grid-cols-1'"
|
||||
gap-16px
|
||||
text-white
|
||||
w-full
|
||||
<template
|
||||
v-for="group in projects"
|
||||
:key="group.title"
|
||||
>
|
||||
<Card
|
||||
v-for="project in displayedProjects"
|
||||
:key="project.id"
|
||||
:project="project"
|
||||
/>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div
|
||||
|
||||
flex
|
||||
items-center
|
||||
gap-x-12px
|
||||
w-full
|
||||
mb="8px lg:16px"
|
||||
mt-22px
|
||||
>
|
||||
<h2
|
||||
text="app-white 16px lg:24px"
|
||||
font-700
|
||||
leading="24px lg:32px"
|
||||
whitespace-nowrap
|
||||
>
|
||||
{{ group.projects.length }} {{ group.title }}
|
||||
</h2>
|
||||
<div
|
||||
h-2px
|
||||
w-full
|
||||
bg-app-text-grey
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
i-ic-baseline-arrow-drop-down
|
||||
text="app-text-grey 24px"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
grid
|
||||
grid-cols="2 lg:10"
|
||||
w-full
|
||||
mb-16px
|
||||
>
|
||||
<div
|
||||
flex
|
||||
items-center
|
||||
gap-4px
|
||||
col-span="1 lg:2"
|
||||
:class="['title' === filter.sortby ? 'text-app-white' : 'text-app-text-grey', 'cursor-pointer']"
|
||||
@click="onChangeSort('title')"
|
||||
>
|
||||
<p
|
||||
text="12px lg:14px"
|
||||
leading="16px lg:24px"
|
||||
whitespace-nowrap
|
||||
>
|
||||
Project name
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
:class="['title' === filter.sortby ? filter.sortDirection === 'desc' ? 'i-ic-baseline-arrow-drop-up'
|
||||
: 'i-ic-baseline-arrow-drop-down'
|
||||
: 'i-ic-baseline-arrow-drop-down']"
|
||||
text="20px"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
flex
|
||||
items-center
|
||||
justify-end
|
||||
gap-4px
|
||||
lg:hidden
|
||||
>
|
||||
<p
|
||||
text="12px lg:14px app-text-grey"
|
||||
leading="16px lg:24px"
|
||||
>
|
||||
Sort by:
|
||||
</p>
|
||||
<p
|
||||
text="12px lg:14px"
|
||||
leading="16px lg:24px"
|
||||
font-700
|
||||
>
|
||||
Score
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
i-ic-baseline-arrow-drop-down
|
||||
text="app-text-grey 20px"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-for="(title, index) in cardTitles"
|
||||
:key="title.label"
|
||||
lg:flex
|
||||
items-center
|
||||
justify-start
|
||||
last:justify-end
|
||||
gap-4px
|
||||
hidden
|
||||
:class="[title.sortKey === filter.sortby ? 'text-app-white' : 'text-app-text-grey', { 'cursor-pointer': title.togglable, 'col-span-1 lg:col-span-2': index === 0 }]"
|
||||
@click="onChangeSort(title.sortKey)"
|
||||
>
|
||||
<p
|
||||
text="12px lg:14px "
|
||||
leading="16px lg:24px"
|
||||
whitespace-nowrap
|
||||
>
|
||||
{{ title.label }}
|
||||
</p>
|
||||
<button
|
||||
v-if="title.togglable"
|
||||
type="button"
|
||||
:class="[title.sortKey === filter.sortby ? filter.sortDirection === 'desc' ? 'i-ic-baseline-arrow-drop-up'
|
||||
: 'i-ic-baseline-arrow-drop-down'
|
||||
: 'i-ic-baseline-arrow-drop-down']"
|
||||
text=" 20px"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
grid
|
||||
:class="switcher ? 'grid-cols-1 lg:grid-cols-1' : 'xl:grid-cols-3 lg:grid-cols-3 sm:grid-cols-2 grid-cols-1'"
|
||||
gap-16px
|
||||
text-white
|
||||
w-full
|
||||
>
|
||||
<Card
|
||||
v-for="project in group.projects"
|
||||
:key="project.id"
|
||||
:project="project"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="totalProjectsCount === 0">
|
||||
<h3>No Projects found...</h3>
|
||||
</div>
|
||||
<button
|
||||
v-if="displayedProjects.length < projects.length"
|
||||
mt-29px
|
||||
text="14px"
|
||||
leading-24px
|
||||
font-700
|
||||
px-12px
|
||||
py-4px
|
||||
border-2px
|
||||
border-app-white
|
||||
@click="showMoreProjects"
|
||||
>
|
||||
Load more projects
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
<script lang="ts" setup>
|
||||
import type { Project, ProjectIndexable } from '~/types'
|
||||
import type { Project } from '~/types'
|
||||
|
||||
const props = defineProps<{
|
||||
project: Project
|
||||
}>()
|
||||
|
||||
const availableSupport = computed(() => {
|
||||
const filteredKeys = ['forum', 'discord', 'twitter', 'lens', 'farcaster', 'telegram']
|
||||
if (typeof props.project.links === 'object' && (props.project.links !== null || props.project.links !== undefined))
|
||||
return Object.keys(props.project.links).filter(key => filteredKeys.includes(key)).length
|
||||
// const availableSupport = computed(() => {
|
||||
// const filteredKeys = ['forum', 'discord', 'twitter', 'lens', 'farcaster', 'telegram']
|
||||
// if (typeof props.project.links === 'object' && (props.project.links !== null || props.project.links !== undefined))
|
||||
// return Object.keys(props.project.links).filter(key => filteredKeys.includes(key)).length
|
||||
|
||||
return 0
|
||||
})
|
||||
// return 0
|
||||
// })
|
||||
|
||||
/**
|
||||
* From data points
|
||||
|
@ -21,80 +21,42 @@ const availableSupport = computed(() => {
|
|||
- team: anon / public
|
||||
- audit: yes / no
|
||||
*/
|
||||
const calculateScore = computed(() => {
|
||||
const criterias: { value: keyof ProjectIndexable, key: keyof ProjectIndexable | '' }[] = [
|
||||
{ value: 'product_readiness', key: '' },
|
||||
{ value: 'github', key: 'links' },
|
||||
{ value: 'docs', key: 'links' },
|
||||
{ value: 'team', key: '' },
|
||||
{ value: 'audits', key: '' },
|
||||
]
|
||||
|
||||
let matched = 0
|
||||
for (let i = 0; i < criterias.length; i++) {
|
||||
let value
|
||||
// value = ((criterias[i].key ?? props.project[criterias[i].value as keyof typeof props.project]) ?? null === null) ? null : (props.project as ProjectIndexable)[criterias[i].key][criterias[i].value]
|
||||
|
||||
const indexableProject = props.project as ProjectIndexable
|
||||
if (criterias[i].key !== '')
|
||||
value = (indexableProject[criterias[i].key] as any)?.[criterias[i].value]
|
||||
else
|
||||
value = indexableProject?.[criterias[i].value]
|
||||
|
||||
// console.log(props.project?.links?.github);
|
||||
// console.log(Object.keys(props.indexableProject["team"]).length);
|
||||
if (value === null || value === undefined)
|
||||
continue
|
||||
|
||||
if (fulfilled(value))
|
||||
matched++
|
||||
}
|
||||
|
||||
return 100 / criterias.length * matched
|
||||
})
|
||||
|
||||
function fulfilled(value: any): boolean {
|
||||
const type = typeof value
|
||||
switch (type) {
|
||||
case 'string':
|
||||
if (value !== '')
|
||||
return true
|
||||
break
|
||||
case 'object':
|
||||
if (Object.keys(value!).length > 0)
|
||||
return true
|
||||
break
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const logo = props.project?.logos?.at(0)?.url
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
lg:flex
|
||||
flex
|
||||
flex-col
|
||||
gap-y-16px
|
||||
lg:flex-row
|
||||
items-center
|
||||
lg:gap-32px
|
||||
>
|
||||
<NuxtImg
|
||||
lg:max-w-320px
|
||||
lg:max-h-320px
|
||||
max-w-200px
|
||||
max-h-200px
|
||||
shrink
|
||||
border="1px app-text-grey"
|
||||
:src="logo ?? '/no-image-1-1.svg'"
|
||||
class="bg-app-bg-grey object-cover max-w-full h-full vertical-align[middle] block border-0 w-full h-[300px]"
|
||||
class="bg-app-bg-grey object-cover h-full vertical-align[middle] block w-full h-[300px] "
|
||||
/>
|
||||
<div grow>
|
||||
<div
|
||||
grow
|
||||
w-full
|
||||
>
|
||||
<div
|
||||
flex
|
||||
flex-col
|
||||
items-center
|
||||
lg:items-start
|
||||
justify-between
|
||||
gap-32px
|
||||
lg:flex-row
|
||||
lg:items-center
|
||||
gap-y="lg:12px 24px"
|
||||
text-app-text-grey
|
||||
w-full
|
||||
>
|
||||
<div mt-24px>
|
||||
<div mt-4px>
|
||||
<NuxtLink
|
||||
:to="project.links?.web"
|
||||
target="_blank"
|
||||
|
@ -112,139 +74,154 @@ const logo = props.project?.logos?.at(0)?.url
|
|||
{{ project.name }}
|
||||
</h1>
|
||||
<UnoIcon
|
||||
i-web-openinnew
|
||||
text-16px
|
||||
i-ic-twotone-open-in-new
|
||||
text="22px app-white"
|
||||
/>
|
||||
</NuxtLink>
|
||||
<h2
|
||||
text="16px app-text-grey"
|
||||
leading-24px
|
||||
mt-8px
|
||||
>
|
||||
{{ project.project_type ?? '---' }}
|
||||
</h2>
|
||||
</div>
|
||||
<div
|
||||
border-2px
|
||||
class="border-app-black bg-app-white text-app-black"
|
||||
flex
|
||||
items-center
|
||||
justify-center
|
||||
px-32px
|
||||
py-16px
|
||||
text-32px
|
||||
font-700
|
||||
leading-40px
|
||||
cursor-pointer
|
||||
lg:grid
|
||||
grid-cols-10
|
||||
w-full
|
||||
items-center
|
||||
mt-4px
|
||||
>
|
||||
{{ `${calculateScore}%` }}
|
||||
<h2
|
||||
hidden
|
||||
lg:block
|
||||
>
|
||||
Usecases:
|
||||
</h2>
|
||||
<p
|
||||
text-app-white
|
||||
col-span-9
|
||||
>
|
||||
Swap, Mixer
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
grid
|
||||
grid-cols-2
|
||||
gap-16px
|
||||
my-32px
|
||||
lg:grid-cols-4
|
||||
>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.links?.github"
|
||||
title="Github"
|
||||
bold
|
||||
text-size="18px"
|
||||
<div
|
||||
grid
|
||||
grid-cols-2
|
||||
gap-y-12px
|
||||
lg:flex
|
||||
lg:flex-col
|
||||
order-3
|
||||
lg:order-2
|
||||
w-full
|
||||
>
|
||||
<template #prefix>
|
||||
<UnoIcon i-web-code />
|
||||
</template>
|
||||
{{ project.links?.github ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.project_status?.version"
|
||||
title="Product readyness"
|
||||
bold
|
||||
text-size="18px"
|
||||
<div
|
||||
flex
|
||||
flex-col
|
||||
gap-4px
|
||||
lg:grid
|
||||
lg:grid-cols-10
|
||||
lg:items-center
|
||||
w-full
|
||||
>
|
||||
<h2>
|
||||
Categories:
|
||||
</h2>
|
||||
<p
|
||||
text-app-white
|
||||
col-span-9
|
||||
>
|
||||
Dapp, Network
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
flex
|
||||
flex-col
|
||||
gap-4px
|
||||
lg:grid
|
||||
lg:grid-cols-10
|
||||
lg:items-center
|
||||
w-full
|
||||
>
|
||||
<h2>
|
||||
Ecosystems:
|
||||
</h2>
|
||||
<p
|
||||
text-app-white
|
||||
col-span-9
|
||||
>
|
||||
Ethereum, Secret Network
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
grid
|
||||
grid-cols-4
|
||||
w-full
|
||||
items-center
|
||||
order-2
|
||||
lg:order-3
|
||||
>
|
||||
<template #prefix>
|
||||
<UnoIcon i-web-cube />
|
||||
</template>
|
||||
{{ project.project_status?.version }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.team?.length"
|
||||
title="Team"
|
||||
bold
|
||||
text-size="18px"
|
||||
>
|
||||
<template #prefix>
|
||||
<UnoIcon i-web-team />
|
||||
</template>
|
||||
{{ `${project.team?.length} members` }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.links?.docs"
|
||||
title="Docs"
|
||||
bold
|
||||
text-size="18px"
|
||||
>
|
||||
<template #prefix>
|
||||
<UnoIcon
|
||||
i-web-docs
|
||||
text-28px
|
||||
/>
|
||||
</template>
|
||||
{{ project.links?.docs ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.audits"
|
||||
title="Audit"
|
||||
bold
|
||||
text-size="18px"
|
||||
>
|
||||
<template #prefix>
|
||||
<UnoIcon
|
||||
i-web-audit
|
||||
text-28px
|
||||
/>
|
||||
</template>
|
||||
{{ project.audits ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.links"
|
||||
title="Available support"
|
||||
bold
|
||||
text-size="18px"
|
||||
>
|
||||
<template #prefix>
|
||||
<UnoIcon
|
||||
i-web-support
|
||||
text-28px
|
||||
/>
|
||||
</template>
|
||||
{{ `${availableSupport} channels` }}
|
||||
</ProjectInfoItem>
|
||||
</div>
|
||||
<div
|
||||
grid
|
||||
grid-cols-2
|
||||
gap-16px
|
||||
my-32px
|
||||
lg:grid-cols-4
|
||||
>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.blockchain_features?.network"
|
||||
tooltip-link="/"
|
||||
title="Ecosystem"
|
||||
bold
|
||||
>
|
||||
{{ project.blockchain_features?.network }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
invisible
|
||||
title="Last update"
|
||||
bold
|
||||
>
|
||||
17/11/2023 – 23:22
|
||||
</ProjectInfoItem>
|
||||
<div
|
||||
flex
|
||||
items-center
|
||||
justify-between
|
||||
lg:justify-start
|
||||
lg:gap-24px
|
||||
col-span-3
|
||||
>
|
||||
<div
|
||||
v-for="rating of project.ratings"
|
||||
:key="rating.name"
|
||||
flex
|
||||
flex-col
|
||||
lg:flex-row
|
||||
items-center
|
||||
>
|
||||
<p
|
||||
text="12px lg:16px"
|
||||
leading="16px lg:24px"
|
||||
>
|
||||
{{ rating.name }}:
|
||||
</p>
|
||||
<ProjectRating
|
||||
:rating="rating"
|
||||
:percentage="rating.points"
|
||||
compact
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
flex
|
||||
items-center
|
||||
justify-end
|
||||
w-full
|
||||
gap-16px
|
||||
mt--8px
|
||||
lg:mt-0
|
||||
>
|
||||
<h2
|
||||
hidden
|
||||
lg:block
|
||||
>
|
||||
Total Score:
|
||||
</h2>
|
||||
<div
|
||||
flex
|
||||
items-center
|
||||
justify-center
|
||||
border="2px app-white"
|
||||
text="16px lg:24px app-white"
|
||||
leading="24px md:32px"
|
||||
max-h-="32px md:40px"
|
||||
max-w="84px"
|
||||
w-full
|
||||
h-full
|
||||
font-700
|
||||
whitespace-nowrap
|
||||
py="2px lg:8px"
|
||||
lg:py-4px
|
||||
>
|
||||
{{ calculateScore(project) }} %
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
36
components/Project/ProjectHistory.vue
Normal file
36
components/Project/ProjectHistory.vue
Normal file
|
@ -0,0 +1,36 @@
|
|||
<script lang="ts" setup>
|
||||
import type { Project } from '~/types'
|
||||
|
||||
defineProps<{
|
||||
project: Project
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProjectDetailCategoryDivider
|
||||
title="HISTORY"
|
||||
badge-text="3/10"
|
||||
>
|
||||
<UnoIcon
|
||||
i-material-symbols-calendar-month
|
||||
text-24px
|
||||
/>
|
||||
</ProjectDetailCategoryDivider>
|
||||
<ProjectDetailContainer>
|
||||
<div
|
||||
grid
|
||||
grid-cols-2
|
||||
items-start
|
||||
mt-32px
|
||||
gap-y-16px
|
||||
lg:grid-cols-4
|
||||
>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.history?.time"
|
||||
title="Date of creation"
|
||||
>
|
||||
{{ formatDate(project.history!.time!) }}
|
||||
</ProjectInfoItem>
|
||||
</div>
|
||||
</ProjectDetailContainer>
|
||||
</template>
|
|
@ -32,13 +32,6 @@ const githubProjectUrl = computed(() => {
|
|||
md:block
|
||||
>{{ 'BACK TO LIST' }}</span>
|
||||
</NavigationButton>
|
||||
<hr
|
||||
hidden
|
||||
md:block
|
||||
border-t-2px
|
||||
border-white
|
||||
w-full
|
||||
>
|
||||
<div
|
||||
flex
|
||||
gap-16px
|
||||
|
|
|
@ -12,7 +12,7 @@ defineProps<{
|
|||
badge-text="3/10"
|
||||
>
|
||||
<UnoIcon
|
||||
i-web-code_v2
|
||||
i-bi-code-square
|
||||
text-24px
|
||||
/>
|
||||
</ProjectDetailCategoryDivider>
|
||||
|
@ -23,25 +23,98 @@ defineProps<{
|
|||
leading-24px
|
||||
font-400
|
||||
>
|
||||
<h3 text-app-text-grey>
|
||||
{{ 'Project Description' }}
|
||||
<h3
|
||||
text-app-text-grey
|
||||
mb-8px
|
||||
>
|
||||
Project Description
|
||||
</h3>
|
||||
<span
|
||||
<p
|
||||
text="14px sm:16px"
|
||||
leading-20px
|
||||
>{{ project.description ?? '---' }}</span>
|
||||
>
|
||||
{{ project.description ?? '---' }}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
grid
|
||||
grid-cols="2 lg:4"
|
||||
mt="24px lg:32px"
|
||||
text="14px lg:16px"
|
||||
gap-y-16px
|
||||
>
|
||||
<div>
|
||||
<h3
|
||||
text-app-text-grey
|
||||
leading-20px
|
||||
mb="4px lg:8px"
|
||||
>
|
||||
Project Phase
|
||||
</h3>
|
||||
<div
|
||||
flex
|
||||
items-center
|
||||
gap-8px
|
||||
>
|
||||
<div
|
||||
h-10px
|
||||
w-10px
|
||||
rounded-full
|
||||
bg-green
|
||||
/><p leading="20px lg:24px">
|
||||
Mainnet
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3
|
||||
text-app-text-grey
|
||||
leading-20px
|
||||
mb="4px lg:8px"
|
||||
>
|
||||
Assets used
|
||||
</h3>
|
||||
<p leading="20px lg:24px">
|
||||
ETH, DAI, USDC, FRAX
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3
|
||||
text-app-text-grey
|
||||
leading-20px
|
||||
mb="4px lg:8px"
|
||||
>
|
||||
Native token
|
||||
</h3>
|
||||
<p leading="20px lg:24px">
|
||||
SCRT
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3
|
||||
text-app-text-grey
|
||||
leading-20px
|
||||
mb="4px lg:8px"
|
||||
>
|
||||
Project launch day
|
||||
</h3>
|
||||
<p leading="20px lg:24px">
|
||||
06/2017
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div mt-24px>
|
||||
<h3
|
||||
text="14px sm:16px app-text-grey"
|
||||
leading-20px
|
||||
>
|
||||
{{ 'Infrastructure links' }}
|
||||
Infrastructure links:
|
||||
</h3>
|
||||
<div
|
||||
grid
|
||||
grid-cols-2
|
||||
gap-16px
|
||||
gap-x-16px
|
||||
gap-y-12px
|
||||
mt-8px
|
||||
lg:grid-cols-4
|
||||
>
|
||||
|
@ -50,18 +123,12 @@ defineProps<{
|
|||
:to="project.links?.web"
|
||||
>
|
||||
<template #prefix>
|
||||
<UnoIcon i-web-website />
|
||||
<UnoIcon
|
||||
i-ic-baseline-language
|
||||
text="24px app-text-grey"
|
||||
/>
|
||||
</template>
|
||||
{{ 'Website' }}
|
||||
</ProjectOpenessLink>
|
||||
<ProjectOpenessLink
|
||||
v-if="project.links?.blog"
|
||||
:to="project.links.blog"
|
||||
>
|
||||
<template #prefix>
|
||||
<UnoIcon i-web-website />
|
||||
</template>
|
||||
{{ 'Blog' }}
|
||||
Website
|
||||
</ProjectOpenessLink>
|
||||
<ProjectOpenessLink
|
||||
v-if="project.links?.github"
|
||||
|
@ -69,12 +136,25 @@ defineProps<{
|
|||
>
|
||||
<template #prefix>
|
||||
<UnoIcon
|
||||
i-web-github
|
||||
opacity-30
|
||||
i-mdi-github
|
||||
text="24px app-text-grey"
|
||||
text-27px
|
||||
/>
|
||||
</template>
|
||||
{{ 'Github' }}
|
||||
Github
|
||||
</ProjectOpenessLink>
|
||||
<ProjectOpenessLink
|
||||
v-if="project.links?.whitepaper"
|
||||
:to="project.links?.whitepaper"
|
||||
>
|
||||
<template #prefix>
|
||||
<UnoIcon
|
||||
i-material-symbols-description
|
||||
text="24px app-text-grey"
|
||||
text-27px
|
||||
/>
|
||||
</template>
|
||||
Whitepaper
|
||||
</ProjectOpenessLink>
|
||||
<ProjectOpenessLink
|
||||
v-if="project.links?.docs"
|
||||
|
@ -82,11 +162,38 @@ defineProps<{
|
|||
>
|
||||
<template #prefix>
|
||||
<UnoIcon
|
||||
i-web-documents
|
||||
text-24px
|
||||
i-material-symbols-contract
|
||||
text="24px app-text-grey"
|
||||
text-27px
|
||||
/>
|
||||
</template>
|
||||
{{ 'Docs' }}
|
||||
Docs
|
||||
</ProjectOpenessLink>
|
||||
<ProjectOpenessLink
|
||||
v-if="project.links?.blog"
|
||||
:to="project.links.blog"
|
||||
>
|
||||
<template #prefix>
|
||||
<UnoIcon
|
||||
i-material-symbols-newsmode
|
||||
text="24px app-text-grey"
|
||||
text-27px
|
||||
/>
|
||||
</template>
|
||||
Blog
|
||||
</ProjectOpenessLink>
|
||||
<ProjectOpenessLink
|
||||
v-if="project.links?.forum"
|
||||
:to="project.links.forum"
|
||||
>
|
||||
<template #prefix>
|
||||
<UnoIcon
|
||||
i-material-symbols-forum-outline
|
||||
text="24px app-text-grey"
|
||||
text-27px
|
||||
/>
|
||||
</template>
|
||||
Forum
|
||||
</ProjectOpenessLink>
|
||||
<ProjectOpenessLink
|
||||
v-if="project.links?.block_explorer"
|
||||
|
@ -94,48 +201,25 @@ defineProps<{
|
|||
>
|
||||
<template #prefix>
|
||||
<UnoIcon
|
||||
i-web-explorer
|
||||
opacity-30
|
||||
i-material-symbols-explore-outline
|
||||
text="24px app-text-grey"
|
||||
text-27px
|
||||
/>
|
||||
</template>
|
||||
{{ 'Explorer' }}
|
||||
Explorer
|
||||
</ProjectOpenessLink>
|
||||
<ProjectOpenessLink
|
||||
v-if="project.links?.snapshot"
|
||||
:to="project.links.snapshot"
|
||||
v-if="project.links?.governance"
|
||||
:to="project.links.governance"
|
||||
>
|
||||
<template #prefix>
|
||||
<UnoIcon
|
||||
i-web-snapshot
|
||||
text-32px
|
||||
i-material-symbols-how-to-vote-outline
|
||||
text="24px app-text-grey"
|
||||
text-27px
|
||||
/>
|
||||
</template>
|
||||
{{ 'Snapshot' }}
|
||||
</ProjectOpenessLink>
|
||||
<ProjectOpenessLink
|
||||
v-if="project.links?.token"
|
||||
:to="project.links.token"
|
||||
>
|
||||
<template #prefix>
|
||||
<UnoIcon
|
||||
i-web-token
|
||||
text-28px
|
||||
/>
|
||||
</template>
|
||||
{{ 'Token' }}
|
||||
</ProjectOpenessLink>
|
||||
<ProjectOpenessLink
|
||||
v-if="project.links?.coingecko"
|
||||
:to="project.links.coingecko"
|
||||
>
|
||||
<template #prefix>
|
||||
<UnoIcon
|
||||
i-web-coingecko
|
||||
opacity-30
|
||||
text-24px
|
||||
/>
|
||||
</template>
|
||||
{{ 'Coingecko' }}
|
||||
Governance
|
||||
</ProjectOpenessLink>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -149,22 +233,22 @@ defineProps<{
|
|||
<div
|
||||
grid
|
||||
grid-cols-2
|
||||
gap-16px
|
||||
gap-x-16px
|
||||
gap-y-12px
|
||||
mt-8px
|
||||
lg:grid-cols-4
|
||||
>
|
||||
<ProjectOpenessLink
|
||||
v-if="project.links?.forum"
|
||||
:to="project.links.forum"
|
||||
v-if="project.links?.twitter"
|
||||
:to="project.links.twitter"
|
||||
>
|
||||
<template #prefix>
|
||||
<UnoIcon
|
||||
i-web-forum
|
||||
opacity-30
|
||||
text-28px
|
||||
i-bi-twitter-x
|
||||
text="24px app-text-grey"
|
||||
/>
|
||||
</template>
|
||||
{{ 'Forum' }}
|
||||
Twitter
|
||||
</ProjectOpenessLink>
|
||||
<ProjectOpenessLink
|
||||
v-if="project.links?.discord"
|
||||
|
@ -172,24 +256,23 @@ defineProps<{
|
|||
>
|
||||
<template #prefix>
|
||||
<UnoIcon
|
||||
i-web-discord
|
||||
text-27px
|
||||
i-ic-baseline-discord
|
||||
text="24px app-text-grey"
|
||||
/>
|
||||
</template>
|
||||
{{ 'Discord' }}
|
||||
Discord
|
||||
</ProjectOpenessLink>
|
||||
<ProjectOpenessLink
|
||||
v-if="project.links?.twitter"
|
||||
:to="project.links.twitter"
|
||||
v-if="project.links?.telegram"
|
||||
:to="project.links.telegram"
|
||||
>
|
||||
<template #prefix>
|
||||
<UnoIcon
|
||||
i-web-twitter_x
|
||||
opacity-30
|
||||
text-22px
|
||||
i-mdi-telegram
|
||||
text="24px app-text-grey"
|
||||
/>
|
||||
</template>
|
||||
{{ 'Twitter' }}
|
||||
Telegram
|
||||
</ProjectOpenessLink>
|
||||
<ProjectOpenessLink
|
||||
v-if="project.links?.lens"
|
||||
|
@ -198,10 +281,10 @@ defineProps<{
|
|||
<template #prefix>
|
||||
<UnoIcon
|
||||
i-web-lens
|
||||
text-32px
|
||||
text="24px app-text-grey"
|
||||
/>
|
||||
</template>
|
||||
{{ 'Lens' }}
|
||||
Lens
|
||||
</ProjectOpenessLink>
|
||||
<ProjectOpenessLink
|
||||
v-if="project.links?.farcaster"
|
||||
|
@ -210,89 +293,63 @@ defineProps<{
|
|||
<template #prefix>
|
||||
<UnoIcon
|
||||
i-web-farcaster
|
||||
text-26px
|
||||
text="24px app-text-grey"
|
||||
/>
|
||||
</template>
|
||||
{{ 'Farcaster' }}
|
||||
</ProjectOpenessLink>
|
||||
<ProjectOpenessLink
|
||||
v-if="project.links?.telegram"
|
||||
:to="project.links.telegram"
|
||||
>
|
||||
<template #prefix>
|
||||
<UnoIcon
|
||||
i-web-telegram
|
||||
opacity-30
|
||||
text-22px
|
||||
/>
|
||||
</template>
|
||||
{{ 'Telegram' }}
|
||||
Farcaster
|
||||
</ProjectOpenessLink>
|
||||
</div>
|
||||
</div>
|
||||
<div mt-24px>
|
||||
<ProjectOpenessTeamMembers :members="project.team" />
|
||||
</div>
|
||||
<div
|
||||
grid
|
||||
grid-cols-2
|
||||
items-start
|
||||
mt-32px
|
||||
gap-y-26px
|
||||
lg:grid-cols-4
|
||||
>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.product_launch_day"
|
||||
title="Product launch day"
|
||||
<ProjectOpenessTeamMembers
|
||||
v-if="project?.team"
|
||||
:members="project.team"
|
||||
mt-24px
|
||||
/>
|
||||
<div mt-32px>
|
||||
<h3
|
||||
text="app-text-grey 14px lg:16px"
|
||||
leading-24px
|
||||
>
|
||||
{{ project.product_launch_day }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
title="Opensource"
|
||||
bold
|
||||
:check-undefined="project.blockchain_features?.opensource"
|
||||
:color=" project.blockchain_features?.opensource ? '#A8FF18' : '#FF0000'"
|
||||
>
|
||||
{{ project.blockchain_features?.opensource ? 'Yes' : 'No' }}
|
||||
</ProjectInfoItem>
|
||||
</div>
|
||||
<div
|
||||
mt-32px
|
||||
w-full
|
||||
>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.funding"
|
||||
title="Funding"
|
||||
bold
|
||||
Funding
|
||||
</h3>
|
||||
<div
|
||||
v-for="funding of project.funding"
|
||||
:key="funding.name"
|
||||
flex
|
||||
items-center
|
||||
justify-between
|
||||
rounded-full
|
||||
w-full
|
||||
bg-app-bg-funding-card
|
||||
px-24px
|
||||
py-12px
|
||||
mt-12px
|
||||
>
|
||||
<template
|
||||
v-for="fund in project.funding"
|
||||
:key="fund.name"
|
||||
<h3
|
||||
text="14px lg:16px"
|
||||
leading="20px lg:24px"
|
||||
font-700
|
||||
>
|
||||
<div
|
||||
mt-16px
|
||||
grid
|
||||
grid-cols-2
|
||||
sm:grid-cols-4
|
||||
>
|
||||
<span v-if="fund.name">{{ fund.name }}</span>
|
||||
<span
|
||||
v-if="fund.time"
|
||||
font-400
|
||||
>{{ fund.time }}</span>
|
||||
<span
|
||||
v-if="fund.time"
|
||||
font-400
|
||||
text-app-text-grey
|
||||
>{{ fund.type }}</span>
|
||||
<span
|
||||
v-if="fund.time"
|
||||
font-400
|
||||
>{{ fund.value }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</ProjectInfoItem>
|
||||
{{ funding.name }}
|
||||
</h3>
|
||||
<NuxtLink
|
||||
:to="funding.link"
|
||||
external
|
||||
target="_blank"
|
||||
>
|
||||
<UnoIcon
|
||||
i-ic-twotone-open-in-new
|
||||
text="22px app-text-grey"
|
||||
/>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<h3
|
||||
v-if="!project.funding?.length"
|
||||
text="app-text-grey 14px lg:16px"
|
||||
leading-24px
|
||||
>
|
||||
N/A
|
||||
</h3>
|
||||
</div>
|
||||
</ProjectDetailContainer>
|
||||
</template>
|
||||
|
|
|
@ -32,58 +32,32 @@ const props = defineProps<{
|
|||
>
|
||||
<div
|
||||
flex
|
||||
items-center
|
||||
gap-12px
|
||||
>
|
||||
<template v-if="member.link">
|
||||
<!-- <template v-if="member.link">
|
||||
<NuxtImg
|
||||
:src="member.link"
|
||||
width="48"
|
||||
height="48"
|
||||
:alt="member.name"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<svg
|
||||
width="48"
|
||||
height="48"
|
||||
viewBox="0 0 48 48"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle
|
||||
opacity="0.2"
|
||||
cx="24"
|
||||
cy="24"
|
||||
r="23.5"
|
||||
stroke="white"
|
||||
/>
|
||||
<g opacity="0.2">
|
||||
<mask
|
||||
id="mask0_2200_7716"
|
||||
style="mask-type:alpha"
|
||||
maskUnits="userSpaceOnUse"
|
||||
x="12"
|
||||
y="12"
|
||||
width="24"
|
||||
height="24"
|
||||
>
|
||||
<rect
|
||||
x="12"
|
||||
y="12"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="#D9D9D9"
|
||||
/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_2200_7716)">
|
||||
<path
|
||||
d="M24 24C22.9 24 21.9583 23.6083 21.175 22.825C20.3917 22.0417 20 21.1 20 20C20 18.9 20.3917 17.9583 21.175 17.175C21.9583 16.3917 22.9 16 24 16C25.1 16 26.0417 16.3917 26.825 17.175C27.6083 17.9583 28 18.9 28 20C28 21.1 27.6083 22.0417 26.825 22.825C26.0417 23.6083 25.1 24 24 24ZM16 32V29.2C16 28.6333 16.1458 28.1125 16.4375 27.6375C16.7292 27.1625 17.1167 26.8 17.6 26.55C18.6333 26.0333 19.6833 25.6458 20.75 25.3875C21.8167 25.1292 22.9 25 24 25C25.1 25 26.1833 25.1292 27.25 25.3875C28.3167 25.6458 29.3667 26.0333 30.4 26.55C30.8833 26.8 31.2708 27.1625 31.5625 27.6375C31.8542 28.1125 32 28.6333 32 29.2V32H16Z"
|
||||
fill="white"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
||||
</template> -->
|
||||
<div
|
||||
flex
|
||||
items-center
|
||||
justify-center
|
||||
text-black
|
||||
w="40px lg:48px"
|
||||
h="40px lg:48px"
|
||||
rounded-full
|
||||
bg-app-bg-team-grey
|
||||
>
|
||||
<div
|
||||
i-heroicons-solid-user
|
||||
text-24px
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
flex
|
||||
flex-col
|
||||
|
@ -92,10 +66,6 @@ const props = defineProps<{
|
|||
text="14px sm:16px"
|
||||
font-700
|
||||
>{{ member.name }}</span>
|
||||
<span
|
||||
text="14px sm:16px app-text-grey"
|
||||
font-400
|
||||
>{{ member.role ?? 'N/A' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -12,7 +12,7 @@ defineProps<{
|
|||
badge-text="3/10"
|
||||
>
|
||||
<UnoIcon
|
||||
i-web-code_v2
|
||||
i-heroicons-solid-eye
|
||||
text-24px
|
||||
/>
|
||||
</ProjectDetailCategoryDivider>
|
||||
|
@ -26,11 +26,11 @@ defineProps<{
|
|||
lg:grid-cols-4
|
||||
>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.blockchain_features?.p2p"
|
||||
bold
|
||||
title="Peer to Peer (P2P)"
|
||||
:check-undefined="project.default_privacy"
|
||||
title="Default privacy"
|
||||
:color="project.default_privacy ? '#18FF2F' : '#FF0000'"
|
||||
>
|
||||
{{ project.blockchain_features?.p2p ? 'YES' : 'NO' }}
|
||||
{{ project.default_privacy ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.tracebility?.kyc"
|
||||
|
@ -40,109 +40,6 @@ defineProps<{
|
|||
>
|
||||
{{ project.tracebility?.kyc ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.storage"
|
||||
bold
|
||||
title="Decentralized storage"
|
||||
:color="project.storage?.decentralized ? '#18FF2F' : '#FF0000'"
|
||||
>
|
||||
{{ project.storage?.decentralized ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.default_privacy"
|
||||
title="Default privacy"
|
||||
:color="project.default_privacy ? '#18FF2F' : '#FF0000'"
|
||||
>
|
||||
{{ project.default_privacy ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
</div>
|
||||
<div
|
||||
grid
|
||||
grid-cols-2
|
||||
items-start
|
||||
mt-32px
|
||||
gap-y-16px
|
||||
lg:grid-cols-4
|
||||
>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.blockchain_features?.revealed_recipient"
|
||||
:color="project.blockchain_features?.revealed_recipient ? '#FF0000' : '#18FF2F'"
|
||||
bold
|
||||
title="Revealed recipient"
|
||||
>
|
||||
{{ project.blockchain_features?.revealed_recipient ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.blockchain_features?.revealed_sender"
|
||||
:color="project.blockchain_features?.revealed_sender ? '#FF0000' : '#18FF2F'"
|
||||
bold
|
||||
title="Revealed sender"
|
||||
>
|
||||
{{ project.blockchain_features?.revealed_sender ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.blockchain_features?.revealed_ammount"
|
||||
:color="project.blockchain_features?.revealed_ammount ? '#FF0000' : '#18FF2F'"
|
||||
bold
|
||||
title="Revealed amount"
|
||||
>
|
||||
{{ project.blockchain_features?.revealed_ammount ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.blockchain_features?.reversability_condition"
|
||||
bold
|
||||
title="Reversability"
|
||||
>
|
||||
{{ project.blockchain_features?.reversability_condition }}
|
||||
</ProjectInfoItem>
|
||||
</div>
|
||||
<div
|
||||
grid
|
||||
grid-cols-2
|
||||
items-start
|
||||
mt-32px
|
||||
gap-y-16px
|
||||
lg:grid-cols-4
|
||||
>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.blockchain_features?.connected_tx"
|
||||
:color="project.blockchain_features?.connected_tx ? '#FF0000' : '#18FF2F'"
|
||||
bold
|
||||
title="Connected Txs"
|
||||
>
|
||||
{{ project.blockchain_features?.connected_tx ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.blockchain_features?.data_masking"
|
||||
bold
|
||||
title="Data masking"
|
||||
>
|
||||
{{ project.blockchain_features?.data_masking }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.blockchain_features?.tx_history"
|
||||
bold
|
||||
title="Tx history"
|
||||
>
|
||||
{{ project.blockchain_features?.tx_history ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
</div>
|
||||
<div my-24px>
|
||||
<hr
|
||||
border-t-2px
|
||||
border-white
|
||||
opacity-20
|
||||
w-80px
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
grid
|
||||
grid-cols-2
|
||||
items-start
|
||||
mt-32px
|
||||
gap-y-16px
|
||||
lg:grid-cols-4
|
||||
>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.privacy_policy"
|
||||
:color="project.privacy_policy?.defined ? '#18FF2F' : '#FF0000'"
|
||||
|
@ -150,6 +47,31 @@ defineProps<{
|
|||
title="Privacy Policy"
|
||||
>
|
||||
{{ project.privacy_policy?.defined ? 'YES' : 'NO' }}
|
||||
<NuxtLink
|
||||
:to="project.privacy_policy?.link"
|
||||
external
|
||||
target="_blank"
|
||||
>
|
||||
<UnoIcon
|
||||
i-ic-twotone-open-in-new
|
||||
text="22px app-text-grey"
|
||||
/>
|
||||
</NuxtLink>
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.compliance"
|
||||
color="#FFB800"
|
||||
bold
|
||||
title="Compliance with"
|
||||
>
|
||||
{{ project.compliance ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.tracebility?.sign_in_type_requirments"
|
||||
bold
|
||||
title="Sign-in requirements"
|
||||
>
|
||||
{{ project.tracebility?.sign_in_type_requirments }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.tracebility?.tracked_data"
|
||||
|
@ -163,58 +85,6 @@ defineProps<{
|
|||
>
|
||||
{{ project.privacy_policy?.data_usage }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.blockchain_features?.frontend_anonymity"
|
||||
bold
|
||||
title="Frontend anonymity"
|
||||
>
|
||||
{{ project.blockchain_features?.frontend_anonymity }}
|
||||
</ProjectInfoItem>
|
||||
</div>
|
||||
<div my-24px>
|
||||
<hr
|
||||
border-t-2px
|
||||
border-white
|
||||
opacity-20
|
||||
w-80px
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
grid
|
||||
grid-cols-2
|
||||
items-start
|
||||
mt-32px
|
||||
gap-y-16px
|
||||
>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.compliance"
|
||||
:color="project.compliance ? '#FF0000' : '#18FF2F'"
|
||||
bold
|
||||
title="Compliance"
|
||||
>
|
||||
{{ project.compliance ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
</div>
|
||||
<div
|
||||
grid
|
||||
grid-cols-2
|
||||
items-start
|
||||
mt-32px
|
||||
gap-y-16px
|
||||
>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.tracebility?.sign_in_type_requirments"
|
||||
bold
|
||||
title="Sign-in requirements"
|
||||
>
|
||||
{{ project.tracebility?.sign_in_type_requirments }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.blockchain_features?.identity_integration"
|
||||
title="Identity integrations"
|
||||
>
|
||||
{{ project.blockchain_features?.identity_integration }}
|
||||
</ProjectInfoItem>
|
||||
</div>
|
||||
</ProjectDetailContainer>
|
||||
</template>
|
||||
|
|
131
components/Project/ProjectRating.vue
Normal file
131
components/Project/ProjectRating.vue
Normal file
|
@ -0,0 +1,131 @@
|
|||
<script lang="ts" setup>
|
||||
import type { ProjectRating } from '~/types'
|
||||
|
||||
// Define props for score
|
||||
const props = defineProps<{
|
||||
rating: ProjectRating
|
||||
percentage: number
|
||||
compact?: boolean
|
||||
}>()
|
||||
|
||||
const colors = [
|
||||
'#ff0000', // 0-10%
|
||||
'#ff4500', // 11-20%
|
||||
'#ff8c00', // 21-30%
|
||||
'#ffd700', // 31-40%
|
||||
'#adff2f', // 41-50%
|
||||
'#7fff00', // 51-60%
|
||||
'#00ff00', // 61-70%
|
||||
'#32cd32', // 71-80%
|
||||
'#00fa9a', // 81-90%
|
||||
'#00ffff', // 91-100%
|
||||
]
|
||||
|
||||
const backgroundColorByScore = computed(() => {
|
||||
const normalizedPercentage = Math.min(Math.max(props.percentage, 0), 100)
|
||||
const colorIndex = Math.floor(normalizedPercentage / 10)
|
||||
return colors[colorIndex]
|
||||
})
|
||||
|
||||
const isPopoverVisible = ref(false)
|
||||
|
||||
let hideTimeout: ReturnType<typeof setTimeout> | null = null
|
||||
const showPopover = () => {
|
||||
if (hideTimeout) {
|
||||
clearTimeout(hideTimeout)
|
||||
hideTimeout = null
|
||||
}
|
||||
isPopoverVisible.value = true
|
||||
}
|
||||
|
||||
const hidePopover = () => {
|
||||
hideTimeout = setTimeout(() => {
|
||||
isPopoverVisible.value = false
|
||||
}, 100) // Delay of 200ms before hiding
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative">
|
||||
<!-- Main div that shows rating and triggers the popover on hover -->
|
||||
<div
|
||||
flex
|
||||
items-center
|
||||
p-12px
|
||||
gap-4px
|
||||
hover:bg-app-bg-rating-hover
|
||||
hover:rounded-8px
|
||||
@mouseenter="showPopover"
|
||||
@mouseleave="hidePopover"
|
||||
>
|
||||
<div
|
||||
v-for="point of [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]"
|
||||
:key="point"
|
||||
:style="`background-color: ${percentage >= point * 10 ? backgroundColorByScore : '#494949'}`"
|
||||
:class="[compact ? 'h-8px lg:h-10px w-4px lg:w-5px' : 'w-5px lg:w-6px h-10px lg:h-12px', point % 2 === 0 ? 'rounded-l-2px' : 'rounded-r-2px ml--4px', 'bg-app-bg-rating-default']"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Popover panel that appears on hover -->
|
||||
<transition
|
||||
enter-active-class="transition duration-300 ease-out"
|
||||
enter-from-class="transform scale-95 opacity-0"
|
||||
enter-to-class="transform scale-100 opacity-100"
|
||||
leave-active-class="transition duration-200 ease-in"
|
||||
leave-from-class="transform scale-100 opacity-100"
|
||||
leave-to-class="transform scale-95 opacity-0"
|
||||
>
|
||||
<div
|
||||
v-if="isPopoverVisible"
|
||||
class="absolute mt-2 p-2 bg-app-bg-rating-hover w-240px shadow-lg rounded"
|
||||
z-100
|
||||
style="left: 50%; transform: translateX(-50%);"
|
||||
flex
|
||||
flex-col
|
||||
gap-14px
|
||||
px-16px
|
||||
py-10px
|
||||
@mouseenter="showPopover"
|
||||
@mouseleave="hidePopover"
|
||||
>
|
||||
<div
|
||||
v-for="item in rating.items"
|
||||
:key="item.label"
|
||||
flex
|
||||
justify-between
|
||||
items-center
|
||||
text-12px
|
||||
font-700
|
||||
leading-20px
|
||||
:class="[item.isValid ? 'text-app-white': 'text-app-text-rating-negative']"
|
||||
>
|
||||
<div
|
||||
flex
|
||||
items-center
|
||||
gap-6px
|
||||
>
|
||||
<div
|
||||
:class="[item.isValid ? 'i-ic-sharp-thumb-up' : 'i-ic-sharp-thumb-down']"
|
||||
text-20px
|
||||
mt--4px
|
||||
/>
|
||||
{{ item.label }}
|
||||
</div>
|
||||
<NuxtLink
|
||||
v-if="item.isValid && item.positive === 'Link'"
|
||||
:to="item.value"
|
||||
target="_blank"
|
||||
external
|
||||
underline
|
||||
@click.stop
|
||||
>
|
||||
{{ item.positive }}
|
||||
</NuxtLink>
|
||||
<div v-else>
|
||||
{{ item.isValid ? item.positive : item.negative }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
|
@ -12,11 +12,36 @@ defineProps<{
|
|||
badge-text="3/10"
|
||||
>
|
||||
<UnoIcon
|
||||
i-web-code_v2
|
||||
i-material-symbols-lock-outline
|
||||
text-24px
|
||||
/>
|
||||
</ProjectDetailCategoryDivider>
|
||||
<ProjectDetailContainer>
|
||||
<div v-if="project.audits">
|
||||
<h2
|
||||
text-18px
|
||||
text-app-text-grey
|
||||
my-24px
|
||||
>
|
||||
Audits
|
||||
</h2>
|
||||
<div
|
||||
flex
|
||||
flex-col
|
||||
gap="12px lg:16px"
|
||||
>
|
||||
<template
|
||||
v-for="audit in project.audits"
|
||||
:key="audit.name"
|
||||
>
|
||||
<ProjectSecurityAudit
|
||||
:audit-name="audit.name"
|
||||
:audit-url="audit.link"
|
||||
:date="audit.time"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
grid
|
||||
grid-cols-2
|
||||
|
@ -26,20 +51,11 @@ defineProps<{
|
|||
lg:grid-cols-4
|
||||
>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.blockchain_features?.asset_custody_type"
|
||||
bold
|
||||
title="Asset custody"
|
||||
:check-undefined="project.technical_spof"
|
||||
:color="project.technical_spof ? '#FF0000' : '#18FF2F'"
|
||||
title="Technical dependency"
|
||||
>
|
||||
{{ project.blockchain_features?.asset_custody_type }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.blockchain_features?.upgradability"
|
||||
title="Upgradability"
|
||||
>
|
||||
<b :color="project.blockchain_features?.upgradability?.enabled ? '#FF0000' : '#18FF2F'">
|
||||
{{ project.blockchain_features?.upgradability?.enabled ? 'YES' : 'NO' }}
|
||||
</b>
|
||||
{{ ` – ${project.blockchain_features?.upgradability?.type}` }}
|
||||
{{ project.technical_spof }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.social_trust"
|
||||
|
@ -55,47 +71,6 @@ defineProps<{
|
|||
>
|
||||
{{ project.third_party_dependency ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.technical_spof"
|
||||
:color="project.technical_spof ? '#FF0000' : '#18FF2F'"
|
||||
title="Technical dependency"
|
||||
>
|
||||
{{ project.technical_spof }}
|
||||
</ProjectInfoItem>
|
||||
</div>
|
||||
<div my-24px>
|
||||
<hr
|
||||
border-t-2px
|
||||
border-white
|
||||
opacity-20
|
||||
w-80px
|
||||
>
|
||||
</div>
|
||||
<div v-if="project.audits">
|
||||
<h2
|
||||
text-18px
|
||||
text-app-text-grey
|
||||
my-24px
|
||||
>
|
||||
Audits
|
||||
</h2>
|
||||
<template
|
||||
v-for="audit in project.audits"
|
||||
:key="audit.name"
|
||||
>
|
||||
<ProjectSecurityAudit
|
||||
:audit-name="audit.name"
|
||||
:audit-url="audit.link"
|
||||
:date="audit.time"
|
||||
>
|
||||
<NuxtImg
|
||||
:src="audit.logo ?? '/no-image-1-1.svg'"
|
||||
w-64px
|
||||
h-64px
|
||||
object-cover
|
||||
/>
|
||||
</ProjectSecurityAudit>
|
||||
</template>
|
||||
</div>
|
||||
</ProjectDetailContainer>
|
||||
</template>
|
||||
|
|
|
@ -9,36 +9,69 @@ defineProps<{
|
|||
<template>
|
||||
<div
|
||||
flex
|
||||
items-center
|
||||
gap-16px
|
||||
justify-between
|
||||
lg:grid
|
||||
lg:grid-cols-2
|
||||
rounded-full
|
||||
py-12px
|
||||
px-16px
|
||||
bg-app-bg-audits-card
|
||||
>
|
||||
<slot />
|
||||
<div
|
||||
flex
|
||||
flex-col
|
||||
text-14px
|
||||
font-700
|
||||
leading-24px
|
||||
grid
|
||||
grid-cols-3
|
||||
w-full
|
||||
>
|
||||
<NuxtLink
|
||||
hover:underline
|
||||
flex
|
||||
items-center
|
||||
gap-8px
|
||||
:to="auditUrl"
|
||||
<h2
|
||||
text="14px lg:16px"
|
||||
leading-20px
|
||||
font-700
|
||||
col-span="3 lg:2"
|
||||
>
|
||||
{{ auditName }}
|
||||
<UnoIcon
|
||||
v-if="auditUrl"
|
||||
i-web-openinnew
|
||||
text-16px
|
||||
/>
|
||||
</NuxtLink>
|
||||
<span
|
||||
</h2>
|
||||
<h2
|
||||
text-14px
|
||||
font-400
|
||||
leading-24px
|
||||
>{{ date }}</span>
|
||||
leading-20px
|
||||
hidden
|
||||
lg:block
|
||||
>
|
||||
Overview of smart contracts
|
||||
</h2>
|
||||
</div>
|
||||
<div
|
||||
flex
|
||||
items-center
|
||||
justify-end
|
||||
gap="16px lg:80px"
|
||||
whitespace-nowrap
|
||||
>
|
||||
<h2
|
||||
text-14px
|
||||
leading-20px
|
||||
>
|
||||
{{ date ? formatDate(date) : 'N/A' }}
|
||||
</h2>
|
||||
<NuxtLink
|
||||
flex
|
||||
items-center
|
||||
gap-4px
|
||||
:to="auditUrl"
|
||||
external
|
||||
target="_blank"
|
||||
text-14px
|
||||
text-app-text-grey
|
||||
leading-20px
|
||||
hover:underline
|
||||
><p
|
||||
hidden
|
||||
lg:block
|
||||
>
|
||||
More info
|
||||
</p> <UnoIcon
|
||||
i-ic-twotone-open-in-new
|
||||
text-22px
|
||||
/></NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -12,7 +12,7 @@ defineProps<{
|
|||
badge-text="3/10"
|
||||
>
|
||||
<UnoIcon
|
||||
i-web-code_v2
|
||||
i-material-symbols-deployed-code-outline
|
||||
text-24px
|
||||
/>
|
||||
</ProjectDetailCategoryDivider>
|
||||
|
@ -21,100 +21,54 @@ defineProps<{
|
|||
grid
|
||||
grid-cols-2
|
||||
items-start
|
||||
mt-32px
|
||||
mt-24px
|
||||
gap-y-16px
|
||||
lg:grid-cols-4
|
||||
>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.blockchain_features?.opensource"
|
||||
title="Opensource"
|
||||
bold
|
||||
:color="project.blockchain_features?.opensource ? '#18FF2F' : '#FF0000'"
|
||||
>
|
||||
{{ project.blockchain_features?.opensource ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.blockchain_features?.asset_custody_type"
|
||||
title="Asset custody"
|
||||
:color="project.blockchain_features?.asset_custody_type === 'non-custody' ? '#18FF2F' : project.blockchain_features?.asset_custody_type === 'multisig' ? '#FFB800' : '#FF0000'"
|
||||
bold
|
||||
>
|
||||
{{ project.blockchain_features?.asset_custody_type.toUpperCase() }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
title="Upgradability"
|
||||
bold
|
||||
:check-undefined="project.blockchain_features?.upgradability"
|
||||
:color="project.blockchain_features?.upgradability ? '#FF0000' : '#18FF2F' "
|
||||
>
|
||||
{{ project.blockchain_features?.upgradability ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.technology?.type"
|
||||
title="Technology type"
|
||||
bold
|
||||
>
|
||||
{{ project.technology?.type }}
|
||||
{{ project.technology?.type.toUpperCase() }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.blockchain_features?.encryption"
|
||||
title="Encryption"
|
||||
:check-undefined="project.blockchain_features?.p2p"
|
||||
title="Peer to Peer (P2P)"
|
||||
bold
|
||||
>
|
||||
{{ project.blockchain_features?.encryption }}
|
||||
{{ project.blockchain_features?.p2p ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
title="License"
|
||||
bold
|
||||
:check-undefined="project.licences"
|
||||
>
|
||||
{{ project.licences }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.links?.whitepaper"
|
||||
title="Whitepaper"
|
||||
bold
|
||||
:link="project.links?.whitepaper"
|
||||
>
|
||||
{{ project.links?.whitepaper ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
</div>
|
||||
<div
|
||||
grid
|
||||
grid-cols-1
|
||||
items-start
|
||||
mt-16px
|
||||
gap-y-16px
|
||||
lg:grid-cols-4
|
||||
>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.project_status"
|
||||
title="Version"
|
||||
:check-undefined="project.storage?.decentralized"
|
||||
title="Decentralized storage"
|
||||
bold
|
||||
>
|
||||
<div
|
||||
v-if="project.project_status?.live_status"
|
||||
flex
|
||||
items-center
|
||||
gap-12px
|
||||
>
|
||||
<UnoIcon
|
||||
i-web-live
|
||||
text-10px
|
||||
class="color-#B5E26B"
|
||||
/>
|
||||
<span>{{ `Live on ${project.project_status.version}` }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
flex
|
||||
items-center
|
||||
gap-12px
|
||||
>
|
||||
<UnoIcon
|
||||
i-web-live
|
||||
text-10px
|
||||
class="color-#e26b6b"
|
||||
/>
|
||||
<span>{{ 'Offline' }}</span>
|
||||
</div>
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.technology?.features"
|
||||
title="Features"
|
||||
bold
|
||||
>
|
||||
{{ project.technology?.features.join(', ') }}
|
||||
</ProjectInfoItem>
|
||||
<ProjectInfoItem
|
||||
:check-undefined="project.client_diversability"
|
||||
title="Client diversability"
|
||||
bold
|
||||
>
|
||||
<template
|
||||
v-for="item in project.client_diversability"
|
||||
:key="item.name"
|
||||
>
|
||||
<NuxtLink :to="item.link">
|
||||
{{ item.name }}
|
||||
</NuxtLink><br>
|
||||
</template>
|
||||
{{ project.storage?.decentralized ? 'YES' : 'NO' }}
|
||||
</ProjectInfoItem>
|
||||
</div>
|
||||
</ProjectDetailContainer>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -33,7 +33,7 @@ const selectedValue = useVModel(props, 'modelValue', emits)
|
|||
<span class="block truncate mr-8px">{{ props.options.find(option => option.value === selectedValue)?.label }}</span>
|
||||
<span class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
||||
<UnoIcon
|
||||
i-heroicons-solid-chevron-down
|
||||
i-ic-baseline-arrow-drop-down
|
||||
:class="[blackAndWhite ? ' text-app-white' : 'text-app-black']"
|
||||
/>
|
||||
</span>
|
||||
|
|
|
@ -1,23 +1,45 @@
|
|||
import type { Category, Project, ProjectShallow } from '~/types'
|
||||
import type { Category, Project, ProjectRating, ProjectRatingItem, ProjectShallow } from '~/types'
|
||||
import type { Asset } from '~/types/asset'
|
||||
import type { Ecosystem } from '~/types/ecosystem'
|
||||
import type { Feature } from '~/types/feature'
|
||||
import type { Rank } from '~/types/rank'
|
||||
import type { Usecase } from '~/types/usecase'
|
||||
|
||||
export const useData = defineStore('data', () => {
|
||||
const categories = useState<Category[]>('categories')
|
||||
const usecases = useState<Usecase[]>('usecases')
|
||||
const features = useState<Feature[]>('features')
|
||||
const assets = useState<Asset[]>('assets')
|
||||
const ecosystems = useState<Ecosystem[]>('ecosystems')
|
||||
const projects = useState<Project[]>('projects')
|
||||
const selectedCategoryId = useState(() => 'defi')
|
||||
const ranks = useState<Rank[]>('ranks')
|
||||
|
||||
const selectedCategoryId = useState(() => 'all')
|
||||
const selectedUsecaseId = useState(() => 'all')
|
||||
const selectedEcosystemId = useState(() => 'all')
|
||||
const selectedAssetsUsedId = useState(() => 'all')
|
||||
const selectedFeaturesId = useState(() => 'all')
|
||||
|
||||
const filter = reactive({
|
||||
query: '',
|
||||
sortby: 'atoz',
|
||||
sortby: 'score',
|
||||
sortDirection: 'desc',
|
||||
})
|
||||
const switcher = ref(true)
|
||||
|
||||
watch(selectedCategoryId, () => {
|
||||
if (selectedCategoryId.value !== 'all')
|
||||
watch([selectedCategoryId, selectedUsecaseId, selectedEcosystemId, selectedAssetsUsedId, selectedFeaturesId], () => {
|
||||
if (selectedCategoryId.value !== 'all' || selectedUsecaseId.value !== 'all' || selectedEcosystemId.value !== 'all' || selectedAssetsUsedId.value !== 'all' || selectedFeaturesId.value !== 'all')
|
||||
filter.query = ''
|
||||
})
|
||||
|
||||
watch(filter, () => {
|
||||
if (filter.query !== '')
|
||||
if (filter.query !== '') {
|
||||
selectedCategoryId.value = 'all'
|
||||
selectedUsecaseId.value = 'all'
|
||||
selectedEcosystemId.value = 'all'
|
||||
selectedAssetsUsedId.value = 'all'
|
||||
selectedFeaturesId.value = 'all'
|
||||
}
|
||||
})
|
||||
|
||||
const fetchData = async () => {
|
||||
|
@ -25,20 +47,32 @@ export const useData = defineStore('data', () => {
|
|||
const data = await $fetch<{
|
||||
categories: Category[]
|
||||
projects: Project[]
|
||||
usecases: Usecase[]
|
||||
ecosystems: Ecosystem[]
|
||||
assets: Asset[]
|
||||
features: Feature[]
|
||||
ranks: Rank[]
|
||||
}>('/api/data')
|
||||
projects.value = data.projects.filter(p => p.name)
|
||||
projects.value = data.projects.map(project => ({
|
||||
...project,
|
||||
ratings: generateProjectRating(project),
|
||||
})).filter(p => p.name)
|
||||
categories.value = data.categories.map((c) => {
|
||||
c.projectsCount = projects.value.filter(p =>
|
||||
p.categories?.includes(c.id),
|
||||
).length
|
||||
return c
|
||||
}).filter(c => c.projectsCount > 0)
|
||||
usecases.value = data.usecases
|
||||
ecosystems.value = data.ecosystems
|
||||
assets.value = data.assets
|
||||
features.value = data.features
|
||||
ranks.value = data.ranks
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -57,7 +91,7 @@ export const useData = defineStore('data', () => {
|
|||
id: project.id,
|
||||
title1: project.name,
|
||||
description: project.description ?? 'N/A',
|
||||
percentage: Math.floor(Math.random() * 91),
|
||||
percentage: Math.round((project.ratings?.reduce((a, b) => a + b.points, 0) || 0) / 1.5),
|
||||
forum: project.links?.forum,
|
||||
explorer: project.links?.block_explorer,
|
||||
twitter: project.links?.twitter,
|
||||
|
@ -72,15 +106,33 @@ export const useData = defineStore('data', () => {
|
|||
support: availableSupport(),
|
||||
image: project.logos?.[0]?.url ?? '',
|
||||
anonymity: true,
|
||||
categories: project.categories,
|
||||
usecases: project.usecases,
|
||||
ecosystem: project.ecosystem,
|
||||
assets_used: project.assets_used,
|
||||
ratings: project.ratings,
|
||||
}
|
||||
}
|
||||
const shallowProjects = computed(() => projects.value.map(project => projectToShallow(project)))
|
||||
|
||||
const getProjectsByCategory = <T extends ProjectShallow>(id: string, options?: { shallow: boolean }): T[] => {
|
||||
if (id === 'all')
|
||||
return projects.value.map(project => projectToShallow(project)) as T[]
|
||||
else
|
||||
return projects.value.filter(project => project.categories?.includes(id)).map(project => options?.shallow ? projectToShallow(project) : project) as T[]
|
||||
const getProjectsByFilters = <T extends ProjectShallow>(options?: { shallow: boolean }): T[] => {
|
||||
const filteredProjects = projects.value
|
||||
.filter(project =>
|
||||
selectedCategoryId.value !== 'all' ? project.categories.includes(selectedCategoryId.value) : true,
|
||||
)
|
||||
.filter(project =>
|
||||
selectedUsecaseId.value !== 'all' ? project.usecases?.map(u => u.toLowerCase()).includes(selectedUsecaseId.value.toLowerCase()) : true,
|
||||
)
|
||||
.filter(project =>
|
||||
selectedEcosystemId.value !== 'all' ? project.ecosystem?.map(e => e.toLowerCase()).includes(selectedEcosystemId.value.toLowerCase()) : true,
|
||||
)
|
||||
.filter(project =>
|
||||
selectedAssetsUsedId.value !== 'all' ? project.assets_used?.map(a => a.toLowerCase()).includes(selectedAssetsUsedId.value.toLowerCase()) : true,
|
||||
)
|
||||
.filter(project =>
|
||||
selectedFeaturesId.value !== 'all' ? project.technology?.features?.map(f => f.toLowerCase()).includes(selectedFeaturesId.value.toLowerCase()) : true,
|
||||
)
|
||||
return (filteredProjects.map(project => options?.shallow ? projectToShallow(project) : project) as T[])
|
||||
}
|
||||
|
||||
const getProjectById = <T extends Project | ProjectShallow>(id: string, options?: { shallow: boolean }): T => {
|
||||
|
@ -94,7 +146,7 @@ export const useData = defineStore('data', () => {
|
|||
|
||||
const query = filter.query.toLowerCase()
|
||||
|
||||
const filteredShallowProjects = getProjectsByCategory(selectedCategoryId.value, { shallow: true })
|
||||
const filteredShallowProjects = getProjectsByFilters({ shallow: true })
|
||||
.filter((project) => {
|
||||
return (
|
||||
project
|
||||
|
@ -108,29 +160,123 @@ export const useData = defineStore('data', () => {
|
|||
return true
|
||||
}).sort((a, b) => {
|
||||
if (filter.sortby === 'score')
|
||||
return b.percentage - a.percentage
|
||||
if (filter.sortby === 'atoz')
|
||||
return a.title1.localeCompare(b.title1)
|
||||
if (filter.sortDirection === 'asc')
|
||||
return a.percentage - b.percentage
|
||||
else
|
||||
return b.percentage - a.percentage
|
||||
if (filter.sortby === 'title')
|
||||
if (filter.sortDirection === 'asc')
|
||||
return a.title1.toLowerCase().localeCompare(b.title1.toLowerCase())
|
||||
else
|
||||
return b.title1.toLowerCase().localeCompare(a.title1.toLowerCase())
|
||||
if (filter.sortby === 'openess' || filter.sortby === 'technology' || filter.sortby === 'privacy') {
|
||||
const scoreA = a.ratings?.find(r => r.type === filter.sortby)?.points || 0
|
||||
const scoreB = b.ratings?.find(r => r.type === filter.sortby)?.points || 0
|
||||
if (filter.sortDirection === 'asc')
|
||||
return scoreB - scoreA
|
||||
else
|
||||
return scoreA - scoreB
|
||||
}
|
||||
else
|
||||
return 0
|
||||
})
|
||||
|
||||
return filteredShallowProjects
|
||||
})
|
||||
|
||||
const groupedProjectsPerCategory = computed(() => {
|
||||
const groupedProjects = categories.value.map((category) => {
|
||||
// Find all projects that include this category
|
||||
const projectsInCategory = filteredProjects.value.filter(project =>
|
||||
project.categories.includes(category.id),
|
||||
)
|
||||
|
||||
return {
|
||||
title: category.name,
|
||||
projects: projectsInCategory,
|
||||
}
|
||||
}).sort((a, b) => b.projects.length - a.projects.length)
|
||||
|
||||
return groupedProjects
|
||||
})
|
||||
|
||||
const filteredProjectsCount = computed(() => filteredProjects.value.length)
|
||||
|
||||
const getNestedField = (project: Project, field: string) => {
|
||||
const fields = field.split('.')
|
||||
|
||||
return fields.reduce((acc: any, curr: string) => {
|
||||
return acc && acc[curr as keyof typeof acc]
|
||||
}, project)
|
||||
}
|
||||
|
||||
const generateProjectRating = (project: Project) => {
|
||||
const projectRatings: ProjectRating[] = ranks.value?.map((rank) => {
|
||||
let rankPoints = 0
|
||||
|
||||
const ratingStats: ProjectRatingItem[] = rank.references?.map((ref) => {
|
||||
let isValid = false
|
||||
const field = ref.field.includes('.') ? getNestedField(project, ref.field) : project[ref.field]
|
||||
|
||||
let value
|
||||
let positive
|
||||
|
||||
if (ref.condition.minLength) {
|
||||
value = (field as any[])?.length
|
||||
if (value) {
|
||||
isValid = value >= ref.condition.minLength
|
||||
positive = `${value} ${ref.label.positive}${value > 1 ? 's' : ''}`
|
||||
}
|
||||
}
|
||||
if (ref.condition.equals) {
|
||||
value = field
|
||||
if (value)
|
||||
isValid = value === ref.condition.equals
|
||||
}
|
||||
|
||||
if (ref.condition.exists) {
|
||||
value = field
|
||||
if (value)
|
||||
isValid = !!value
|
||||
}
|
||||
rankPoints += isValid ? ref.points : 0
|
||||
return {
|
||||
isValid,
|
||||
label: ref.label.name,
|
||||
positive: positive ? positive : ref.label.positive,
|
||||
negative: ref.label.negative,
|
||||
value,
|
||||
} as ProjectRatingItem
|
||||
})
|
||||
return {
|
||||
type: rank.id,
|
||||
name: rank.name,
|
||||
items: ratingStats,
|
||||
points: rankPoints,
|
||||
}
|
||||
})
|
||||
|
||||
return projectRatings
|
||||
}
|
||||
|
||||
return {
|
||||
selectedCategoryId,
|
||||
selectedUsecaseId,
|
||||
selectedEcosystemId,
|
||||
selectedAssetsUsedId,
|
||||
selectedFeaturesId,
|
||||
filter,
|
||||
switcher,
|
||||
categories,
|
||||
usecases,
|
||||
features,
|
||||
ecosystems,
|
||||
assets,
|
||||
projects,
|
||||
shallowProjects,
|
||||
groupedProjectsPerCategory,
|
||||
filteredProjectsCount,
|
||||
fetchData,
|
||||
getProjectById,
|
||||
getProjectsByCategory,
|
||||
filteredProjects,
|
||||
projectToShallow,
|
||||
}
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
<script lang="ts" setup>
|
||||
import type { InputOption } from '~/types'
|
||||
|
||||
const { categories, filteredProjectsCount, selectedCategoryId } = storeToRefs(useData())
|
||||
|
||||
const categoriesOptions = ref(categories.value ? categories.value.map(c => ({ label: c.name, value: c.id, count: c.projectsCount })) : [])
|
||||
const extendedOptions: InputOption[] = [
|
||||
...categoriesOptions.value,
|
||||
]
|
||||
const { categories, usecases, ecosystems, assets, features, filteredProjectsCount, selectedCategoryId, selectedUsecaseId, selectedEcosystemId, selectedAssetsUsedId, selectedFeaturesId } = storeToRefs(useData())
|
||||
|
||||
const selectedCategory = computed(() => {
|
||||
return categories.value.find(c => c.id === selectedCategoryId.value)
|
||||
})
|
||||
const availableUsecases = computed(() => {
|
||||
if (selectedCategoryId.value === 'all')
|
||||
return usecases.value
|
||||
return usecases.value.filter(u => selectedCategory.value?.usecases?.includes(u.id))
|
||||
})
|
||||
|
||||
const sortedFilteredCategories = computed(() => ([
|
||||
categories.value.find(c => c.id === 'defi')!,
|
||||
...[...categories.value].sort((a, b) => a.name.localeCompare(b.name)).filter(c => c.id !== 'defi'),
|
||||
]))
|
||||
const categoryOptions = ref<InputOption[]>(categories.value ? [{ label: 'Category', value: 'all' }, ...categories.value.map(c => ({ label: c.name, value: c.id, count: c.projectsCount }))] : [])
|
||||
const usecaseOptions = computed<InputOption[]>(() => availableUsecases.value.length ? [{ label: 'Usecase', value: 'all' }, ...availableUsecases.value.map(u => ({ label: u.name, value: u.id }))] : [])
|
||||
const ecosystemOptions = ref<InputOption[]>(ecosystems.value ? [{ label: 'Ecosystem', value: 'all' }, ...ecosystems.value.map(e => ({ label: e.name, value: e.id }))] : [])
|
||||
const assetOptions = ref<InputOption[]>(assets.value ? [{ label: 'Asset used', value: 'all' }, ...assets.value.map(a => ({ label: `${a.id.toUpperCase()} (${a.name})`, value: a.id }))] : [])
|
||||
const featureOptions = ref<InputOption[]>(features.value ? [{ label: 'Feature', value: 'all' }, ...features.value.map(f => ({ label: f.name, value: f.id }))] : [])
|
||||
|
||||
const { showBar } = storeToRefs(useNavigaiton())
|
||||
const swipeEl = ref()
|
||||
|
@ -56,77 +57,67 @@ 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:text-app-text-grey
|
||||
:placeholder="`Search in ${filteredProjectsCount} Projects`"
|
||||
/>
|
||||
<div
|
||||
xl:hidden
|
||||
block
|
||||
md:flex-2
|
||||
flex
|
||||
items-center
|
||||
gap-16px
|
||||
>
|
||||
<h2
|
||||
text-14px
|
||||
font-700
|
||||
>
|
||||
Choose category
|
||||
</h2>
|
||||
<CategorySelectBox
|
||||
v-model="selectedCategoryId"
|
||||
:options="extendedOptions"
|
||||
:options="categoryOptions"
|
||||
name="categorySelect"
|
||||
w-full
|
||||
@selected="selectedCategoryId === 'all' ? navigateTo(`/`) : navigateTo(`/category/${selectedCategoryId}`)"
|
||||
/>
|
||||
<CategorySelectBox
|
||||
v-if="usecases?.length"
|
||||
v-model="selectedUsecaseId"
|
||||
name="usecaseSelect"
|
||||
:options="usecaseOptions"
|
||||
w-full
|
||||
/>
|
||||
<CategorySelectBox
|
||||
v-if="ecosystems?.length"
|
||||
v-model="selectedEcosystemId"
|
||||
name="ecosystemSelect"
|
||||
:options="ecosystemOptions"
|
||||
w-full
|
||||
/>
|
||||
<CategorySelectBox
|
||||
v-if="assets?.length"
|
||||
v-model="selectedAssetsUsedId"
|
||||
name="assetsUsedSelect"
|
||||
:options="assetOptions"
|
||||
w-full
|
||||
/>
|
||||
<CategorySelectBox
|
||||
v-if="features?.length"
|
||||
v-model="selectedFeaturesId"
|
||||
name="featuresSelect"
|
||||
:options="featureOptions"
|
||||
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>
|
||||
|
|
11
package.json
11
package.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "develitesse-nuxt",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@9.9.0",
|
||||
"packageManager": "pnpm@9.10.0",
|
||||
"scripts": {
|
||||
"build": "nuxt build",
|
||||
"cleanup": "nuxt cleanup",
|
||||
|
@ -17,8 +17,14 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@formkit/auto-animate": "^0.8.2",
|
||||
"@iconify-json/bi": "^1.2.0",
|
||||
"@iconify-json/heroicons-outline": "^1.2.0",
|
||||
"@iconify-json/heroicons-solid": "^1.2.0",
|
||||
"@iconify-json/ic": "^1.2.0",
|
||||
"@iconify-json/iconoir": "^1.2.0",
|
||||
"@iconify-json/material-symbols": "^1.2.1",
|
||||
"@iconify-json/mdi": "^1.2.0",
|
||||
"@iconify-json/simple-icons": "^1.2.2",
|
||||
"@nuxt/devtools": "^1.4.1",
|
||||
"@nuxt/eslint": "0.5.5",
|
||||
"@nuxt/image": "^1.8.0",
|
||||
|
@ -46,5 +52,8 @@
|
|||
},
|
||||
"lint-staged": {
|
||||
"*": "eslint --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"moment": "^2.30.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts" setup>
|
||||
const dataStore = useData()
|
||||
const { selectedCategoryId, filteredProjects } = storeToRefs(dataStore)
|
||||
const { selectedCategoryId, categories, filteredProjects } = storeToRefs(dataStore)
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
|
@ -8,8 +8,10 @@ onMounted(() => {
|
|||
if (route.params.id)
|
||||
selectedCategoryId.value = route.params.id as string
|
||||
})
|
||||
|
||||
const group = computed(() => [{ title: categories.value.find(c => c.id === selectedCategoryId.value)?.name || '', projects: filteredProjects.value }])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProjectGrid :projects="filteredProjects" />
|
||||
<ProjectGrid :projects="group" />
|
||||
</template>
|
||||
|
|
|
@ -7,9 +7,11 @@ useSeoMeta({
|
|||
ogDescription: 'There are challenges in finding crucial technical details and comparing various privacy-focused projects.',
|
||||
ogImage: '/web3privacy_eye.webp',
|
||||
})
|
||||
const { filteredProjects } = storeToRefs(useData())
|
||||
const { groupedProjectsPerCategory } = storeToRefs(useData())
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProjectGrid :projects="filteredProjects" />
|
||||
<div>
|
||||
<ProjectGrid :projects="groupedProjectsPerCategory" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -32,7 +32,10 @@ useSeoMeta({
|
|||
|
||||
<template>
|
||||
<div v-if="project">
|
||||
<div app-container>
|
||||
<div
|
||||
app-container
|
||||
px-16px
|
||||
>
|
||||
<div
|
||||
flex
|
||||
flex-col
|
||||
|
@ -46,8 +49,7 @@ useSeoMeta({
|
|||
<ProjectTechnology :project="project" />
|
||||
<ProjectPrivacy :project="project" />
|
||||
<ProjectSecurity :project="project" />
|
||||
<!-- <ProjectActivity :project="project" />
|
||||
<ProjectMarket /> -->
|
||||
<ProjectHistory :project="project" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
104
pnpm-lock.yaml
104
pnpm-lock.yaml
|
@ -7,16 +7,38 @@ settings:
|
|||
importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
moment:
|
||||
specifier: ^2.30.1
|
||||
version: 2.30.1
|
||||
devDependencies:
|
||||
'@formkit/auto-animate':
|
||||
specifier: ^0.8.2
|
||||
version: 0.8.2
|
||||
'@iconify-json/bi':
|
||||
specifier: ^1.2.0
|
||||
version: 1.2.0
|
||||
'@iconify-json/heroicons-outline':
|
||||
specifier: ^1.2.0
|
||||
version: 1.2.0
|
||||
'@iconify-json/heroicons-solid':
|
||||
specifier: ^1.2.0
|
||||
version: 1.2.0
|
||||
'@iconify-json/ic':
|
||||
specifier: ^1.2.0
|
||||
version: 1.2.0
|
||||
'@iconify-json/iconoir':
|
||||
specifier: ^1.2.0
|
||||
version: 1.2.0
|
||||
'@iconify-json/material-symbols':
|
||||
specifier: ^1.2.1
|
||||
version: 1.2.1
|
||||
'@iconify-json/mdi':
|
||||
specifier: ^1.2.0
|
||||
version: 1.2.0
|
||||
'@iconify-json/simple-icons':
|
||||
specifier: ^1.2.2
|
||||
version: 1.2.2
|
||||
'@nuxt/devtools':
|
||||
specifier: ^1.4.1
|
||||
version: 1.4.1(rollup@4.21.2)(vite@5.4.2(@types/node@20.8.7)(terser@5.22.0))
|
||||
|
@ -1088,12 +1110,30 @@ packages:
|
|||
resolution: {integrity: sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==}
|
||||
engines: {node: '>=18.18'}
|
||||
|
||||
'@iconify-json/bi@1.2.0':
|
||||
resolution: {integrity: sha512-kaBV87cQlyeMkBBiMqsf3b43Nsxdk/rYKvR29dnktht57WUyHCnBAuH+ca/bscX856CzRpVX+sYs7arjrJD0qA==}
|
||||
|
||||
'@iconify-json/heroicons-outline@1.2.0':
|
||||
resolution: {integrity: sha512-Qy1sRmQYqih6xRxwCtnX0hXJ4252t83C0CnNWAP3gF0fH0Qmp9RY66LMB0moYGxQxUhsTFIl2nNceSVSBUo8Tg==}
|
||||
|
||||
'@iconify-json/heroicons-solid@1.2.0':
|
||||
resolution: {integrity: sha512-o+PjtMXPr4wk0veDS7Eh6H1BnTJT1vD7HcKl+I7ixdYQC8i1P2zdtk0C2v7C9OjJBMsiwJSCxT4qQ3OzONgyjw==}
|
||||
|
||||
'@iconify-json/ic@1.2.0':
|
||||
resolution: {integrity: sha512-L4+m77xTQB08X3I+3xs1+IrvK+aNcuN/7ODu5aUPznHKLU+/8UYcsjUgNHze6vPOGPQ0AG+kCwvy91EYPXSRxw==}
|
||||
|
||||
'@iconify-json/iconoir@1.2.0':
|
||||
resolution: {integrity: sha512-GbYAERFy9c1laIo1QZon9sBjRkX9rksirehmLIvvohn+W++fpPlvQnzVl0VpY/v2GCvs1pZ42spTKDj0AcofvA==}
|
||||
|
||||
'@iconify-json/material-symbols@1.2.1':
|
||||
resolution: {integrity: sha512-r9yaBzlUmN87aCTSoCNtDCd7R9F0iVDjNPL9QHHhm1WglFJvTUKx9iBC5xcZpP0qN0bg9R5FkM90CndWxEBAnw==}
|
||||
|
||||
'@iconify-json/mdi@1.2.0':
|
||||
resolution: {integrity: sha512-E9/3l5Syg3wfuarorFodhn4s8YorxhH3U3U20LaNBNiqw1kFNIDWhF6HymuzAD35k7RH0OBasJ+ZUyFtVVV6eg==}
|
||||
|
||||
'@iconify-json/simple-icons@1.2.2':
|
||||
resolution: {integrity: sha512-VMgCoMnpvcCJ5b3rTOGPzW5j6959nIdRCk+8FGzK/vAaDd6f9sx65OcKOqP3C75llpybH/iQhk5yrJ/TOdQKeg==}
|
||||
|
||||
'@iconify/types@2.0.0':
|
||||
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
|
||||
|
||||
|
@ -1671,9 +1711,6 @@ packages:
|
|||
'@types/eslint-scope@3.7.6':
|
||||
resolution: {integrity: sha512-zfM4ipmxVKWdxtDaJ3MP3pBurDXOCoyjvlpE3u6Qzrmw4BPbfm4/ambIeTk/r/J0iq/+2/xp0Fmt+gFvXJY2PQ==}
|
||||
|
||||
'@types/eslint@8.44.6':
|
||||
resolution: {integrity: sha512-P6bY56TVmX8y9J87jHNgQh43h6VVU+6H7oN7hgvivV81K2XY8qJZ5vqPy/HdUoVIelii2kChYVzQanlswPWVFw==}
|
||||
|
||||
'@types/eslint@9.6.1':
|
||||
resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==}
|
||||
|
||||
|
@ -2821,9 +2858,6 @@ packages:
|
|||
errx@0.1.0:
|
||||
resolution: {integrity: sha512-fZmsRiDNv07K6s2KkKFTiD2aIvECa7++PKyD5NC32tpRw46qZA3sOz+aM+/V9V0GDHxVTKLziveV4JhzBHDp9Q==}
|
||||
|
||||
es-module-lexer@1.3.1:
|
||||
resolution: {integrity: sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==}
|
||||
|
||||
es-module-lexer@1.5.4:
|
||||
resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==}
|
||||
|
||||
|
@ -3827,6 +3861,9 @@ packages:
|
|||
mlly@1.7.1:
|
||||
resolution: {integrity: sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==}
|
||||
|
||||
moment@2.30.1:
|
||||
resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==}
|
||||
|
||||
mri@1.2.0:
|
||||
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
|
||||
engines: {node: '>=4'}
|
||||
|
@ -6425,6 +6462,10 @@ snapshots:
|
|||
|
||||
'@humanwhocodes/retry@0.3.0': {}
|
||||
|
||||
'@iconify-json/bi@1.2.0':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
||||
'@iconify-json/heroicons-outline@1.2.0':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
@ -6433,6 +6474,26 @@ snapshots:
|
|||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
||||
'@iconify-json/ic@1.2.0':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
||||
'@iconify-json/iconoir@1.2.0':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
||||
'@iconify-json/material-symbols@1.2.1':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
||||
'@iconify-json/mdi@1.2.0':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
||||
'@iconify-json/simple-icons@1.2.2':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
||||
'@iconify/types@2.0.0': {}
|
||||
|
||||
'@iconify/utils@2.1.32':
|
||||
|
@ -7223,13 +7284,8 @@ snapshots:
|
|||
|
||||
'@types/eslint-scope@3.7.6':
|
||||
dependencies:
|
||||
'@types/eslint': 8.44.6
|
||||
'@types/estree': 1.0.3
|
||||
|
||||
'@types/eslint@8.44.6':
|
||||
dependencies:
|
||||
'@types/estree': 1.0.3
|
||||
'@types/json-schema': 7.0.14
|
||||
'@types/eslint': 9.6.1
|
||||
'@types/estree': 1.0.5
|
||||
|
||||
'@types/eslint@9.6.1':
|
||||
dependencies:
|
||||
|
@ -7947,9 +8003,9 @@ snapshots:
|
|||
dependencies:
|
||||
event-target-shim: 5.0.1
|
||||
|
||||
acorn-import-assertions@1.9.0(acorn@8.11.2):
|
||||
acorn-import-assertions@1.9.0(acorn@8.12.1):
|
||||
dependencies:
|
||||
acorn: 8.11.2
|
||||
acorn: 8.12.1
|
||||
|
||||
acorn-import-attributes@1.9.5(acorn@8.12.1):
|
||||
dependencies:
|
||||
|
@ -8662,8 +8718,6 @@ snapshots:
|
|||
|
||||
errx@0.1.0: {}
|
||||
|
||||
es-module-lexer@1.3.1: {}
|
||||
|
||||
es-module-lexer@1.5.4: {}
|
||||
|
||||
esbuild@0.19.10:
|
||||
|
@ -9865,6 +9919,8 @@ snapshots:
|
|||
pkg-types: 1.2.0
|
||||
ufo: 1.5.4
|
||||
|
||||
moment@2.30.1: {}
|
||||
|
||||
mri@1.2.0: {}
|
||||
|
||||
mrmime@2.0.0: {}
|
||||
|
@ -10793,7 +10849,7 @@ snapshots:
|
|||
|
||||
schema-utils@3.3.0:
|
||||
dependencies:
|
||||
'@types/json-schema': 7.0.14
|
||||
'@types/json-schema': 7.0.15
|
||||
ajv: 6.12.6
|
||||
ajv-keywords: 3.5.2(ajv@6.12.6)
|
||||
|
||||
|
@ -11141,7 +11197,7 @@ snapshots:
|
|||
|
||||
terser-webpack-plugin@5.3.9(esbuild@0.23.1)(webpack@5.89.0(esbuild@0.23.1)):
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.20
|
||||
'@jridgewell/trace-mapping': 0.3.25
|
||||
jest-worker: 27.5.1
|
||||
schema-utils: 3.3.0
|
||||
serialize-javascript: 6.0.1
|
||||
|
@ -11724,16 +11780,16 @@ snapshots:
|
|||
webpack@5.89.0(esbuild@0.23.1):
|
||||
dependencies:
|
||||
'@types/eslint-scope': 3.7.6
|
||||
'@types/estree': 1.0.3
|
||||
'@types/estree': 1.0.5
|
||||
'@webassemblyjs/ast': 1.11.6
|
||||
'@webassemblyjs/wasm-edit': 1.11.6
|
||||
'@webassemblyjs/wasm-parser': 1.11.6
|
||||
acorn: 8.11.2
|
||||
acorn-import-assertions: 1.9.0(acorn@8.11.2)
|
||||
browserslist: 4.22.2
|
||||
acorn: 8.12.1
|
||||
acorn-import-assertions: 1.9.0(acorn@8.12.1)
|
||||
browserslist: 4.23.3
|
||||
chrome-trace-event: 1.0.3
|
||||
enhanced-resolve: 5.15.0
|
||||
es-module-lexer: 1.3.1
|
||||
es-module-lexer: 1.5.4
|
||||
eslint-scope: 5.1.1
|
||||
events: 3.3.0
|
||||
glob-to-regexp: 0.4.1
|
||||
|
|
|
@ -1,4 +1,77 @@
|
|||
{
|
||||
"categories": [
|
||||
{
|
||||
"id": "infrastructure",
|
||||
"name": "Infrastructure",
|
||||
"usecases": [
|
||||
"node",
|
||||
"rpc-provider",
|
||||
"infrastructure",
|
||||
"eth-layer-2",
|
||||
"research-and-development",
|
||||
"computing",
|
||||
"storage",
|
||||
"data-management",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "social-and-communications",
|
||||
"name": "Social & Communications",
|
||||
"usecases": [
|
||||
"dao",
|
||||
"nft-community",
|
||||
"alliances",
|
||||
"messaging",
|
||||
"events",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "hardware",
|
||||
"name": "Hardware",
|
||||
"usecases": [
|
||||
"wallets",
|
||||
"node",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "applications",
|
||||
"name": "Applications",
|
||||
"usecases": [
|
||||
"browser",
|
||||
"vpn",
|
||||
"did",
|
||||
"operation-systems",
|
||||
"dapps",
|
||||
"wallets",
|
||||
"ai",
|
||||
"kyc-solution",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "defi",
|
||||
"name": "Defi",
|
||||
"usecases": [
|
||||
"bridge",
|
||||
"defi",
|
||||
"mixing-service",
|
||||
"mixing-management",
|
||||
"currency",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "archived-projects",
|
||||
"name": "Archived projects",
|
||||
"usecases": [
|
||||
"legacy-projects",
|
||||
"deprecated-systems"
|
||||
]
|
||||
}
|
||||
],
|
||||
"projects": [
|
||||
{
|
||||
"id": "01-labs",
|
||||
|
@ -15885,181 +15958,6 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"assets": [
|
||||
{
|
||||
"id": "eth",
|
||||
"name": "Ethereum"
|
||||
},
|
||||
{
|
||||
"id": "btc",
|
||||
"name": "Bitcoin"
|
||||
},
|
||||
{
|
||||
"id": "usdc",
|
||||
"name": "Coinbase stable"
|
||||
},
|
||||
{
|
||||
"id": "usdt",
|
||||
"name": "Tether"
|
||||
},
|
||||
{
|
||||
"id": "dai",
|
||||
"name": "MakerDAO stable"
|
||||
},
|
||||
{
|
||||
"id": "atom",
|
||||
"name": "Cosmos"
|
||||
},
|
||||
{
|
||||
"id": "scrt",
|
||||
"name": "Secret Network"
|
||||
},
|
||||
{
|
||||
"id": "dot",
|
||||
"name": "Polkadot"
|
||||
},
|
||||
{
|
||||
"id": "sol",
|
||||
"name": "Solana"
|
||||
},
|
||||
{
|
||||
"id": "zcash",
|
||||
"name": "Zcash"
|
||||
},
|
||||
{
|
||||
"id": "xmr",
|
||||
"name": "Monero"
|
||||
},
|
||||
{
|
||||
"id": "other",
|
||||
"name": "Other"
|
||||
}
|
||||
],
|
||||
"categories": [
|
||||
{
|
||||
"id": "infrastructure",
|
||||
"name": "Infrastructure",
|
||||
"usecases": [
|
||||
"node",
|
||||
"rpc-provider",
|
||||
"infrastructure",
|
||||
"eth-layer-2",
|
||||
"research-and-development",
|
||||
"computing",
|
||||
"storage",
|
||||
"data-management",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "social-and-communications",
|
||||
"name": "Social & Communications",
|
||||
"usecases": [
|
||||
"dao",
|
||||
"nft-community",
|
||||
"alliances",
|
||||
"messaging",
|
||||
"events",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "hardware",
|
||||
"name": "Hardware",
|
||||
"usecases": [
|
||||
"wallets",
|
||||
"node",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "applications",
|
||||
"name": "Applications",
|
||||
"usecases": [
|
||||
"browser",
|
||||
"vpn",
|
||||
"did",
|
||||
"operation-systems",
|
||||
"dapps",
|
||||
"wallets",
|
||||
"ai",
|
||||
"kyc-solution",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "defi",
|
||||
"name": "Defi",
|
||||
"usecases": [
|
||||
"bridge",
|
||||
"defi",
|
||||
"mixing-service",
|
||||
"mixing-management",
|
||||
"currency",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "archived-projects",
|
||||
"name": "Archived projects",
|
||||
"usecases": [
|
||||
"legacy-projects",
|
||||
"deprecated-systems"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ecosystems": [
|
||||
{
|
||||
"id": "ethereum",
|
||||
"name": "Ethereum"
|
||||
},
|
||||
{
|
||||
"id": "bitcoin",
|
||||
"name": "Bitcoin"
|
||||
},
|
||||
{
|
||||
"id": "solana",
|
||||
"name": "Solana"
|
||||
},
|
||||
{
|
||||
"id": "cosmos",
|
||||
"name": "Cosmos"
|
||||
},
|
||||
{
|
||||
"id": "monero",
|
||||
"name": "Monero"
|
||||
},
|
||||
{
|
||||
"id": "other",
|
||||
"name": "Other"
|
||||
}
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"id": "no-compliance",
|
||||
"name": "No compliance"
|
||||
},
|
||||
{
|
||||
"id": "non-kyc",
|
||||
"name": "Non-KYC"
|
||||
},
|
||||
{
|
||||
"id": "private-by-default",
|
||||
"name": "Private by default"
|
||||
},
|
||||
{
|
||||
"id": "non-custodial",
|
||||
"name": "Non custodial"
|
||||
},
|
||||
{
|
||||
"id": "opensource",
|
||||
"name": "Opensource"
|
||||
},
|
||||
{
|
||||
"id": "live-on-mainnet",
|
||||
"name": "Live on Mainnet"
|
||||
}
|
||||
],
|
||||
"usecases": [
|
||||
{
|
||||
"id": "wallets",
|
||||
|
@ -16185,5 +16083,360 @@
|
|||
"id": "other",
|
||||
"name": "Other"
|
||||
}
|
||||
],
|
||||
"assets": [
|
||||
{
|
||||
"id": "eth",
|
||||
"name": "Ethereum"
|
||||
},
|
||||
{
|
||||
"id": "btc",
|
||||
"name": "Bitcoin"
|
||||
},
|
||||
{
|
||||
"id": "usdc",
|
||||
"name": "Coinbase stable"
|
||||
},
|
||||
{
|
||||
"id": "usdt",
|
||||
"name": "Tether"
|
||||
},
|
||||
{
|
||||
"id": "dai",
|
||||
"name": "MakerDAO stable"
|
||||
},
|
||||
{
|
||||
"id": "atom",
|
||||
"name": "Cosmos"
|
||||
},
|
||||
{
|
||||
"id": "scrt",
|
||||
"name": "Secret Network"
|
||||
},
|
||||
{
|
||||
"id": "dot",
|
||||
"name": "Polkadot"
|
||||
},
|
||||
{
|
||||
"id": "sol",
|
||||
"name": "Solana"
|
||||
},
|
||||
{
|
||||
"id": "zcash",
|
||||
"name": "Zcash"
|
||||
},
|
||||
{
|
||||
"id": "xmr",
|
||||
"name": "Monero"
|
||||
},
|
||||
{
|
||||
"id": "other",
|
||||
"name": "Other"
|
||||
}
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"id": "no-compliance",
|
||||
"name": "No compliance"
|
||||
},
|
||||
{
|
||||
"id": "non-kyc",
|
||||
"name": "Non-KYC"
|
||||
},
|
||||
{
|
||||
"id": "private-by-default",
|
||||
"name": "Private by default"
|
||||
},
|
||||
{
|
||||
"id": "non-custodial",
|
||||
"name": "Non custodial"
|
||||
},
|
||||
{
|
||||
"id": "opensource",
|
||||
"name": "Opensource"
|
||||
},
|
||||
{
|
||||
"id": "live-on-mainnet",
|
||||
"name": "Live on Mainnet"
|
||||
}
|
||||
],
|
||||
"ecosystems": [
|
||||
{
|
||||
"id": "ethereum",
|
||||
"name": "Ethereum",
|
||||
"icon": "https://assets.coingecko.com/coins/images/279/standard/ethereum.png?1696501628"
|
||||
},
|
||||
{
|
||||
"id": "bitcoin",
|
||||
"name": "Bitcoin",
|
||||
"icon": "https://assets.coingecko.com/coins/images/1/standard/bitcoin.png?1696501400"
|
||||
},
|
||||
{
|
||||
"id": "solana",
|
||||
"name": "Solana",
|
||||
"icon": "https://assets.coingecko.com/coins/images/4128/standard/solana.png?1718769756"
|
||||
},
|
||||
{
|
||||
"id": "cosmos",
|
||||
"name": "Cosmos",
|
||||
"icon": "https://assets.coingecko.com/coins/images/1481/standard/cosmos_hub.png?1696502525"
|
||||
},
|
||||
{
|
||||
"id": "monero",
|
||||
"name": "Monero",
|
||||
"icon": "https://assets.coingecko.com/coins/images/69/standard/monero_logo.png?1696501460"
|
||||
},
|
||||
{
|
||||
"id": "other",
|
||||
"name": "Other"
|
||||
}
|
||||
],
|
||||
"ranks": [
|
||||
{
|
||||
"id": "openess",
|
||||
"name": "Openess",
|
||||
"references": [
|
||||
{
|
||||
"field": "team.teammembers",
|
||||
"label": {
|
||||
"name": "Team",
|
||||
"positive": "Member",
|
||||
"negative": "Anonymous"
|
||||
},
|
||||
"condition": {
|
||||
"minLength": 1
|
||||
},
|
||||
"points": 10
|
||||
},
|
||||
{
|
||||
"field": "links.docs",
|
||||
"label": {
|
||||
"name": "Documentation",
|
||||
"positive": "Link",
|
||||
"negative": "Not available"
|
||||
},
|
||||
"condition": {
|
||||
"exists": true
|
||||
},
|
||||
"points": 10
|
||||
},
|
||||
{
|
||||
"field": "links.github",
|
||||
"label": {
|
||||
"name": "Github",
|
||||
"positive": "Link",
|
||||
"negative": "Not available"
|
||||
},
|
||||
"condition": {
|
||||
"exists": true
|
||||
},
|
||||
"points": 10
|
||||
},
|
||||
{
|
||||
"field": "links.twitter",
|
||||
"label": {
|
||||
"name": "Twitter",
|
||||
"positive": "Link",
|
||||
"negative": "Not available"
|
||||
},
|
||||
"condition": {
|
||||
"exists": true
|
||||
},
|
||||
"points": 1
|
||||
},
|
||||
{
|
||||
"field": "links.telegram",
|
||||
"label": {
|
||||
"name": "Twitter",
|
||||
"positive": "Link",
|
||||
"negative": "Not available"
|
||||
},
|
||||
"condition": {
|
||||
"exists": true
|
||||
},
|
||||
"points": 1
|
||||
},
|
||||
{
|
||||
"field": "links.discord",
|
||||
"label": {
|
||||
"name": "Discord",
|
||||
"positive": "Link",
|
||||
"negative": "Not available"
|
||||
},
|
||||
"condition": {
|
||||
"exists": true
|
||||
},
|
||||
"points": 1
|
||||
},
|
||||
{
|
||||
"field": "links.lens",
|
||||
"label": {
|
||||
"name": "Lens",
|
||||
"positive": "Link",
|
||||
"negative": "Not available"
|
||||
},
|
||||
"condition": {
|
||||
"exists": true
|
||||
},
|
||||
"points": 1
|
||||
},
|
||||
{
|
||||
"field": "links.farcaster",
|
||||
"label": {
|
||||
"name": "Farcaster",
|
||||
"positive": "Link",
|
||||
"negative": "Not available"
|
||||
},
|
||||
"condition": {
|
||||
"exists": true
|
||||
},
|
||||
"points": 1
|
||||
},
|
||||
{
|
||||
"field": "links.whitepaper",
|
||||
"label": {
|
||||
"name": "Whitepaper",
|
||||
"positive": "Link",
|
||||
"negative": "Not available"
|
||||
},
|
||||
"condition": {
|
||||
"exists": true
|
||||
},
|
||||
"points": 10
|
||||
},
|
||||
{
|
||||
"field": "funding.value",
|
||||
"label": {
|
||||
"name": "Funding",
|
||||
"positive": "Investment",
|
||||
"negative": "Not available"
|
||||
},
|
||||
"condition": {
|
||||
"exists": true
|
||||
},
|
||||
"points": 10
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "technology",
|
||||
"name": "Technology",
|
||||
"references": [
|
||||
{
|
||||
"field": "project_status.mainnet",
|
||||
"label": {
|
||||
"name": "Mainnet",
|
||||
"positive": "Yes",
|
||||
"negative": "No"
|
||||
},
|
||||
"condition": {
|
||||
"exists": true
|
||||
},
|
||||
"points": 10
|
||||
},
|
||||
{
|
||||
"field": "blockchain_features.opensource",
|
||||
"label": {
|
||||
"name": "Open Source",
|
||||
"positive": "Yes",
|
||||
"negative": "No"
|
||||
},
|
||||
"condition": {
|
||||
"equals": true
|
||||
},
|
||||
"points": 20
|
||||
},
|
||||
{
|
||||
"field": "blockchain_features.asset_custody_type",
|
||||
"label": {
|
||||
"name": "Non Custody",
|
||||
"positive": "None",
|
||||
"negative": "Custodial"
|
||||
},
|
||||
"condition": {
|
||||
"equals": "non-custody"
|
||||
},
|
||||
"points": 10
|
||||
},
|
||||
{
|
||||
"field": "blockchain_features.upgradability.enabled",
|
||||
"label": {
|
||||
"name": "Upgradability",
|
||||
"positive": "Disabled",
|
||||
"negative": "Enabled"
|
||||
},
|
||||
"condition": {
|
||||
"equals": false
|
||||
},
|
||||
"points": 10
|
||||
},
|
||||
{
|
||||
"field": "audits",
|
||||
"label": {
|
||||
"name": "Audits",
|
||||
"positive": "Audit",
|
||||
"negative": "None"
|
||||
},
|
||||
"condition": {
|
||||
"minLength": 1
|
||||
},
|
||||
"points": 10
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "privacy",
|
||||
"name": "Privacy",
|
||||
"references": [
|
||||
{
|
||||
"field": "privacy_policy.link",
|
||||
"label": {
|
||||
"name": "Privacy Policy",
|
||||
"positive": "Link",
|
||||
"negative": "Not available"
|
||||
},
|
||||
"condition": {
|
||||
"exists": true
|
||||
},
|
||||
"points": 10
|
||||
},
|
||||
{
|
||||
"field": "traceability.kyc",
|
||||
"label": {
|
||||
"name": "KYC",
|
||||
"positive": "No",
|
||||
"negative": "Yes"
|
||||
},
|
||||
"condition": {
|
||||
"equals": false
|
||||
},
|
||||
"points": 10
|
||||
},
|
||||
{
|
||||
"field": "compliance",
|
||||
"label": {
|
||||
"name": "Compliance",
|
||||
"positive": "No",
|
||||
"negative": "OFAC"
|
||||
},
|
||||
"condition": {
|
||||
"equals": true
|
||||
},
|
||||
"points": 5
|
||||
},
|
||||
{
|
||||
"field": "default_privacy",
|
||||
"label": {
|
||||
"name": "Default Privacy",
|
||||
"positive": "YES",
|
||||
"negative": "No"
|
||||
},
|
||||
"condition": {
|
||||
"equals": true
|
||||
},
|
||||
"points": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
4
types/asset.ts
Normal file
4
types/asset.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export interface Asset {
|
||||
id: string
|
||||
name: string
|
||||
}
|
|
@ -2,4 +2,5 @@ export interface Category {
|
|||
id: string
|
||||
name: string
|
||||
projectsCount: number
|
||||
usecases?: string[]
|
||||
}
|
||||
|
|
5
types/ecosystem.ts
Normal file
5
types/ecosystem.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
export interface Ecosystem {
|
||||
id: string
|
||||
name: string
|
||||
icon?: string
|
||||
}
|
4
types/feature.ts
Normal file
4
types/feature.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export interface Feature {
|
||||
id: string
|
||||
name: string
|
||||
}
|
|
@ -7,11 +7,13 @@ export interface Project {
|
|||
id: string
|
||||
name: string
|
||||
categories: string[]
|
||||
ecosystem?: string
|
||||
usecases?: string[]
|
||||
ecosystem?: string[]
|
||||
product_readiness?: string
|
||||
security?: string
|
||||
have_token?: boolean
|
||||
token_link?: string
|
||||
assets_used?: string[]
|
||||
tokens?: {
|
||||
name?: string
|
||||
symbol: string
|
||||
|
@ -35,6 +37,7 @@ export interface Project {
|
|||
telegram?: string
|
||||
discord?: string
|
||||
blog?: string
|
||||
governance?: string
|
||||
facebook?: string
|
||||
block_explorer?: string
|
||||
whitepaper?: string
|
||||
|
@ -121,6 +124,7 @@ export interface Project {
|
|||
url?: string
|
||||
[k: string]: unknown
|
||||
}[]
|
||||
ratings?: ProjectRating[]
|
||||
}
|
||||
|
||||
export interface ProjectShallow {
|
||||
|
@ -129,6 +133,10 @@ export interface ProjectShallow {
|
|||
title1: string
|
||||
description: string
|
||||
percentage: number
|
||||
categories: string[]
|
||||
usecases?: string[]
|
||||
ecosystem?: string[]
|
||||
assets_used?: string []
|
||||
forum?: string | undefined
|
||||
github?: string | undefined
|
||||
website?: string | undefined
|
||||
|
@ -142,8 +150,24 @@ export interface ProjectShallow {
|
|||
audits?: Audit[] | undefined
|
||||
support?: number | undefined
|
||||
anonymity?: boolean | undefined
|
||||
ratings?: ProjectRating[]
|
||||
}
|
||||
|
||||
export interface ProjectIndexable extends Project {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export interface ProjectRating {
|
||||
type: string
|
||||
name: string
|
||||
items: ProjectRatingItem[]
|
||||
points: number
|
||||
}
|
||||
|
||||
export interface ProjectRatingItem {
|
||||
isValid: boolean
|
||||
label: string
|
||||
positive: string
|
||||
negative: string
|
||||
value: any
|
||||
}
|
||||
|
|
24
types/rank.ts
Normal file
24
types/rank.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import type { Project } from './project'
|
||||
|
||||
export interface Rank {
|
||||
id: string
|
||||
name: string
|
||||
references: Reference[]
|
||||
}
|
||||
|
||||
interface Reference {
|
||||
field: keyof Project
|
||||
label: {
|
||||
name: string
|
||||
positive: string
|
||||
negative: string
|
||||
}
|
||||
condition: Condition
|
||||
points: number
|
||||
}
|
||||
|
||||
interface Condition {
|
||||
minLength?: number
|
||||
exists?: boolean
|
||||
equals?: boolean | string
|
||||
}
|
4
types/usecase.ts
Normal file
4
types/usecase.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export interface Usecase {
|
||||
id: string
|
||||
name: string
|
||||
}
|
|
@ -35,5 +35,8 @@ 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>',
|
||||
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>',
|
||||
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>',
|
||||
thumb_up: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><mask id="mask0_308_7787" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="16" height="16"><rect width="16" height="16" fill="#D9D9D9"/></mask><g mask="url(#mask0_308_7787)"><path d="M11.9987 14.0013H5.33203V5.33464L9.9987 0.667969L10.832 1.5013C10.9098 1.57908 10.9737 1.68464 11.0237 1.81797C11.0737 1.9513 11.0987 2.07908 11.0987 2.2013V2.43464L10.3654 5.33464H13.9987C14.3543 5.33464 14.6654 5.46797 14.932 5.73463C15.1987 6.0013 15.332 6.31241 15.332 6.66797V8.0013C15.332 8.07908 15.3237 8.16241 15.307 8.2513C15.2904 8.34019 15.2654 8.42352 15.232 8.5013L13.232 13.2013C13.132 13.4235 12.9654 13.6124 12.732 13.768C12.4987 13.9235 12.2543 14.0013 11.9987 14.0013ZM3.9987 5.33464V14.0013H1.33203V5.33464H3.9987Z" fill="white"/></g></svg>',
|
||||
},
|
||||
}
|
||||
|
|
|
@ -50,9 +50,29 @@ export default defineConfig({
|
|||
bg: {
|
||||
grey: '#ffffff33',
|
||||
dark_grey: '#161616',
|
||||
rating: {
|
||||
default: '#494949',
|
||||
red: '#FF4218',
|
||||
orange: '#FF9900',
|
||||
yellow: '#FFE600',
|
||||
green: '#42FF00',
|
||||
hover: '#202020',
|
||||
},
|
||||
team: {
|
||||
grey: '#404040',
|
||||
},
|
||||
funding: {
|
||||
card: '#101010',
|
||||
},
|
||||
audits: {
|
||||
card: '#191919',
|
||||
},
|
||||
},
|
||||
text: {
|
||||
grey: '#909090',
|
||||
rating: {
|
||||
negative: '#FFB800',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
50
utils/score.ts
Normal file
50
utils/score.ts
Normal file
|
@ -0,0 +1,50 @@
|
|||
import type { Project, ProjectIndexable, ProjectShallow } from '~/types'
|
||||
|
||||
const fulfilled = (value: any): boolean => {
|
||||
const type = typeof value
|
||||
switch (type) {
|
||||
case 'string':
|
||||
if (value !== '')
|
||||
return true
|
||||
break
|
||||
case 'object':
|
||||
if (Object.keys(value!).length > 0)
|
||||
return true
|
||||
break
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export const calculateScore = (project: ProjectIndexable | ProjectShallow | Project) => {
|
||||
const criterias: { value: keyof ProjectIndexable, key: keyof ProjectIndexable | '' }[] = [
|
||||
{ value: 'product_readiness', key: '' },
|
||||
{ value: 'github', key: 'links' },
|
||||
{ value: 'docs', key: 'links' },
|
||||
{ value: 'team', key: '' },
|
||||
{ value: 'audits', key: '' },
|
||||
]
|
||||
|
||||
let matched = 0
|
||||
for (let i = 0; i < criterias.length; i++) {
|
||||
let value
|
||||
// value = ((criterias[i].key ?? props.project[criterias[i].value as keyof typeof props.project]) ?? null === null) ? null : (props.project as ProjectIndexable)[criterias[i].key][criterias[i].value]
|
||||
|
||||
const indexableProject = project as ProjectIndexable
|
||||
if (criterias[i].key !== '')
|
||||
value = (indexableProject[criterias[i].key] as any)?.[criterias[i].value]
|
||||
else
|
||||
value = indexableProject?.[criterias[i].value]
|
||||
|
||||
// console.log(props.project?.links?.github);
|
||||
// console.log(Object.keys(props.indexableProject["team"]).length);
|
||||
if (value === null || value === undefined)
|
||||
continue
|
||||
|
||||
if (fulfilled(value))
|
||||
matched++
|
||||
}
|
||||
|
||||
return 100 / criterias.length * matched
|
||||
}
|
5
utils/text.ts
Normal file
5
utils/text.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import moment from 'moment'
|
||||
|
||||
export function formatDate(date: Date | string) {
|
||||
return moment(date).format('MM / YYYY')
|
||||
}
|
Loading…
Reference in a new issue