Skip to content

Commit a8e6168

Browse files
committed
Merge remote-tracking branch 'origin/main' into fix/trends-date-inputs
# Conflicts: # app/components/Package/TrendsChart.vue
2 parents 9efce42 + a331176 commit a8e6168

24 files changed

Lines changed: 811 additions & 259 deletions

File tree

app/components/AppHeader.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ onKeyStroke(
180180
for (const link of desktopLinks.value) {
181181
if (link.to && link.keyshortcut && isKeyWithoutModifiers(e, link.keyshortcut)) {
182182
e.preventDefault()
183-
navigateTo(link.to.name)
183+
navigateTo(link.to)
184184
break
185185
}
186186
}

app/components/Code/DirectoryListing.vue

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
<script setup lang="ts">
22
import type { PackageFileTree } from '#shared/types'
33
import type { RouteLocationRaw } from 'vue-router'
4+
import type { RouteNamedMap } from 'vue-router/auto-routes'
45
import { ADDITIONAL_ICONS, getFileIcon } from '~/utils/file-icons'
56
67
const props = defineProps<{
78
tree: PackageFileTree[]
89
currentPath: string
910
baseUrl: string
10-
/** Base path segments for the code route (e.g., ['nuxt', 'v', '4.2.0']) */
11-
basePath: string[]
11+
baseRoute: Pick<RouteNamedMap['code'], 'params'>
1212
}>()
1313
1414
// Get the current directory's contents
@@ -41,13 +41,14 @@ const parentPath = computed(() => {
4141
4242
// Build route object for a path
4343
function getCodeRoute(nodePath?: string): RouteLocationRaw {
44-
if (!nodePath) {
45-
return { name: 'code', params: { path: props.basePath as [string, ...string[]] } }
46-
}
47-
const pathSegments = [...props.basePath, ...nodePath.split('/')]
4844
return {
4945
name: 'code',
50-
params: { path: pathSegments as [string, ...string[]] },
46+
params: {
47+
org: props.baseRoute.params.org,
48+
packageName: props.baseRoute.params.packageName,
49+
version: props.baseRoute.params.version,
50+
filePath: nodePath ?? '',
51+
},
5152
}
5253
}
5354

app/components/Code/FileTree.vue

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
<script setup lang="ts">
22
import type { PackageFileTree } from '#shared/types'
33
import type { RouteLocationRaw } from 'vue-router'
4+
import type { RouteNamedMap } from 'vue-router/auto-routes'
45
import { ADDITIONAL_ICONS, getFileIcon } from '~/utils/file-icons'
56
67
const props = defineProps<{
78
tree: PackageFileTree[]
89
currentPath: string
910
baseUrl: string
10-
/** Base path segments for the code route (e.g., ['nuxt', 'v', '4.2.0']) */
11-
basePath: string[]
11+
baseRoute: Pick<RouteNamedMap['code'], 'params'>
1212
depth?: number
1313
}>()
1414
@@ -23,10 +23,14 @@ function isNodeActive(node: PackageFileTree): boolean {
2323
2424
// Build route object for a file path
2525
function getFileRoute(nodePath: string): RouteLocationRaw {
26-
const pathSegments = [...props.basePath, ...nodePath.split('/')]
2726
return {
2827
name: 'code',
29-
params: { path: pathSegments as [string, ...string[]] },
28+
params: {
29+
org: props.baseRoute.params.org,
30+
packageName: props.baseRoute.params.packageName,
31+
version: props.baseRoute.params.version,
32+
filePath: nodePath ?? '',
33+
},
3034
}
3135
}
3236
@@ -75,7 +79,7 @@ watch(
7579
:tree="node.children"
7680
:current-path="currentPath"
7781
:base-url="baseUrl"
78-
:base-path="basePath"
82+
:base-route="baseRoute"
7983
:depth="depth + 1"
8084
/>
8185
</template>

app/components/Code/MobileTreeDrawer.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<script setup lang="ts">
22
import type { PackageFileTree } from '#shared/types'
3+
import type { RouteNamedMap } from 'vue-router/auto-routes'
34
45
defineProps<{
56
tree: PackageFileTree[]
67
currentPath: string
78
baseUrl: string
8-
/** Base path segments for the code route (e.g., ['nuxt', 'v', '4.2.0']) */
9-
basePath: string[]
9+
baseRoute: Pick<RouteNamedMap['code'], 'params'>
1010
}>()
1111
1212
const isOpen = shallowRef(false)
@@ -75,7 +75,7 @@ watch(isOpen, open => (isLocked.value = open))
7575
:tree="tree"
7676
:current-path="currentPath"
7777
:base-url="baseUrl"
78-
:base-path="basePath"
78+
:base-route="baseRoute"
7979
/>
8080
</aside>
8181
</Transition>

app/components/Filter/Panel.vue

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ const { t } = useI18n()
3232
const isExpanded = shallowRef(false)
3333
const showAllKeywords = shallowRef(false)
3434
35+
const filterText = computed({
36+
get: () => props.filters.text,
37+
set: value => emit('update:text', value),
38+
})
39+
3540
const displayedKeywords = computed(() => {
3641
const keywords = props.availableKeywords ?? []
3742
return showAllKeywords.value ? keywords : keywords.slice(0, 20)
@@ -130,11 +135,6 @@ function getSecurityLabelKey(value: SecurityFilter): string {
130135
return securityLabelKeys.value[value]
131136
}
132137
133-
function handleTextInput(event: Event) {
134-
const target = event.target as HTMLInputElement
135-
emit('update:text', target.value)
136-
}
137-
138138
// Compact summary of active filters for collapsed header using operator syntax
139139
const filterSummary = computed(() => {
140140
const parts: string[] = []
@@ -242,13 +242,12 @@ const hasActiveFilters = computed(() => !!filterSummary.value)
242242
<InputBase
243243
id="filter-search"
244244
type="text"
245-
:value="filters.text"
245+
v-model="filterText"
246246
:placeholder="searchPlaceholder"
247247
autocomplete="off"
248248
class="w-full min-w-25"
249249
size="medium"
250250
no-correct
251-
@input="handleTextInput"
252251
/>
253252
</div>
254253

app/components/Package/InstallScripts.vue

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
22
import { getOutdatedTooltip, getVersionClass } from '~/utils/npm/outdated-dependencies'
3+
import type { RouteLocationRaw } from 'vue-router'
34
45
const props = defineProps<{
56
packageName: string
@@ -11,12 +12,25 @@ const props = defineProps<{
1112
}
1213
}>()
1314
14-
function getCodeLink(filePath: string): string {
15-
return `/code/${props.packageName}/v/${props.version}/${filePath}`
15+
function getCodeLink(filePath: string): RouteLocationRaw {
16+
const split = props.packageName.split('/')
17+
18+
return {
19+
name: 'code',
20+
params: {
21+
org: split.length === 2 ? split[0] : null,
22+
packageName: split.length === 2 ? split[1]! : split[0]!,
23+
version: props.version,
24+
filePath: filePath,
25+
},
26+
}
1627
}
1728
1829
const scriptParts = computed(() => {
19-
const parts: Record<string, { prefix: string | null; filePath: string | null; link: string }> = {}
30+
const parts: Record<
31+
string,
32+
{ prefix: string | null; filePath: string | null; link: RouteLocationRaw }
33+
> = {}
2034
for (const scriptName of props.installScripts.scripts) {
2135
const content = props.installScripts.content?.[scriptName]
2236
if (!content) continue

app/components/Package/TrendsChart.vue

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,45 @@ import { useCssVariables } from '~/composables/useColors'
66
import { OKLCH_NEUTRAL_FALLBACK, transparentizeOklch } from '~/utils/colors'
77
import { getFrameworkColor, isListedFramework } from '~/utils/frameworks'
88
import { drawNpmxLogoAndTaglineWatermark } from '~/composables/useChartWatermark'
9+
import type {
10+
ChartTimeGranularity,
11+
DailyDataPoint,
12+
DateRangeFields,
13+
EvolutionData,
14+
EvolutionOptions,
15+
MonthlyDataPoint,
16+
WeeklyDataPoint,
17+
YearlyDataPoint,
18+
} from '~/types/chart'
919
import { DATE_INPUT_MAX } from '~/utils/input'
1020
11-
const props = defineProps<{
12-
// For single package downloads history
13-
weeklyDownloads?: WeeklyDataPoint[]
14-
inModal?: boolean
21+
const props = withDefaults(
22+
defineProps<{
23+
// For single package downloads history
24+
weeklyDownloads?: WeeklyDataPoint[]
25+
inModal?: boolean
1526
16-
/**
17-
* Backward compatible single package mode.
18-
* Used when `weeklyDownloads` is provided.
19-
*/
20-
packageName?: string
27+
/**
28+
* Backward compatible single package mode.
29+
* Used when `weeklyDownloads` is provided.
30+
*/
31+
packageName?: string
2132
22-
/**
23-
* Multi-package mode.
24-
* Used when `weeklyDownloads` is not provided.
25-
*/
26-
packageNames?: string[]
27-
createdIso?: string | null
33+
/**
34+
* Multi-package mode.
35+
* Used when `weeklyDownloads` is not provided.
36+
*/
37+
packageNames?: string[]
38+
createdIso?: string | null
2839
29-
/** When true, shows facet selector (e.g. Downloads / Likes). */
30-
showFacetSelector?: boolean
31-
}>()
40+
/** When true, shows facet selector (e.g. Downloads / Likes). */
41+
showFacetSelector?: boolean
42+
permalink?: boolean
43+
}>(),
44+
{
45+
permalink: false,
46+
},
47+
)
3248
3349
const { locale } = useI18n()
3450
const { accentColors, selectedAccentColor } = useAccentColor()
@@ -111,14 +127,7 @@ const watermarkColors = computed(() => ({
111127
const mobileBreakpointWidth = 640
112128
const isMobile = computed(() => width.value > 0 && width.value < mobileBreakpointWidth)
113129
114-
type ChartTimeGranularity = 'daily' | 'weekly' | 'monthly' | 'yearly'
115130
const DEFAULT_GRANULARITY: ChartTimeGranularity = 'weekly'
116-
type EvolutionData = DailyDataPoint[] | WeeklyDataPoint[] | MonthlyDataPoint[] | YearlyDataPoint[]
117-
118-
type DateRangeFields = {
119-
startDate?: string
120-
endDate?: string
121-
}
122131
123132
function isRecord(value: unknown): value is Record<string, unknown> {
124133
return typeof value === 'object' && value !== null
@@ -323,7 +332,10 @@ const effectivePackageNames = computed<string[]>(() => {
323332
return single ? [single] : []
324333
})
325334
326-
const selectedGranularity = shallowRef<ChartTimeGranularity>(DEFAULT_GRANULARITY)
335+
const selectedGranularity = usePermalink<ChartTimeGranularity>('granularity', DEFAULT_GRANULARITY, {
336+
permanent: props.permalink,
337+
})
338+
327339
const displayedGranularity = shallowRef<ChartTimeGranularity>(DEFAULT_GRANULARITY)
328340
329341
const isEndDateOnPeriodEnd = computed(() => {
@@ -353,8 +365,13 @@ const shouldRenderEstimationOverlay = computed(
353365
() => !pending.value && isEstimationGranularity.value,
354366
)
355367
356-
const startDate = shallowRef<string>('') // YYYY-MM-DD
357-
const endDate = shallowRef<string>('') // YYYY-MM-DD
368+
const startDate = usePermalink<string>('start', '', {
369+
permanent: props.permalink,
370+
})
371+
const endDate = usePermalink<string>('end', '', {
372+
permanent: props.permalink,
373+
})
374+
358375
const hasUserEditedDates = shallowRef(false)
359376
360377
/**
@@ -579,7 +596,9 @@ const METRICS = computed<MetricDef[]>(() => [
579596
},
580597
])
581598
582-
const selectedMetric = shallowRef<MetricId>(DEFAULT_METRIC_ID)
599+
const selectedMetric = usePermalink<MetricId>('facet', DEFAULT_METRIC_ID, {
600+
permanent: props.permalink,
601+
})
583602
584603
// Per-metric state keyed by metric id
585604
const metricStates = reactive<

0 commit comments

Comments
 (0)