Skip to content

Commit 4643715

Browse files
authored
feat(dapp): improve names page layout (#422)
* feat: improve layout and add nft name page * fix: cleanup debris code * fix: move cleanup * feat: add logic to button segment * feat: improve filters ux * fix: layout * refactor: remove code duplications * chore: drop useMemo * chore: apply simplification * refactor: improve displayed title in cards * feat: simplify layour * fix: disable subnames button when necessary * refactor: move availability check component to correct place * fix: build * fix: apply suggested changes * chore: rename function
1 parent a374122 commit 4643715

29 files changed

+734
-456
lines changed

dapp/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"next": "14.2.28",
3030
"react": "^18.3.1",
3131
"react-dom": "^18.3.1",
32+
"zustand": "^5.0.6",
3233
"react-hot-toast": "^2.4.1"
3334
},
3435
"devDependencies": {

dapp/src/app/(protected)/layout.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,8 @@ import { useEffect, type PropsWithChildren } from 'react';
99

1010
import { CONNECT_ROUTE } from '@/lib/constants';
1111

12-
function ProtectedLayout({ children }: PropsWithChildren): JSX.Element {
12+
export default function ProtectedLayout({ children }: PropsWithChildren): JSX.Element {
1313
const currentAccount = useCurrentAccount();
14-
1514
useEffect(() => {
1615
if (!currentAccount) {
1716
redirect(CONNECT_ROUTE.path);
@@ -20,9 +19,9 @@ function ProtectedLayout({ children }: PropsWithChildren): JSX.Element {
2019

2120
return (
2221
<main className="flex flex-col min-h-screen">
23-
<div className="container w-full h-full py-12 flex">{children}</div>
22+
<div className="container w-full h-full pt-20 flex flex-col flex-1">
23+
<div className="flex flex-col w-full gap-y-lg py-lg flex-1">{children}</div>
24+
</div>
2425
</main>
2526
);
2627
}
27-
28-
export default ProtectedLayout;
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright (c) 2025 IOTA Stiftung
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { Card, CardBody, CardType, Header, Panel } from '@iota/apps-ui-kit';
5+
import { useEffect, useState } from 'react';
6+
7+
import { useNameTree } from '@/hooks/useNameTree';
8+
import { RegistrationNft } from '@/lib/interfaces';
9+
import { NameTree } from '@/lib/utils/buildNameTree';
10+
import { formatNameLabel, normalizeName } from '@/lib/utils/format/formatNames';
11+
12+
interface SubnamesPanelProps {
13+
selectedName: RegistrationNft;
14+
onClose: () => void;
15+
}
16+
17+
export function SubnamesPanel({ selectedName, onClose }: SubnamesPanelProps) {
18+
const nftName = normalizeName(selectedName.name);
19+
const rootTree = useNameTree(nftName);
20+
21+
const [navigationStack, setNavigationStack] = useState<NameTree[]>([]);
22+
23+
useEffect(() => {
24+
if (rootTree) {
25+
setNavigationStack([rootTree]);
26+
}
27+
}, [rootTree]);
28+
29+
const currentNode = navigationStack[navigationStack.length - 1];
30+
31+
const goBack = () => {
32+
setNavigationStack((prev) => (prev.length > 1 ? prev.slice(0, -1) : prev));
33+
};
34+
35+
const goDeeper = (childName: string) => {
36+
const child = currentNode?.subnames.find((n) => n.name === childName);
37+
if (child) {
38+
setNavigationStack((prev) => [...prev, child]);
39+
}
40+
};
41+
42+
if (!currentNode) return null;
43+
44+
const headerTitle = `Subnames for ${formatNameLabel(navigationStack.length > 1 ? currentNode.name : selectedName.name)}`;
45+
const isOnRoot = navigationStack.length === 1;
46+
47+
return (
48+
<div className="max-w-[360px] w-full">
49+
<Panel>
50+
<div className="w-full flex flex-row items-center justify-between">
51+
<Header
52+
onBack={isOnRoot ? undefined : goBack}
53+
title={headerTitle}
54+
onClose={onClose}
55+
/>
56+
</div>
57+
58+
<div className="flex flex-col gap-lg px-md">
59+
{currentNode.subnames.map((nft) => (
60+
<Card
61+
key={nft.name}
62+
type={CardType.Filled}
63+
onClick={() => goDeeper(nft.name)}
64+
>
65+
<CardBody title={nft.name} />
66+
</Card>
67+
))}
68+
</div>
69+
</Panel>
70+
</div>
71+
);
72+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Copyright (c) 2025 IOTA Stiftung
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
export enum GroupedNamesFilter {
5+
All = 'All',
6+
InAuction = 'In Auction',
7+
Owned = 'Owned',
8+
Subnames = 'Subnames',
9+
}

0 commit comments

Comments
 (0)