Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions assets/images/badge-verified.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/network-logos/igra-lockup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions assets/images/network-logos/kaspa-lockup-mark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions assets/images/network-logos/kaspa-lockup-text.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 0 additions & 24 deletions components/dashboard/INSItem.tsx

This file was deleted.

39 changes: 0 additions & 39 deletions components/dashboard/KNSItem.tsx

This file was deleted.

79 changes: 79 additions & 0 deletions components/dashboard/NameCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import badgeVerified from "@/assets/images/badge-verified.svg";
import kaspaLockupMark from "@/assets/images/network-logos/kaspa-lockup-mark.svg";
import kaspaLockupText from "@/assets/images/network-logos/kaspa-lockup-text.svg";
import igraLockup from "@/assets/images/network-logos/igra-lockup.png";

type NameCardProps = {
name: string;
source: "kas" | "igra";
isVerified?: boolean;
onClick: () => void;
};

// Design steps the name down through four sizes so long names still fit the
// 88px text box. Tracking is -2% at every step.
const nameSize = (length: number) => {
if (length <= 12) return "text-[16px]";
if (length <= 24) return "text-[14px]";
if (length <= 40) return "text-[12px]";
return "text-[10px]";
};

export default function NameCard({
name,
source,
isVerified,
onClick,
}: NameCardProps) {
return (
<button
type="button"
onClick={onClick}
title={name}
className="relative h-[120px] w-[104px] shrink-0 overflow-hidden rounded-[12px] border border-daintree-700 bg-[linear-gradient(201.32deg,#4ADCEF_14.46%,#00D7FF_31.38%,#0095F1_91.32%)] text-left hover:border-white"
>
{isVerified && (
<img
src={badgeVerified}
alt="verified"
// Badge box is 8x8 at right/top 10px; the asset is 14x14 because it
// carries the drop shadow as a 37.5% bleed on every side. Insetting
// by 7px lands the 8px glyph back on its designed position.
className="absolute right-[7px] top-[7px] size-[14px]"
/>
)}

<div className="absolute bottom-[8px] left-1/2 flex w-[88px] -translate-x-1/2 flex-col gap-[10px]">
<span
className={`h-[50.98px] overflow-hidden font-bold leading-normal tracking-[-0.02em] text-white [overflow-wrap:anywhere] ${nameSize(name.length)}`}
style={{ textShadow: "0px 0px 4px rgba(0,19,58,0.4)" }}
>
{name}
</span>

{source === "kas" ? (
// ponytail: two exported leaves rather than one merged file — the
// combined Figma export is a padded 39x18 box that would misalign.
<span className="relative block h-[10px] w-[30.8px]">
<img
src={kaspaLockupMark}
alt=""
className="absolute left-0 top-0 h-[10px] w-[10.0125px]"
/>
<img
src={kaspaLockupText}
alt=""
className="absolute left-[13.05px] top-[2.51px] h-[6.73626px] w-[17.7516px]"
/>
</span>
) : (
<img
src={igraLockup}
alt=""
className="h-[10px] w-[31.4px] [filter:drop-shadow(0_0_4px_rgba(0,19,58,0.4))]"
/>
)}
</div>
</button>
);
}
34 changes: 24 additions & 10 deletions components/dashboard/Names.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { useEffect, useRef } from "react";
import { useNavigate } from "react-router-dom";
import useWalletManager from "@/hooks/wallet/useWalletManager";
import useEvmAddress from "@/hooks/evm/useEvmAddress";
import { useAssetsByAddress } from "@/hooks/kns/useKns";
import { useInsDomainsByAddress } from "@/hooks/ins/useIns";
import KNSItem from "@/components/dashboard/KNSItem.tsx";
import INSItem from "@/components/dashboard/INSItem";
import NameCard from "@/components/dashboard/NameCard";

export default function Names() {
const navigate = useNavigate();
const { account } = useWalletManager();
const evmAddress = useEvmAddress();

Expand Down Expand Up @@ -46,9 +47,9 @@ export default function Names() {
(knsData?.[0]?.data?.assets?.length ?? 0) === 0;

return (
<div className="space-y-2 pb-4">
<div className="flex flex-wrap gap-[12px] pb-4">
{isEmpty && (
<div className="flex justify-center py-6 text-sm text-daintree-400">
<div className="flex w-full justify-center py-6 text-sm text-daintree-400">
No names found
</div>
)}
Expand All @@ -58,13 +59,19 @@ export default function Names() {
Array.from({ length: 2 }).map((_, index) => (
<div
key={index}
className="min-h-[72px] animate-pulse cursor-pointer rounded-xl border border-daintree-700 bg-daintree-800 p-3"
className="h-[120px] w-[104px] shrink-0 animate-pulse rounded-[12px] border border-daintree-700 bg-daintree-800"
/>
))}

{knsData?.flatMap((page) =>
page.data.assets.map((asset) => (
<KNSItem key={asset.assetId} asset={asset} />
<NameCard
key={asset.assetId}
name={asset.asset}
source="kas"
isVerified={asset.isVerifiedDomain}
onClick={() => navigate(`/kns/${asset.assetId}`)}
/>
)),
)}

Expand All @@ -73,18 +80,25 @@ export default function Names() {
Array.from({ length: 2 }).map((_, index) => (
<div
key={index}
className="min-h-[72px] animate-pulse cursor-pointer rounded-xl border border-daintree-700 bg-daintree-800 p-3"
className="h-[120px] w-[104px] shrink-0 animate-pulse rounded-[12px] border border-daintree-700 bg-daintree-800"
/>
))}

{insDomains.map((name) => (
<INSItem key={name} name={name} />
// No isVerified: INS exposes no verification flag, so the badge must
// stay absent rather than assert "verified" for every INS name.
<NameCard
key={name}
name={name}
source="igra"
onClick={() => navigate(`/ins/${name}`)}
/>
))}

<div ref={sentinelRef} className="h-1" />
<div ref={sentinelRef} className="h-1 w-full" />

{isKnsLoading && !knsFirstLoading && (
<div className="flex justify-center py-2">
<div className="flex w-full justify-center py-2">
<div
className="inline-block size-6 animate-spin rounded-full border-[6px] border-current border-t-[#A2F5FF] text-icy-blue-600"
role="status"
Expand Down
Loading