Skip to content

Commit fba9ee4

Browse files
committed
feat: improve navigation history
1 parent be8729e commit fba9ee4

File tree

7 files changed

+48
-59
lines changed

7 files changed

+48
-59
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"packageManager": "pnpm@9.15.4",
66
"scripts": {
77
"build": "pnpm -r run build",
8-
"dev": "nuxt dev packages/node-modules-inspector/src",
8+
"dev": "pnpm -C packages/node-modules-inspector run dev",
99
"start": "pnpm -C packages/node-modules-inspector run start",
1010
"prepare": "nuxt prepare packages/node-modules-inspector/src && npx simple-git-hooks",
1111
"lint": "nuxi prepare && eslint .",

packages/node-modules-inspector/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"scripts": {
2323
"build": "nuxi build src && unbuild",
2424
"start": "node ./bin.mjs",
25-
"dev": "pnpm run -r stub && nuxi dev src",
25+
"dev": "pnpm run -r stub && cd src && nuxi dev",
2626
"prepack": "pnpm build"
2727
},
2828
"dependencies": {

packages/node-modules-inspector/src/app/components/panel/Nav.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ const isFiltersOpen = computed({
3030
},
3131
})
3232
33+
const location = window.location
34+
3335
const tabsMeta = [
3436
{
3537
name: 'Graph View',
@@ -104,7 +106,7 @@ function resetPanelState() {
104106
flex="~ items-center justify-center"
105107
:title="tab.name"
106108
:class="route.path.startsWith(tab.path) ? 'text-primary' : 'op50'"
107-
:to="{ path: tab.path, query: route.query }"
109+
:to="{ path: tab.path, hash: location.hash }"
108110
@click="resetPanelState()"
109111
>
110112
<div :class="tab.icon" text-xl />

packages/node-modules-inspector/src/app/components/panel/PackageDetails.vue

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,21 @@ function toggleExclude() {
7575
<div p1 flex="~ col">
7676
<button
7777
px2 py1 rounded hover:bg-active flex="~ items-center gap-2"
78-
:class="filters.focus?.includes(pkg.spec) ? 'text-primary' : 'op50'"
78+
:class="filters.focus?.includes(pkg.spec) ? 'text-primary' : 'op75'"
79+
:disabled="filters.excludes?.includes(pkg.spec)"
80+
class="disabled:op25! disabled:pointer-events-none"
7981
@click="toggleFocus()"
8082
>
8183
<div i-ph-arrows-in-cardinal-duotone flex-none />
8284
<span class="ml-2">{{ filters.focus?.includes(pkg.spec) ? 'Unfocus' : 'Focus' }} on this package</span>
8385
</button>
8486
<button
8587
px2 py1 rounded hover:bg-active flex="~ items-center gap-2"
86-
:class="filters.excludes?.includes(pkg.spec) ? 'text-purple' : 'op50'"
88+
:class="filters.excludes?.includes(pkg.spec) ? 'text-purple' : 'op75'"
8789
@click="toggleExclude()"
8890
>
8991
<div i-ph-network-slash-duotone flex-none />
90-
<span class="ml-2">{{ filters.focus?.includes(pkg.spec) ? 'Un-exclude' : 'Exclude' }} this package</span>
92+
<span class="ml-2">{{ filters.excludes?.includes(pkg.spec) ? 'Un-exclude' : 'Exclude' }} this package</span>
9193
</button>
9294
</div>
9395
</template>
@@ -104,7 +106,7 @@ function toggleExclude() {
104106
</div>
105107

106108
<div flex="~ col gap-2" p5>
107-
<div font-mono text-2xl flex="~ wrap items-center gap-2" pr10>
109+
<div font-mono text-2xl flex="~ wrap items-center gap-2" pr20>
108110
<span>{{ pkg.name }}</span>
109111
<DisplayModuleType text-sm :pkg :force="true" />
110112
</div>

packages/node-modules-inspector/src/app/components/report/MostDeps.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const top20 = computed(() => {
1414
<template>
1515
<div v-if="top20.length">
1616
<SubTitle>Packages with the Most of Transitive Dependencies</SubTitle>
17-
<div grid="~ cols-[max-content_max-content_1fr] gap-x-4 gap-y-1" border="~ rounded-xl base" p4 bg-glass>
17+
<div grid="~ cols-[max-content_max-content_1fr] gap-x-4 gap-y-1" border="~ rounded-xl base" p4 bg-glass of-auto>
1818
<template v-for="pkg of top20" :key="pkg.spec">
1919
<button
2020
font-mono text-left hover:bg-active px2 ml--2 rounded

packages/node-modules-inspector/src/app/state/filters.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ export const FILTER_KEYS = [
3232
'source-type',
3333
] satisfies (keyof FilterOptions)[]
3434

35+
export const FILTER_KEYS_ARRAY = [
36+
'modules',
37+
'focus',
38+
'licenses',
39+
'excludes',
40+
] satisfies (keyof FilterOptions)[]
41+
3542
export const FILTER_KEYS_FULL = [
3643
'excludes',
3744
'exclude-dts',
Lines changed: 29 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,62 @@
1-
import type { LocationQuery } from 'vue-router'
21
import type { FilterOptions } from './filters'
32
import { useRoute, useRouter } from '#app/composables/router'
43
import { debouncedWatch, ignorableWatch } from '@vueuse/core'
54
import { reactive, watch } from 'vue'
6-
import { FILTER_KEYS_FULL, filters } from './filters'
5+
import { FILTER_KEYS_ARRAY, FILTER_KEYS_FULL, filters } from './filters'
76

87
export interface QueryOptions extends FilterOptions {
98
selected?: string
109
}
1110

12-
export const query = reactive<QueryOptions>({} as any)
11+
export const query = reactive<QueryOptions>({
12+
selected: '',
13+
} as any)
1314

14-
const FIELDS_ARRAY: (keyof QueryOptions)[] = [
15-
'modules',
16-
'focus',
17-
'licenses',
18-
'excludes',
19-
]
20-
21-
// function stringifyQuery(object: QueryOptions): string {
22-
// const entries = Object.entries(object)
23-
// .map(i => [i[0], Array.isArray(i[1]) ? i[1].join(',') : i[1]])
24-
// .filter(x => !!x[1]) as [string, string][]
25-
// const query = new URLSearchParams(entries)
26-
// return query.toString()
27-
// }
15+
function stringifyQuery(object: QueryOptions): string {
16+
const entries = Object.entries(object)
17+
.map(i => [i[0], Array.isArray(i[1]) ? i[1].join(',') : i[1]])
18+
.filter(x => !!x[1]) as [string, string][]
19+
const query = new URLSearchParams(entries)
20+
return query.toString()
21+
}
2822

2923
function parseQuery(query: string): QueryOptions {
3024
return Object.fromEntries(
3125
Array.from(new URLSearchParams(query).entries())
32-
.map(([key, value]) => [key, (FIELDS_ARRAY.includes(key as any) && typeof value === 'string') ? value.split(',') : value]),
33-
) as any as QueryOptions
34-
}
35-
36-
function toVueRouterQuery(query: QueryOptions): Record<string, string> {
37-
return Object.fromEntries(
38-
Object.entries(query)
39-
.map(([key, value]) => [key, Array.isArray(value) ? value.join(',') : value])
40-
.filter(x => !!x[1]),
41-
)
42-
}
43-
44-
function fromVueRouterQuery(query: LocationQuery): QueryOptions {
45-
return Object.fromEntries(
46-
Object.entries(query)
47-
.map(([key, value]) => [key, (FIELDS_ARRAY.includes(key as any) && typeof value === 'string') ? value.split(',') : value]),
26+
.map(([key, value]) => [key, (FILTER_KEYS_ARRAY.includes(key as any) && typeof value === 'string') ? value.split(',') : value]),
4827
) as any as QueryOptions
4928
}
5029

5130
export function setupQuery() {
52-
Object.assign(query, parseQuery(location.search))
53-
Object.assign(filters, query)
31+
Object.assign(query, parseQuery(location.hash.replace(/^#/, '')))
32+
33+
FILTER_KEYS_FULL.forEach((key) => {
34+
if (query[key] === undefined)
35+
(filters as any)[key] = query[key]
36+
})
5437

5538
const router = useRouter()
5639
const route = useRoute()
5740

5841
const { ignoreUpdates } = ignorableWatch(
59-
query,
60-
() => {
61-
// TODO: store the filters in the localStorge
62-
// Do soft .replace instead of pushing to history
63-
// Navigation should only be recording when changing `selected` or route
64-
router.push({ path: route.path, query: toVueRouterQuery(query) })
42+
() => [query, query.selected],
43+
(n, o) => {
44+
const hash = `#${decodeURIComponent(stringifyQuery(query)).replace(/^\?/g, '')}`
45+
if (n[1] !== o[1])
46+
router.push({ path: route.path, hash })
47+
else
48+
history.replaceState(null, '', hash)
6549
},
6650
{ deep: true, flush: 'post' },
6751
)
6852

6953
watch(
70-
() => route.query,
71-
(after) => {
54+
() => route.hash,
55+
() => {
7256
ignoreUpdates(() => {
73-
const target = fromVueRouterQuery(after)
74-
for (const [key, value] of Object.entries(target)) {
75-
if ((query as any)[key] !== value) {
76-
(query as any)[key] = value
77-
}
78-
}
57+
Object.assign(query, parseQuery(location.hash.replace(/^#/, '')))
7958
})
8059
},
81-
{ deep: true },
8260
)
8361

8462
debouncedWatch(
@@ -89,6 +67,6 @@ export function setupQuery() {
8967
(query as any)[key] = filters[key]
9068
}
9169
},
92-
{ deep: true, debounce: 500 },
70+
{ deep: true, debounce: 200 },
9371
)
9472
}

0 commit comments

Comments
 (0)