Skip to content

Commit 771b3d0

Browse files
committed
refactor: use proper route segments for code editor
1 parent 58ae1e1 commit 771b3d0

File tree

6 files changed

+79
-58
lines changed

6 files changed

+79
-58
lines changed

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 { 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 { 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
@@ -72,7 +76,7 @@ watch(
7276
:tree="node.children"
7377
:current-path="currentPath"
7478
:base-url="baseUrl"
75-
:base-path="basePath"
79+
:base-route="baseRoute"
7680
:depth="depth + 1"
7781
/>
7882
</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/pages/package-code/@[[org]]/[packageName]/v/[version]/[...filePath].vue

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ import type {
77
88
definePageMeta({
99
name: 'code',
10-
path: '/package-code/:path+',
11-
alias: ['/package/code/:path+', '/code/:path+'],
10+
path: '/package-code/@:org?/:packageName/v/:version/:filePath(.*)?',
11+
alias: [
12+
'/package/code/@:org?/:packageName/v/:version/:filePath(.*)?',
13+
'/code/@:org?/:packageName/v/:version/:filePath(.*)?',
14+
],
1215
})
1316
1417
const route = useRoute('code')
@@ -19,23 +22,11 @@ const route = useRoute('code')
1922
// /code/nuxt/v/4.2.0/src/index.ts → packageName: "nuxt", version: "4.2.0", filePath: "src/index.ts"
2023
// /code/@nuxt/kit/v/1.0.0 → packageName: "@nuxt/kit", version: "1.0.0", filePath: null
2124
const parsedRoute = computed(() => {
22-
const segments = route.params.path
23-
24-
// Find the /v/ separator for version
25-
const vIndex = segments.indexOf('v')
26-
if (vIndex === -1 || vIndex >= segments.length - 1) {
27-
// No version specified - redirect or error
28-
return {
29-
packageName: segments.join('/'),
30-
version: null as string | null,
31-
filePath: null as string | null,
32-
}
33-
}
34-
35-
const packageName = segments.slice(0, vIndex).join('/')
36-
const afterVersion = segments.slice(vIndex + 1)
37-
const version = afterVersion[0] ?? null
38-
const filePath = afterVersion.length > 1 ? afterVersion.slice(1).join('/') : null
25+
const packageName = route.params.org
26+
? `@${route.params.org}/${route.params.packageName}`
27+
: route.params.packageName
28+
const version = route.params.version
29+
const filePath = route.params.filePath || null
3930
4031
return { packageName, version, filePath }
4132
})
@@ -46,8 +37,15 @@ const filePathOrig = computed(() => parsedRoute.value.filePath)
4637
const filePath = computed(() => parsedRoute.value.filePath?.replace(/\/$/, ''))
4738
4839
// Navigation helper - build URL for a path
49-
function getCodeUrl(args: { packageName: string; version: string; filePath?: string }): string {
50-
const base = `/package-code/${args.packageName}/v/${args.version}`
40+
function getCodeUrl(args: {
41+
org?: string
42+
packageName: string
43+
version: string
44+
filePath?: string
45+
}): string {
46+
const base = args.org
47+
? `/package-code/@${args.org}/${args.packageName}/v/${args.version}`
48+
: `/package-code/${args.packageName}/v/${args.version}`
5149
return args.filePath ? `${base}/${args.filePath}` : base
5250
}
5351
@@ -203,18 +201,13 @@ const breadcrumbs = computed(() => {
203201
// Navigation helper - build URL for a path
204202
function getCurrentCodeUrl(path?: string): string {
205203
return getCodeUrl({
204+
org: route.params.org,
206205
packageName: packageName.value,
207206
version: version.value!,
208207
filePath: path,
209208
})
210209
}
211210
212-
// Base path segments for route objects (e.g., ['nuxt', 'v', '4.2.0'] or ['@nuxt', 'kit', 'v', '1.0.0'])
213-
const basePath = computed(() => {
214-
const segments = packageName.value.split('/')
215-
return [...segments, 'v', version.value ?? '']
216-
})
217-
218211
// Extract org name from scoped package
219212
const orgName = computed(() => {
220213
const name = packageName.value
@@ -409,7 +402,7 @@ defineOgImageComponent('Default', {
409402
:tree="fileTree.tree"
410403
:current-path="filePath ?? ''"
411404
:base-url="getCurrentCodeUrl()"
412-
:base-path="basePath"
405+
:base-route="route"
413406
/>
414407
</aside>
415408

@@ -565,7 +558,7 @@ defineOgImageComponent('Default', {
565558
:tree="fileTree.tree"
566559
:current-path="filePath ?? ''"
567560
:base-url="getCurrentCodeUrl()"
568-
:base-path="basePath"
561+
:base-route="route"
569562
/>
570563
</template>
571564
</div>
@@ -579,7 +572,7 @@ defineOgImageComponent('Default', {
579572
:tree="fileTree.tree"
580573
:current-path="filePath ?? ''"
581574
:base-url="getCurrentCodeUrl()"
582-
:base-path="basePath"
575+
:base-route="route"
583576
/>
584577
</Teleport>
585578
</ClientOnly>

app/pages/package/[[org]]/[name].vue

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -516,17 +516,29 @@ useSeoMeta({
516516
twitterDescription: () => pkg.value?.description ?? '',
517517
})
518518
519+
const linkCode = computed((): Parameters<typeof navigateTo>[0] | null => {
520+
if (pkg.value == null || resolvedVersion.value == null) {
521+
return null
522+
}
523+
const split = pkg.value.name.split('/')
524+
return {
525+
name: 'code',
526+
params: {
527+
org: split.length === 2 ? split[0]?.replace(/^@/, '') : undefined,
528+
packageName: split.length === 2 ? split[1]! : split[0]!,
529+
version: resolvedVersion.value,
530+
filePath: '',
531+
},
532+
}
533+
})
534+
519535
onKeyStroke(
520536
e => isKeyWithoutModifiers(e, '.') && !isEditableElement(e.target),
521537
e => {
522-
if (pkg.value == null || resolvedVersion.value == null) return
538+
if (linkCode.value === null) return
523539
e.preventDefault()
524-
navigateTo({
525-
name: 'code',
526-
params: {
527-
path: [pkg.value.name, 'v', resolvedVersion.value],
528-
},
529-
})
540+
541+
navigateTo(linkCode.value)
530542
},
531543
{ dedupe: true },
532544
)
@@ -662,8 +674,9 @@ onKeyStroke(
662674
{{ $t('package.links.docs') }}
663675
</LinkBase>
664676
<LinkBase
677+
v-if="linkCode"
665678
variant="button-secondary"
666-
:to="{ name: 'code', params: { path: [pkg.name, 'v', resolvedVersion] } }"
679+
:to="linkCode"
667680
aria-keyshortcuts="."
668681
classicon="i-carbon:code"
669682
>

test/nuxt/a11y.spec.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -921,7 +921,9 @@ describe('component accessibility audits', () => {
921921
tree: mockTree,
922922
currentPath: '',
923923
baseUrl: '/package-code/vue',
924-
basePath: ['vue', 'v', '3.0.0'],
924+
baseRoute: {
925+
params: { packageName: 'vue', version: '3.0.0', filePath: '' },
926+
},
925927
},
926928
})
927929
const results = await runAxe(component)
@@ -934,7 +936,9 @@ describe('component accessibility audits', () => {
934936
tree: mockTree,
935937
currentPath: 'src',
936938
baseUrl: '/package-code/vue',
937-
basePath: ['vue', 'v', '3.0.0'],
939+
baseRoute: {
940+
params: { packageName: 'vue', version: '3.0.0', filePath: '' },
941+
},
938942
},
939943
})
940944
const results = await runAxe(component)
@@ -959,7 +963,9 @@ describe('component accessibility audits', () => {
959963
tree: mockTree,
960964
currentPath: '',
961965
baseUrl: '/package-code/vue',
962-
basePath: ['vue', 'v', '3.0.0'],
966+
baseRoute: {
967+
params: { packageName: 'vue', version: '3.0.0', filePath: '' },
968+
},
963969
},
964970
})
965971
const results = await runAxe(component)
@@ -972,7 +978,9 @@ describe('component accessibility audits', () => {
972978
tree: mockTree,
973979
currentPath: 'src/index.ts',
974980
baseUrl: '/package-code/vue',
975-
basePath: ['vue', 'v', '3.0.0'],
981+
baseRoute: {
982+
params: { packageName: 'vue', version: '3.0.0', filePath: '' },
983+
},
976984
},
977985
})
978986
const results = await runAxe(component)
@@ -1222,7 +1230,9 @@ describe('component accessibility audits', () => {
12221230
tree: mockTree,
12231231
currentPath: '',
12241232
baseUrl: '/package-code/vue',
1225-
basePath: ['vue', 'v', '3.0.0'],
1233+
baseRoute: {
1234+
params: { packageName: 'vue', version: '3.0.0', filePath: '' },
1235+
},
12261236
},
12271237
})
12281238
const results = await runAxe(component)

0 commit comments

Comments
 (0)