diff --git a/app/composables/useRecentlyViewed.ts b/app/composables/useRecentlyViewed.ts new file mode 100644 index 000000000..f4afcb4e1 --- /dev/null +++ b/app/composables/useRecentlyViewed.ts @@ -0,0 +1,32 @@ +import { useLocalStorage } from '@vueuse/core' +import { computed } from 'vue' + +const MAX_RECENT_ITEMS = 5 +const STORAGE_KEY = 'npmx-recent' + +export type RecentItemType = 'package' | 'org' | 'user' + +export interface RecentItem { + type: RecentItemType + /** Canonical identifier: package name, org name (without @), or username */ + name: string + /** Display label shown on homepage (e.g. "@nuxt", "~sindresorhus") */ + label: string + /** Unix timestamp (ms) of most recent view */ + viewedAt: number +} + +export function useRecentlyViewed() { + const items = useLocalStorage(STORAGE_KEY, []) + + function trackRecentView(item: Omit) { + if (import.meta.server) return + const filtered = items.value.filter( + existing => !(existing.type === item.type && existing.name === item.name), + ) + filtered.unshift({ ...item, viewedAt: Date.now() }) + items.value = filtered.slice(0, MAX_RECENT_ITEMS) + } + + return { items: computed(() => items.value), trackRecentView } +} diff --git a/app/pages/index.vue b/app/pages/index.vue index 74d38d65d..8a8faabfb 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -1,5 +1,6 @@ - - diff --git a/app/pages/org/[org].vue b/app/pages/org/[org].vue index e7ec4a649..52b5e3881 100644 --- a/app/pages/org/[org].vue +++ b/app/pages/org/[org].vue @@ -121,6 +121,19 @@ watch(orgName, () => { currentPage.value = 1 }) +if (import.meta.client) { + const { trackRecentView } = useRecentlyViewed() + watch( + () => [status.value, orgName.value] as const, + ([s, name]) => { + if (s === 'success') { + trackRecentView({ type: 'org', name, label: `@${name}` }) + } + }, + { immediate: true }, + ) +} + // Handle filter chip removal function handleClearFilter(chip: FilterChip) { clearFilter(chip) diff --git a/app/pages/package/[[org]]/[name].vue b/app/pages/package/[[org]]/[name].vue index 72c799c9d..b1e985212 100644 --- a/app/pages/package/[[org]]/[name].vue +++ b/app/pages/package/[[org]]/[name].vue @@ -643,6 +643,19 @@ onKeyStroke( ) const showSkeleton = shallowRef(false) + +if (import.meta.client) { + const { trackRecentView } = useRecentlyViewed() + watch( + () => [status.value, packageName.value] as const, + ([s, name]) => { + if (s === 'success') { + trackRecentView({ type: 'package', name, label: name }) + } + }, + { immediate: true }, + ) +}