From c4e174a48b3ac8683f87ac0b2057dd48c37e046b Mon Sep 17 00:00:00 2001
From: Daniel Klein
Date: Tue, 24 Sep 2024 19:51:28 +0200
Subject: [PATCH] fix(performance): dashboard performance - sorting, filtering,
pagination
---
components/Card.vue | 249 ++++++++++----------
components/CategorySelectBox.vue | 2 +
components/Project/ProjectGrid.vue | 143 +----------
components/Project/ProjectGridGroup.vue | 85 +++++++
components/Project/ProjectGridGroupSort.vue | 103 ++++++++
components/SortSelectBox.vue | 24 +-
composables/useData.ts | 115 +++++----
7 files changed, 392 insertions(+), 329 deletions(-)
create mode 100644 components/Project/ProjectGridGroup.vue
create mode 100644 components/Project/ProjectGridGroupSort.vue
diff --git a/components/Card.vue b/components/Card.vue
index 55dcd65..1d18c5c 100644
--- a/components/Card.vue
+++ b/components/Card.vue
@@ -40,18 +40,16 @@ const projectItems: { label: string | string[], type: string, rating?: ProjectRa
h="48px lg:64px"
:class="switcher ? '' : 'lg:max-w-full! lg:w-full '"
>
-
-
-
+
-
-
+
-
- {{ (projectItem.label as string[] || []).join(', ') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ {{ (projectItem.label as string[] || []).join(', ') }}
+
-
- {{ project.percentage }} %
-
-
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+ {{ project.percentage }} %
+
+
+
+
diff --git a/components/CategorySelectBox.vue b/components/CategorySelectBox.vue
index f7fa559..b329a42 100644
--- a/components/CategorySelectBox.vue
+++ b/components/CategorySelectBox.vue
@@ -2,6 +2,7 @@
import type { InputOption } from '~/types'
const props = defineProps<{
+ name: string
options: InputOption[]
modelValue: string | number
count?: number
@@ -26,6 +27,7 @@ function onOptionSelected(value: string | number) {
>
diff --git a/components/Project/ProjectGrid.vue b/components/Project/ProjectGrid.vue
index 09c325c..e1e5f77 100644
--- a/components/Project/ProjectGrid.vue
+++ b/components/Project/ProjectGrid.vue
@@ -4,33 +4,8 @@ import type { ProjectShallow } from '~/types'
const props = defineProps<{
projects: { title: string, projects: ProjectShallow[] }[]
}>()
-const { switcher, filter } = storeToRefs(useData())
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 },
-])
@@ -39,123 +14,11 @@ const cardTitles = ref< { label: string, sortKey: string, togglable?: boolean }[
flex-col
items-start
>
-
-
-
- {{ group.projects.length }} {{ group.title }}
-
-
-
-
-
-
-
-
-
-
-
- {{ title.label }}
-
-
-
-
-
-
-
-
+ :group="group"
+ />
No Projects found...
diff --git a/components/Project/ProjectGridGroup.vue b/components/Project/ProjectGridGroup.vue
new file mode 100644
index 0000000..08c34ad
--- /dev/null
+++ b/components/Project/ProjectGridGroup.vue
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+ {{ group.projects.length }} {{ group.title }}
+
+
+
+
+
+
+
+
+
+ Loading...
+
+
+
+
+
+
+
+
diff --git a/components/Project/ProjectGridGroupSort.vue b/components/Project/ProjectGridGroupSort.vue
new file mode 100644
index 0000000..4dc38df
--- /dev/null
+++ b/components/Project/ProjectGridGroupSort.vue
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+ {{ title.label }}
+
+
+
+
+
diff --git a/components/SortSelectBox.vue b/components/SortSelectBox.vue
index e68fa00..70aa1ad 100644
--- a/components/SortSelectBox.vue
+++ b/components/SortSelectBox.vue
@@ -8,6 +8,7 @@ const props = withDefaults(defineProps(), {
const emits = defineEmits(['update:modelValue'])
interface SelectProps {
+ name: string
options: InputOption[]
modelValue: string
isMarginTop?: boolean
@@ -27,23 +28,24 @@ const selectedValue = useVModel(props, 'modelValue', emits)
:class="[isMarginTop ? 'mt-2' : 'mt-0', blackAndWhite ? 'bg-app-black' : 'bg-app-white']"
>
-
Sort by:
-
- {{ props.options.find(option => option.value === selectedValue)?.label }}
-
-
-
+
+
+ {{ props.options.find(option => option.value === selectedValue)?.label }}
+
+
{
const shallowProjects = computed(() => projects.value.map(project => projectToShallow(project)))
const getProjectsByFilters = (options?: { shallow: boolean }): T[] => {
- const filteredProjects = projects.value
- .filter(project =>
- selectedCategoryId.value !== 'all' ? project.categories.includes(selectedCategoryId.value) : true,
- )
- .filter(project =>
- selectedUsecaseId.value !== 'all' ? selectedUsecaseId.value === 'sunset' ? project.sunset : 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 selectedCategory = selectedCategoryId.value !== 'all' ? selectedCategoryId.value : undefined
+ const selectedUsecase = selectedUsecaseId.value !== 'all' ? selectedUsecaseId.value.toLowerCase() : undefined
+ const selectedEcosystem = selectedEcosystemId.value !== 'all' ? selectedEcosystemId.value.toLowerCase() : undefined
+ const selectedAssetsUsed = selectedAssetsUsedId.value !== 'all' ? selectedAssetsUsedId.value.toLowerCase() : undefined
+ const selectedFeature = selectedFeaturesId.value !== 'all' ? selectedFeaturesId.value.toLowerCase() : undefined
+
+ return (projects.value.filter((project) => {
+ if (selectedCategory && !project.categories.includes(selectedCategory))
+ return false
+
+ if (selectedUsecase) {
+ if (selectedUsecase === 'sunset') {
+ if (!project.sunset)
+ return false
+ }
+ else {
+ const usecases = project.usecases?.map(u => u.toLowerCase()) || []
+ if (!usecases.includes(selectedUsecase))
+ return false
+ }
+ }
+
+ if (selectedEcosystem) {
+ const ecosystems = project.ecosystem?.map(e => e.toLowerCase()) || []
+ if (!ecosystems.includes(selectedEcosystem))
+ return false
+ }
+
+ if (selectedAssetsUsed) {
+ const assetsUsed = project.assets_used?.map(a => a.toLowerCase()) || []
+ if (!assetsUsed.includes(selectedAssetsUsed))
+ return false
+ }
+
+ if (selectedFeature) {
+ const features = project.technology?.features?.map(f => f.toLowerCase()) || []
+ if (!features.includes(selectedFeature))
+ return false
+ }
+
+ return true
+ }).map(project => (options?.shallow ? projectToShallow(project) : project)) as T[])
}
const getProjectById = (id: string, options?: { shallow: boolean }): T => {
@@ -149,51 +174,39 @@ export const useData = defineStore('data', () => {
}
const filteredProjects = computed(() => {
- if (!projects.value)
- return []
+ if (!projects.value) return []
const query = filter.query.toLowerCase()
+ const sortDirection = filter.sortDirection === 'asc' ? 1 : -1
+ const sortBy = filter.sortby
const filteredShallowProjects = getProjectsByFilters({ shallow: true })
.filter((project) => {
- return (
- project
- && project.title1
- && project.title1.toLowerCase().includes(query)
- )
- }).filter((project) => {
- if (filter.sortby === 'anonymity')
- return project.anonymity === true
- else
- return true
- }).sort((a, b) => {
- if (filter.sortby === 'score')
- 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 project?.title1?.toLowerCase().includes(query)
})
+ .sort((a, b) => {
+ if (sortBy === 'score') {
+ return sortDirection * (a.percentage - b.percentage)
+ }
+
+ if (sortBy === 'title') {
+ return sortDirection * a.title1.toLowerCase().localeCompare(b.title1.toLowerCase())
+ }
+
+ if (sortBy === 'openess' || sortBy === 'technology' || sortBy === 'privacy') {
+ const scoreA = a.ratings?.find(r => r.type === sortBy)?.points || 0
+ const scoreB = b.ratings?.find(r => r.type === sortBy)?.points || 0
+ return sortDirection * (scoreB - scoreA)
+ }
+
+ 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),
)