diff --git a/packages/devtools-kit/src/_types/integrations.ts b/packages/devtools-kit/src/_types/integrations.ts index 16cf495e63..3de48a60f3 100644 --- a/packages/devtools-kit/src/_types/integrations.ts +++ b/packages/devtools-kit/src/_types/integrations.ts @@ -122,6 +122,7 @@ export interface ModuleStaticInfo { learn_more: string category: string type: ModuleType + stats: ModuleStats maintainers: MaintainerInfo[] contributors: GitHubContributor[] compatibility: ModuleCompatibility @@ -132,6 +133,13 @@ export interface ModuleCompatibility { requires: { bridge?: boolean | 'optional' } } +export interface ModuleStats { + downloads: number + stars: number + publishedAt: number + createdAt: number +} + export type CompatibilityStatus = 'working' | 'wip' | 'unknown' | 'not-working' export type ModuleType = 'community' | 'official' | '3rd-party' diff --git a/packages/devtools/client/components/ModuleInstallList.vue b/packages/devtools/client/components/ModuleInstallList.vue index fb1985b5ed..b3afbf4e3a 100644 --- a/packages/devtools/client/components/ModuleInstallList.vue +++ b/packages/devtools/client/components/ModuleInstallList.vue @@ -2,13 +2,30 @@ // @ts-expect-error missing types import { RecycleScroller } from 'vue-virtual-scroller' import Fuse from 'fuse.js' +import type { ModuleStaticInfo } from '../../src/types' + +type SortingFunction = (a: T, b: T) => number const emit = defineEmits(['close']) const collection = useModulesList() +const sortingOptions = ['downloads', 'stars', 'updated', 'created'] as const +const ascendingOrder = ref(false) +const selectedSortingOption = ref(sortingOptions[0]) + +const sortingFactors: Record> = { + downloads: (a, b) => a.stats.downloads - b.stats.downloads, + stars: (a, b) => a.stats.stars - b.stats.stars, + created: (a, b) => a.stats.createdAt - b.stats.createdAt, + updated: (a, b) => a.stats.publishedAt - b.stats.publishedAt, +} + +const sortedItems = computed(() => collection.value?.slice() + .sort((a, b) => sortingFactors[selectedSortingOption.value](a, b) * (ascendingOrder.value ? 1 : -1))) + const search = ref('') -const fuse = computed(() => new Fuse(collection.value || [], { +const fuse = computed(() => new Fuse(sortedItems.value || [], { keys: [ 'name', 'description', @@ -19,7 +36,7 @@ const fuse = computed(() => new Fuse(collection.value || [], { const items = computed(() => { if (!search.value) - return collection.value + return sortedItems.value return fuse.value.search(search.value).map(r => r.item) }) @@ -33,20 +50,51 @@ const items = computed(() => { text="Install Module" /> - + + +
diff --git a/packages/devtools/client/components/ModuleItemBase.vue b/packages/devtools/client/components/ModuleItemBase.vue index f35edc53f7..99c7ec01e1 100644 --- a/packages/devtools/client/components/ModuleItemBase.vue +++ b/packages/devtools/client/components/ModuleItemBase.vue @@ -89,6 +89,21 @@ const openInEditor = useOpenInEditor() + +
+
+ + + {{ data.stats.stars }} + +
+
+ + + {{ data.stats.downloads }} + +
+
{ - const modules = await $fetch('https://cdn.jsdelivr.net/npm/@nuxt/modules@latest/modules.json') - return modules - .filter((m: ModuleStaticInfo) => !ignoredModules.includes(m.npm) && m.compatibility.nuxt.includes('^3')) + const m = await $fetch<{ modules: ModuleStaticInfo[] }>('https://api.nuxt.com/modules?version=3') + return m.modules + .filter((item: ModuleStaticInfo) => !ignoredModules.includes(item.npm) && item.compatibility.nuxt.includes('^3')) }) }