Skip to content
Closed
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
5 changes: 5 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
- Break down complex files into separate files with specific functions to improve readability and maintainability
- Keep functions small and single-purpose
- Extract reusable logic into separate utilities or hooks
- Do not add comment to everything, explain it in the Chat but only add comments in the code where necessary for clarity (complex logic, important notes)
- Do not add JSDoc comments unless specifically requested (no @param or @returns etc, we use TypeScript)
- When you edit test files, run tests using VSCode test explorer instead of the terminal.
- Do not create unused function that might be useful later, only implement what is needed for the current task
- When you spend some time understanding the code, add a brief summary on this file (./.github/copilot-instructions.md) on the most suitable section

### Development Practices

Expand Down
115 changes: 84 additions & 31 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,42 +28,95 @@
content="https://algonoderewards.com/preview.png"
/>
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
<style>
/* Loading spinner styles */
#app-loading {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
background-color: rgb(249 250 251);
}
#app-loading .spinner {
width: 48px;
height: 48px;
border: 4px solid rgb(229 231 235);
border-top-color: rgb(99 102 241);
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* Hide SEO content visually but keep for crawlers */
.seo-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
/* Dark mode support */
@media (prefers-color-scheme: dark) {
#app-loading {
background-color: rgb(17 24 39);
}
#app-loading .spinner {
border-color: rgb(55 65 81);
border-top-color: rgb(129 140 248);
}
}
</style>
</head>
<body class="flex min-h-screen flex-col" id="root">
<header
class="mx-auto w-full max-w-7xl px-2 sm:px-4 lg:divide-y lg:divide-gray-200 lg:px-8"
>
<div class="relative mr-auto flex h-16 justify-between">
<div class="relative z-10 flex px-2 lg:px-0">
<div class="flex items-center">
<a href="/" class="flex items-center gap-2">
<img
alt="Algo Node Rewards"
height="32"
src="/logo.png"
class="h-8 w-auto"
/>
<span class="text-lg">Algo Node Rewards</span>
</a>
<!-- Loading spinner shown immediately -->
<div id="app-loading">
<div class="spinner"></div>
</div>

<!-- SEO content - hidden from users but visible to crawlers -->
<div class="seo-only">
<header
class="mx-auto w-full max-w-7xl px-2 sm:px-4 lg:divide-y lg:divide-gray-200 lg:px-8"
>
<div class="relative mr-auto flex h-16 justify-between">
<div class="relative z-10 flex px-2 lg:px-0">
<div class="flex items-center">
<a href="/" class="flex items-center gap-2">
<img
alt="Algo Node Rewards"
height="32"
src="/logo.png"
class="h-8 w-auto"
/>
<span class="text-lg">Algo Node Rewards</span>
</a>
</div>
</div>
</div>
</div>
</header>
<main class="flex-grow">
<div class="mx-auto max-w-2xl py-32 sm:py-48 lg:py-56">
<div class="relative p-6 text-center">
<h1
class="text-5xl font-semibold tracking-tight text-balance text-gray-900 sm:text-7xl"
>
Cool stats for your Algorand staking rewards
</h1>
<p>
Get your total node rewards and identify peak performance periods
with our detailed rewards heatmap
</p>
</header>
<main class="grow">
<div class="mx-auto max-w-2xl py-32 sm:py-48 lg:py-56">
<div class="relative p-6 text-center">
<h1
class="text-5xl font-semibold tracking-tight text-balance text-gray-900 sm:text-7xl"
>
Cool stats for your Algorand staking rewards
</h1>
<p>
Get your total node rewards and identify peak performance periods
with our detailed rewards heatmap
</p>
</div>
</div>
</div>
</main>
</main>
</div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
74 changes: 74 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-label": "^2.1.8",
"@radix-ui/react-popover": "^1.1.15",
"@radix-ui/react-progress": "^1.1.8",
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-slider": "^1.3.6",
"@radix-ui/react-slot": "^1.2.4",
Expand Down Expand Up @@ -85,6 +86,7 @@
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.4.24",
"fake-indexeddb": "^6.2.5",
"globals": "^16.5.0",
"jsdom": "^27.2.0",
"mockdate": "^3.0.5",
Expand Down
30 changes: 24 additions & 6 deletions src/components/address/address-breadcrumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import {
} from "@/components/ui/tooltip.tsx";
import Settings from "./settings.tsx";
import { useTheme } from "@/components/theme-provider";
import { Block } from "algosdk/client/indexer";
import { MinimalBlock } from "@/lib/block-types";
import { RefreshButton } from "./refresh-button";
import { useNFDReverseMultiple } from "@/queries/useNFD";

const AddressBreadcrumb = ({
resolvedAddresses,
Expand All @@ -29,9 +31,23 @@ const AddressBreadcrumb = ({
setShowFilters: (show: boolean) => void;
showAddAddress: boolean;
setShowAddAddress: (show: boolean) => void;
blocks: Block[];
blocks: MinimalBlock[];
}) => {
const { theme } = useTheme();

// Fetch NFD names for all addresses
const addresses = resolvedAddresses.map((addr) => addr.address);
const { data: nfdMap = {} } = useNFDReverseMultiple(addresses);

// Get display name for an address (NFD name with .algo suffix if available)
const getDisplayName = (address: string, short = false) => {
const nfdName = nfdMap[address];
if (nfdName) {
return `${nfdName}.algo`;
}
return short ? displayAlgoAddress(address) : address;
};

return (
<nav aria-label="Breadcrumb" className="flex justify-between">
<ol role="list" className="flex items-center space-x-4">
Expand Down Expand Up @@ -61,7 +77,7 @@ const AddressBreadcrumb = ({
<Skeleton className="h-4 w-32" />
)}
{resolvedAddresses.length === 1 &&
(resolvedAddresses[0].nfd ?? resolvedAddresses[0].address)}
getDisplayName(resolvedAddresses[0].address)}
{resolvedAddresses.length > 1 &&
`Multiple addresses (${resolvedAddresses.length})`}
</a>
Expand All @@ -74,8 +90,7 @@ const AddressBreadcrumb = ({
<Skeleton className="h-4 w-24" />
)}
{resolvedAddresses.length === 1 &&
(resolvedAddresses[0].nfd ??
displayAlgoAddress(resolvedAddresses[0].address))}
getDisplayName(resolvedAddresses[0].address, true)}
{resolvedAddresses.length > 1 && "Multiple addresses"}
</a>

Expand Down Expand Up @@ -132,7 +147,10 @@ const AddressBreadcrumb = ({
</div>
</li>
</ol>
<Settings blocks={blocks} />
<div className="flex gap-2">
<RefreshButton />
<Settings blocks={blocks} />
</div>
</nav>
);
};
Expand Down
Loading