Skip to content

Commit 92d6c0f

Browse files
committed
feat(rpc): add grouped methods sidebar
1 parent de5c50f commit 92d6c0f

File tree

3 files changed

+130
-7
lines changed

3 files changed

+130
-7
lines changed

app/components/docs/DocsAsideLeftBody.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
<script setup lang="ts">
22
import type { ContentNavigationItem } from '@nuxt/content'
3+
import RpcMethodsSidebar from './RpcMethodsSidebar.vue'
34
45
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
56
const route = useRoute()
67
78
const currentModule = computed(() => route.path.split('/').filter(Boolean)[0] || '')
9+
const isRpcMethodsPage = computed(() => {
10+
return route.path === '/rpc/methods'
11+
|| route.path === '/rpc/methods/'
12+
|| route.path.startsWith('/rpc/methods/')
13+
})
814
915
const filteredNavigation = computed<ContentNavigationItem[]>(() => {
1016
if (!navigation?.value) {
@@ -29,7 +35,9 @@ const filteredNavigation = computed<ContentNavigationItem[]>(() => {
2935
</script>
3036

3137
<template>
38+
<RpcMethodsSidebar v-if="isRpcMethodsPage" />
3239
<UContentNavigation
40+
v-else
3341
highlight
3442
:navigation="filteredNavigation"
3543
/>
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<script setup lang="ts">
2+
import type { OpenrpcDocument } from '@open-rpc/meta-schema'
3+
import type { NimiqRpcMethods } from '../../utils/rpc'
4+
import { useAsyncData, useRoute } from '#imports'
5+
import { computed, ref, watch } from 'vue'
6+
import openRpcDocument from '../../../data/openrpc-document.json'
7+
import { loadMethods } from '../../utils/rpc'
8+
9+
const route = useRoute()
10+
11+
const { data: groups } = await useAsyncData('rpc-sidebar-method-groups', () => loadMethods(openRpcDocument as OpenrpcDocument))
12+
13+
const normalizedPath = computed(() => normalizePath(route.path))
14+
const activeGroup = computed(() => groups.value?.find(group =>
15+
group.methods.some(method => normalizePath(method.link) === normalizedPath.value),
16+
))
17+
const expandedGroup = ref<string | null>(null)
18+
19+
watch(activeGroup, (group) => {
20+
expandedGroup.value = group?.text ?? null
21+
}, { immediate: true })
22+
23+
function isExpanded(group: NimiqRpcMethods) {
24+
return expandedGroup.value === group.text
25+
}
26+
27+
function toggleGroup(group: NimiqRpcMethods) {
28+
expandedGroup.value = isExpanded(group) ? null : group.text
29+
}
30+
31+
function isActive(link: string) {
32+
return normalizePath(link) === normalizedPath.value
33+
}
34+
35+
function normalizePath(path: string) {
36+
return path.replace(/\/+$/, '') || '/'
37+
}
38+
</script>
39+
40+
<template>
41+
<div class="space-y-5">
42+
<div class="space-y-1 px-2">
43+
<p class="text-xs font-semibold uppercase tracking-[0.18em] text-muted">
44+
Methods
45+
</p>
46+
<p class="text-sm leading-6 text-toned">
47+
Browse RPC methods by category.
48+
</p>
49+
</div>
50+
51+
<nav class="space-y-1" aria-label="RPC methods">
52+
<NuxtLink
53+
to="/rpc/methods/"
54+
class="flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors"
55+
:class="isActive('/rpc/methods/')
56+
? 'bg-elevated text-highlighted'
57+
: 'text-toned hover:bg-elevated/60 hover:text-highlighted'"
58+
>
59+
<UIcon name="i-tabler:grid-dots" class="size-4 shrink-0" />
60+
<span>All</span>
61+
</NuxtLink>
62+
63+
<div
64+
v-for="group in (groups || [])"
65+
:key="group.text"
66+
class="space-y-1"
67+
>
68+
<button
69+
type="button"
70+
class="flex w-full items-center justify-between gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors"
71+
:class="isExpanded(group) || activeGroup?.text === group.text
72+
? 'bg-elevated text-highlighted'
73+
: 'text-toned hover:bg-elevated/60 hover:text-highlighted'"
74+
@click="toggleGroup(group)"
75+
>
76+
<span class="flex min-w-0 items-center gap-3">
77+
<UIcon :name="group.icon" class="size-4 shrink-0" />
78+
<span class="truncate">{{ group.text }}</span>
79+
</span>
80+
<UIcon
81+
:name="isExpanded(group) ? 'i-lucide-chevron-down' : 'i-lucide-chevron-right'"
82+
class="size-4 shrink-0 text-muted"
83+
/>
84+
</button>
85+
86+
<div
87+
v-if="isExpanded(group)"
88+
class="ml-5 border-l border-default pl-3"
89+
>
90+
<NuxtLink
91+
v-for="method in group.methods"
92+
:key="method.name"
93+
:to="method.link"
94+
class="block rounded-md px-3 py-2 font-mono text-sm transition-colors"
95+
:class="isActive(method.link)
96+
? 'bg-elevated text-highlighted'
97+
: 'text-toned hover:bg-elevated/60 hover:text-highlighted'"
98+
>
99+
<span class="block truncate">{{ method.name }}</span>
100+
</NuxtLink>
101+
</div>
102+
</div>
103+
</nav>
104+
</div>
105+
</template>

app/utils/rpc.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { MethodObject, OpenrpcDocument, TagObject } from '@open-rpc/meta-schema'
22
import $RefParser from '@apidevtools/json-schema-ref-parser'
3-
import { capitalizeFirstLetter, slugify, toHumanReadable } from './string'
3+
import { slugify, toHumanReadable } from './string'
44

55
// Define types for RPC methods
66
export type RpcMethodTag = typeof tagOrder[number]
@@ -37,15 +37,25 @@ async function deferredMethods(openRpcJson: OpenrpcDocument): Promise<MethodObje
3737
// Helper function to generate RPC method items
3838
const tagOrder = ['validator', 'blockchain', 'consensus', 'wallet', 'policy', 'mempool', 'network', 'zkp_component'] as const
3939
const rpcAccordionIcons: Record<typeof tagOrder[number], string> = {
40-
validator: 'i-nimiq:verified',
41-
blockchain: 'i-nimiq:nodes',
40+
validator: 'i-tabler:shield-check',
41+
blockchain: 'i-tabler:blocks',
4242
consensus: 'i-tabler:network',
4343
wallet: 'i-tabler:wallet',
44-
policy: 'i-nimiq:verified',
45-
mempool: 'i-nimiq:cubes',
46-
network: 'i-nimiq:duotone-network',
44+
policy: 'i-tabler:scale',
45+
mempool: 'i-tabler:stack-2',
46+
network: 'i-tabler:world',
4747
zkp_component: 'i-tabler:lock',
4848
}
49+
const rpcTagLabels: Record<typeof tagOrder[number], string> = {
50+
validator: 'Validator',
51+
blockchain: 'Blockchain',
52+
consensus: 'Consensus',
53+
wallet: 'Wallet',
54+
policy: 'Policy',
55+
mempool: 'Mempool',
56+
network: 'Network',
57+
zkp_component: 'ZKP Component',
58+
}
4959

5060
export interface NimiqRpcMethod {
5161
method: string
@@ -112,7 +122,7 @@ export async function loadMethods(openRpcJson: OpenrpcDocument): Promise<NimiqRp
112122
result.push({
113123
icon: rpcAccordionIcons[tag],
114124
methods: methodsByTag,
115-
text: capitalizeFirstLetter(tag),
125+
text: rpcTagLabels[tag],
116126
items: methodsByTag.map(method => ({
117127
text: `\`${method.name}\``,
118128
link: `/rpc/methods/${slugify(method.name)}`,

0 commit comments

Comments
 (0)