Merge pull request #52 from web3privacy/dw/bug-fixes

Polishing v2
This commit is contained in:
MufCZ 2024-10-03 16:47:50 +02:00 committed by GitHub
commit 120744e9bb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 103 additions and 56 deletions

View file

@ -3,6 +3,7 @@ import type { ProjectRating, ProjectShallow } from '~/types'
const props = defineProps<{ const props = defineProps<{
project: ProjectShallow project: ProjectShallow
hiddenColumns?: string[]
}>() }>()
const { switcher, ecosystems, filter } = storeToRefs(useData()) const { switcher, ecosystems, filter } = storeToRefs(useData())
@ -11,6 +12,14 @@ const isLargeScreen = useMediaQuery('(min-width: 1024px)')
const ratings: { label: string, type: string, rating: ProjectRating }[] = (props.project.ratings || []).map(rating => ({ label: rating.name, type: 'rating', rating: rating })) 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 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' }] 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' }]
const { width } = useWindowSize()
const visibleColumnsCount = computed(() => {
if (width.value >= 1024)
return projectItems.filter(item => item.rating?.type ? !props.hiddenColumns?.includes(item.rating.type) : true).length + 4
else
return 2
})
</script> </script>
<template> <template>
@ -25,7 +34,7 @@ const projectItems: { label: string | string[], type: string, rating?: ProjectRa
> >
<div <div
grid grid
grid-cols="2 lg:10" :style="`grid-template-columns: repeat(${visibleColumnsCount}, 1fr)`"
w-full w-full
> >
@ -89,7 +98,7 @@ const projectItems: { label: string | string[], type: string, rating?: ProjectRa
</div> </div>
</div> </div>
<div <div
v-for="(projectItem, index) of projectItems" v-for="(projectItem, index) of projectItems.filter((item) => item.rating?.type ? !hiddenColumns?.includes(item.rating.type): true)"
:key="projectItem.label.toString()" :key="projectItem.label.toString()"
hidden hidden
lg:flex lg:flex

View file

@ -28,7 +28,7 @@ function onOptionSelected(value: string | number) {
<div class="relative font-700 font-24px"> <div class="relative font-700 font-24px">
<HeadlessListboxButton <HeadlessListboxButton
:id="`headless-listbox-button-${name}`" :id="`headless-listbox-button-${name}`"
class="relative cursor-pointer py-6px px-14px text-left border-2px bg-app-white text-app-black text-xs sm:text-sm sm:leading-6" class="w-full relative cursor-pointer py-6px px-14px text-left border-2px bg-app-white text-app-black text-xs sm:text-sm sm:leading-6"
hover="bg-app-black text-app-white" hover="bg-app-black text-app-white"
transition="all" transition="all"
duration-250 duration-250
@ -52,7 +52,7 @@ function onOptionSelected(value: string | number) {
leave-to-class="opacity-0" leave-to-class="opacity-0"
> >
<HeadlessListboxOptions <HeadlessListboxOptions
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" class="absolute z-100 max-h-60 w-fit border-2px border-t-0 overflow-auto bg-app-black text-app-white focus:outline-none sm:text-sm"
> >
<HeadlessListboxOption <HeadlessListboxOption
v-for="option in props.options" v-for="option in props.options"

View file

@ -3,7 +3,7 @@ const isHovered = ref(false)
</script> </script>
<template> <template>
<div app-container> <div w-full>
<div mt-48px> <div mt-48px>
<hr <hr
border-t-2px border-t-2px
@ -13,7 +13,8 @@ const isHovered = ref(false)
> >
</div> </div>
<div <div
p-24px app-container
pt-24px
pb-8px pb-8px
flex flex
items-center items-center
@ -121,8 +122,8 @@ const isHovered = ref(false)
</div> </div>
</div> </div>
<div <div
app-container
text="14px sm:16px" text="14px sm:16px"
px-24px
grid grid
grid-cols-2 grid-cols-2
sm:grid-cols-3 sm:grid-cols-3
@ -196,7 +197,7 @@ const isHovered = ref(false)
w-full w-full
> >
<div <div
px-24px app-container
my-16px my-16px
sm:mt-32px sm:mt-32px
flex flex

View file

@ -19,6 +19,7 @@ const isProjectDetailRoute = computed(() => {
z-100 z-100
bg-black bg-black
overflow-hidden overflow-hidden
border="b-1px white/20"
> >
<div <div
relative relative
@ -28,7 +29,7 @@ const isProjectDetailRoute = computed(() => {
> >
<img <img
absolute absolute
lg="left--30px" lg="left-10px"
left--30px left--30px
top--25px top--25px
z-101 z-101

View file

@ -15,6 +15,7 @@ const totalProjectsCount = props.projects.map(g => g.projects.length).reduce((a,
items-start items-start
> >
<ProjectGridGroup <ProjectGridGroup
my-24px lg:my-32px
v-for="group in projects" v-for="group in projects"
:key="group.title" :key="group.title"
:group="group" :group="group"

View file

@ -46,7 +46,18 @@ const shownProjects = computed(() => props.group.projects.slice(0, shownProjects
@click="groupCollapsed = !groupCollapsed" @click="groupCollapsed = !groupCollapsed"
/> />
</div> </div>
<ProjectGridGroupSort v-if="!groupCollapsed" /> <ClientOnly>
<ProjectGridGroupSort
v-if="!groupCollapsed"
:hidden-columns="group.title === 'Social & Communications' ? ['technology'] : []"
/>
<template #fallback>
<div
h-48px
w-full
/>
</template>
</ClientOnly>
<div <div
v-if="!groupCollapsed" v-if="!groupCollapsed"
grid grid
@ -61,6 +72,7 @@ const shownProjects = computed(() => props.group.projects.slice(0, shownProjects
<Card <Card
v-for="project in group.projects.slice(0, shownProjectsCount)" v-for="project in group.projects.slice(0, shownProjectsCount)"
:key="project.id" :key="project.id"
:hidden-columns="group.title === 'Social & Communications' ? ['technology'] : []"
:project="project" :project="project"
/> />
@ -79,9 +91,11 @@ const shownProjects = computed(() => props.group.projects.slice(0, shownProjects
text="12px lg:14px" text="12px lg:14px"
leading="24px lg:32px" leading="24px lg:32px"
font-bold font-bold
pt-16px mt-24px
pb-24px px-16px
py-4px
text-app-text-grey text-app-text-grey
border="2px white/50"
@click="shownProjectsCount += 15" @click="shownProjectsCount += 15"
> >
LOAD MORE LOAD MORE

View file

@ -1,4 +1,8 @@
<script lang="ts" setup> <script lang="ts" setup>
const props = defineProps<{
hiddenColumns?: string[]
}>()
const { filter } = storeToRefs(useData()) const { filter } = storeToRefs(useData())
function onChangeSort(sortKey: string) { function onChangeSort(sortKey: string) {
@ -15,6 +19,10 @@ function onChangeSort(sortKey: string) {
filter.value.sortDirection = sortKey === 'score' ? 'desc' : 'asc' filter.value.sortDirection = sortKey === 'score' ? 'desc' : 'asc'
} }
watch(filter, () => {
console.log(filter.value)
}, { deep: true })
const cardTitles = ref< { label: string, sortKey: string, togglable?: boolean }[]>([ const cardTitles = ref< { label: string, sortKey: string, togglable?: boolean }[]>([
{ label: 'Usecase', sortKey: 'usecase' }, { label: 'Usecase', sortKey: 'usecase' },
{ label: 'Openess', sortKey: 'openess', togglable: true }, { label: 'Openess', sortKey: 'openess', togglable: true },
@ -24,12 +32,21 @@ const cardTitles = ref< { label: string, sortKey: string, togglable?: boolean }[
{ label: 'Links', sortKey: 'links' }, { label: 'Links', sortKey: 'links' },
{ label: 'W3PN Score', sortKey: 'score', togglable: true }, { label: 'W3PN Score', sortKey: 'score', togglable: true },
]) ])
const { width } = useWindowSize()
const visibleColumnsCount = computed(() => {
if (width.value >= 1024)
return cardTitles.value.filter(title => !props.hiddenColumns?.includes(title.sortKey)).length + 3
else {
return 2
}
})
</script> </script>
<template> <template>
<div <div
grid grid
grid-cols="2 lg:10" :style="`grid-template-columns: repeat(${visibleColumnsCount}, 1fr)`"
w-full w-full
mb-16px mb-16px
> >
@ -76,7 +93,7 @@ const cardTitles = ref< { label: string, sortKey: string, togglable?: boolean }[
/> />
</div> </div>
<div <div
v-for="(title, index) in cardTitles" v-for="(title, index) in cardTitles.filter((title) => !hiddenColumns?.includes(title.sortKey))"
:key="title.label" :key="title.label"
lg:flex lg:flex
items-center items-center
@ -100,8 +117,8 @@ const cardTitles = ref< { label: string, sortKey: string, togglable?: boolean }[
<button <button
v-if="title.togglable" v-if="title.togglable"
type="button" type="button"
:class="[title.sortKey === filter.sortby ? filter.sortDirection === 'desc' ? 'i-ic-baseline-arrow-drop-up' :class="[title.sortKey === filter.sortby ? filter.sortDirection === 'desc' ? 'i-ic-baseline-arrow-drop-down'
: 'i-ic-baseline-arrow-drop-down' : 'i-ic-baseline-arrow-drop-up'
: 'i-ic-baseline-arrow-drop-down']" : 'i-ic-baseline-arrow-drop-down']"
text-24px text-24px
/> />

View file

@ -114,10 +114,9 @@ const logo = props.project?.logos?.at(0)?.url
flex flex
justify-center justify-center
lg:grid lg:grid
grid-cols-10 grid-cols-8
w-full w-full
items-center items-center
mt-4px
> >
<h2 <h2
hidden hidden
@ -126,10 +125,10 @@ const logo = props.project?.logos?.at(0)?.url
Usecases: Usecases:
</h2> </h2>
<p <p
mt-8px mb-8px
mb-16px lg="mb-0 mt-0"
text-app-white text-app-white
col-span-9 col-span-7
> >
{{ projectUsecases }} {{ projectUsecases }}
</p> </p>
@ -143,15 +142,13 @@ const logo = props.project?.logos?.at(0)?.url
order-3 order-3
lg:order-2 lg:order-2
w-full w-full
md:ml-0px
ml-18px
> >
<div <div
flex flex
flex-col flex-col
gap-4px gap-4px
lg:grid lg:grid
lg:grid-cols-10 lg:grid-cols-8
lg:items-center lg:items-center
w-full w-full
> >
@ -160,7 +157,7 @@ const logo = props.project?.logos?.at(0)?.url
</h2> </h2>
<p <p
text-app-white text-app-white
col-span-9 col-span-7
> >
{{ projectCategories }} {{ projectCategories }}
</p> </p>
@ -170,7 +167,7 @@ const logo = props.project?.logos?.at(0)?.url
flex-col flex-col
gap-4px gap-4px
lg:grid lg:grid
lg:grid-cols-10 lg:grid-cols-8
lg:items-center lg:items-center
w-full w-full
> >
@ -179,7 +176,7 @@ const logo = props.project?.logos?.at(0)?.url
</h2> </h2>
<p <p
text-app-white text-app-white
col-span-9 col-span-7
> >
{{ projectEcosystems }} {{ projectEcosystems }}
</p> </p>
@ -192,6 +189,8 @@ const logo = props.project?.logos?.at(0)?.url
items-center items-center
order-2 order-2
lg:order-3 lg:order-3
lg:ml-0
ml--12px
> >
<div <div
flex flex

View file

@ -30,19 +30,13 @@ const props = defineProps<{
v-for="member in members" v-for="member in members"
:key="member.name" :key="member.name"
> >
<div <NuxtLink
:to="member.link"
target="_blank"
flex flex
items-center items-center
gap-12px gap-12px
> >
<!-- <template v-if="member.link">
<NuxtImg
:src="member.link"
width="48"
height="48"
:alt="member.name"
/>
</template> -->
<div <div
flex flex
items-center items-center
@ -67,7 +61,7 @@ const props = defineProps<{
font-700 font-700
>{{ member.name }}</span> >{{ member.name }}</span>
</div> </div>
</div> </NuxtLink>
</template> </template>
</template> </template>
<template v-else> <template v-else>

View file

@ -14,7 +14,7 @@ const props = defineProps<{
const emits = defineEmits(['selected']) const emits = defineEmits(['selected'])
const colors = [ const colors = [
'#EA171D', // 0-10% '#EA171D', // 1-10%
'#FB2D00', // 11-20% '#FB2D00', // 11-20%
'#FD6515', // 21-30% '#FD6515', // 21-30%
'#FD941A', // 31-40% '#FD941A', // 31-40%
@ -29,6 +29,8 @@ const colors = [
const backgroundColorByScore = computed(() => { const backgroundColorByScore = computed(() => {
if (props.percentage === 100) if (props.percentage === 100)
return '#42FF00' return '#42FF00'
if (props.percentage === 0)
return '#494949'
const normalizedPercentage = Math.min(Math.max(props.percentage, 0), 100) const normalizedPercentage = Math.min(Math.max(props.percentage, 0), 100)
const colorIndex = Math.floor(normalizedPercentage / 10) const colorIndex = Math.floor(normalizedPercentage / 10)
return colors[colorIndex] return colors[colorIndex]

View file

@ -61,10 +61,16 @@ export const useData = defineStore('data', () => {
ranks: Rank[] ranks: Rank[]
}>('/api/data') }>('/api/data')
data.projects.forEach(project => project.ratings = generateProjectRating(project)) data.projects.forEach(project => project.ratings = generateProjectRating(project))
projects.value = data.projects.map(project => ({ projects.value = data.projects.map((project) => {
...project, const totalPoints = project.ratings?.reduce((a, b) => a + b.percentagePoints, 0) || 0
percentage: Math.round((project.ratings?.reduce((a, b) => a + b.points, 0) || 0) / 1.5), const numberOfRatings = project.ratings?.length || 1 // Avoid division by zero
})).filter(p => p.name) const averagePercentage = totalPoints / numberOfRatings
return {
...project,
percentage: Math.min(Math.max(Math.round(averagePercentage), 0), 100), // Ensure within 0-100%
}
}).filter(p => p.name)
console.log(projects.value.filter(p => p.name === 'ETHBerlin'))
const projectCategories = projects.value.map(p => p.categories).flat() const projectCategories = projects.value.map(p => p.categories).flat()
categories.value = data.categories.filter(c => projectCategories.includes(c.id)) categories.value = data.categories.filter(c => projectCategories.includes(c.id))
usecases.value = data.usecases usecases.value = data.usecases
@ -72,7 +78,6 @@ export const useData = defineStore('data', () => {
assets.value = data.assets assets.value = data.assets
features.value = data.features features.value = data.features
ranks.value = data.ranks ranks.value = data.ranks
projectPhase.value = data.phases?.map(p => ({ id: p.id.toLowerCase(), name: p.name })) projectPhase.value = data.phases?.map(p => ({ id: p.id.toLowerCase(), name: p.name }))
assetCustody.value = data.custodys.map(a => ({ id: a.id.toLowerCase(), name: a.name })) assetCustody.value = data.custodys.map(a => ({ id: a.id.toLowerCase(), name: a.name }))
signInRequirments.value = data.requirements.map(s => ({ id: s.id.toLowerCase(), name: s.name })) signInRequirments.value = data.requirements.map(s => ({ id: s.id.toLowerCase(), name: s.name }))
@ -173,9 +178,6 @@ export const useData = defineStore('data', () => {
case 'live-on-mainnet': case 'live-on-mainnet':
return project.project_phase === 'mainnet' return project.project_phase === 'mainnet'
} }
// const features = project.technology?.features?.map(f => f.toLowerCase()) || []
// if (!features.includes(selectedFeature))
// return false
} }
return true return true
@ -191,7 +193,7 @@ export const useData = defineStore('data', () => {
if (!projects.value) return [] if (!projects.value) return []
const query = filter.query.toLowerCase() const query = filter.query.toLowerCase()
const sortDirection = filter.sortDirection === 'asc' ? 1 : -1 const sortDirection = filter.sortDirection === 'desc' ? 1 : -1
const sortBy = filter.sortby const sortBy = filter.sortby
const filteredShallowProjects = getProjectsByFilters({ shallow: true }) const filteredShallowProjects = getProjectsByFilters({ shallow: true })
@ -200,10 +202,11 @@ export const useData = defineStore('data', () => {
}) })
.sort((a, b) => { .sort((a, b) => {
if (sortBy === 'score') { if (sortBy === 'score') {
return sortDirection * (a.percentage - b.percentage) return sortDirection * (b.percentage - a.percentage)
} }
if (sortBy === 'title') { if (sortBy === 'title') {
// sortDirection is reversed because the default sort is descending
return sortDirection * a.title1.toLowerCase().localeCompare(b.title1.toLowerCase()) return sortDirection * a.title1.toLowerCase().localeCompare(b.title1.toLowerCase())
} }
@ -248,11 +251,17 @@ export const useData = defineStore('data', () => {
const projectRatings: ProjectRating[] = ranks.value?.map((rank) => { const projectRatings: ProjectRating[] = ranks.value?.map((rank) => {
let rankPoints = 0 let rankPoints = 0
let maxPoints = 0 let maxPoints = 0
const ratingStats: ProjectRatingItem[] = []
const ratingStats: ProjectRatingItem[] = rank.references?.map((ref) => { rank.references?.forEach((ref) => {
let isValid = false let isValid = false
const field = ref.field.includes('.') ? getNestedField(project, ref.field) : project[ref.field] const field = ref.field.includes('.') ? getNestedField(project, ref.field) : project[ref.field]
// adds only one valid social link
if (ref.label.positive === 'Link' && ref.label.name !== 'Documentation')
if (ratingStats.some(r => r.positive === 'Link' && r.label !== 'Documentation' && r.value) || !field)
return
let value let value
let positive let positive
let negative let negative
@ -285,14 +294,15 @@ export const useData = defineStore('data', () => {
rankPoints += isValid ? ref.points : 0 rankPoints += isValid ? ref.points : 0
maxPoints += ref.points maxPoints += ref.points
return { ratingStats.push({
isValid, isValid,
label: ref.label.name, label: ref.label.name,
positive: positive ? positive : ref.label.positive, positive: positive ? positive : ref.label.positive,
negative: negative ? negative : ref.label.negative, negative: negative ? negative : ref.label.negative,
value, value,
} as ProjectRatingItem } as ProjectRatingItem)
}) })
return { return {
type: rank.id, type: rank.id,
name: rank.name, name: rank.name,

View file

@ -81,10 +81,10 @@ watch([scrollY, top, y], (newValues, oldValues) => {
md:justify-between md:justify-between
md:items-center md:items-center
gap-16px gap-16px
mb="16px md:32px"
> >
<SearchBox <SearchBox
flex-1 flex-1
class="w-full lg:max-w-1/3"
placeholder:text-app-text-grey placeholder:text-app-text-grey
:placeholder="`Search in ${filteredProjectsCount} Projects`" :placeholder="`Search in ${filteredProjectsCount} Projects`"
/> />
@ -98,7 +98,7 @@ watch([scrollY, top, y], (newValues, oldValues) => {
pb-274px pb-274px
mb--250px mb--250px
md="overflow-x-visible pb-0 mb-0" md="overflow-x-visible pb-0 mb-0"
class="no-scrollbar" class="no-scrollbar lg:w-full lg:max-w-2/3"
> >
<CategorySelectBox <CategorySelectBox
v-model="selectedCategoryId" v-model="selectedCategoryId"

View file

@ -34,13 +34,12 @@ useSeoMeta({
<div v-if="project"> <div v-if="project">
<div <div
app-container app-container
px-16px
> >
<div <div
flex flex
flex-col flex-col
gap-48px gap-48px
mt-54px mt-32px
> >
<div> <div>
<div> <div>

View file

@ -10,7 +10,7 @@ import { collections } from './unocss.config.collections'
export default defineConfig({ export default defineConfig({
shortcuts: [ shortcuts: [
{ {
'app-container': 'px-12px sm:px-1.5rem max-w-1140px 2xl:max-w-1400px m-auto w-full', 'app-container': 'px-24px sm:px-1.5rem max-w-1140px 2xl:max-w-1400px m-auto w-full',
'custom-link': 'text-app-text-grey hover:underline underline-offset-4px text-18px font-400 leading-32px cursor-pointer', 'custom-link': 'text-app-text-grey hover:underline underline-offset-4px text-18px font-400 leading-32px cursor-pointer',
}, },
{ {