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
64 changes: 64 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -415,3 +415,67 @@ Before completing any code modification task, verify:
- Generate docs: `npx gitnexus wiki`

<!-- gitnexus:end -->

---

# Implementation Protocol

Applies when a task is a **feature or touches 3+ files**. For smaller changes
(1-2 files, typo, question, research-only), skip this protocol and work normally.

## Preconditions (first step)
- **git**: if the repo is under git, the commit rule is active. If not, skip
commits and note `Commit: N/A (no git)` in the diary.
- **clawmem**: check the index (`index_stats` / `status`). If not indexed, index
it first (`reindex`; add the project to `~/.config/clawmem/index.yml` if
needed), then continue. If indexing is impossible, mirror the durable summary
into the diary with `clawmem: N/A`.

## 1. Prior-art search (before planning)
Search whether this was built or researched before:
- **clawmem**: `search` / `intent_search` / `find_similar` on the feature topic
- **git**: `git log --grep` and `git log -S`
- **tasks**: grep past diaries in `.tasks/`

Record findings in the diary. Reuse what exists, or state why you build anew.

## 2. Diary (`.tasks/`, gitignored)
Create `.tasks/YYYY-MM-DD-<slug>.md` first. One file per task. The agent only
creates and appends — it never deletes (the human cleans manually).

Structure:
- **Plan**: checklist of tickets (T1, T2, …)
- **Prior art**: clawmem / git / tasks findings + conclusion
- **Per ticket on close**: what done, how, deviations from plan + why, research,
commit hash (if git), clawmem id

## 3. Stages & commits
A **stage = an atomic, revertable unit** that can be described as one change.
Group tickets into a stage by this criterion, not by ticket count.

On closing a stage → commit. The message is detailed and natural, the way a
person writes it:
- **what** changed (files / modules)
- **why** (the problem it solves)
- **how** (approach, key decisions)
- **deviations** from plan, and research if it shaped the decision

The commit message MUST stay sterile: no task slug, no clawmem id, no mention of
`.tasks/`, clawmem, or this protocol, and no `Co-Authored-By` / "Generated with"
trailer. The commit is the only artifact that leaves the machine.

## 4. clawmem (per stage + final)
- **Per stage**: a durable entry mirroring the commit content (what / how /
deviations / research) plus the commit hash.
- **On task completion**: pin a final summary (`memory_pin`) — outcome, key
decisions, pitfalls. This survives diary cleanup and is what the next task's
prior-art search finds.

## 5. The linked graph (wiring lives on the private side only)
Join key = **commit hash** (a hash reveals nothing about the system).
- diary ticket stores: commit hash + clawmem id
- clawmem entry stores: commit hash + task slug
- commit stores: nothing pointing back

From any node, reach the other two via the hash. The commit stays clean; the
working artifacts (slug, ids, diaries) never leave the machine.
64 changes: 64 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -484,3 +484,67 @@ Before completing any code modification task, verify:

<!-- gitnexus:end -->
- Run `yarn build` before pushing

---

# Implementation Protocol

Applies when a task is a **feature or touches 3+ files**. For smaller changes
(1-2 files, typo, question, research-only), skip this protocol and work normally.

## Preconditions (first step)
- **git**: if the repo is under git, the commit rule is active. If not, skip
commits and note `Commit: N/A (no git)` in the diary.
- **clawmem**: check the index (`index_stats` / `status`). If not indexed, index
it first (`reindex`; add the project to `~/.config/clawmem/index.yml` if
needed), then continue. If indexing is impossible, mirror the durable summary
into the diary with `clawmem: N/A`.

## 1. Prior-art search (before planning)
Search whether this was built or researched before:
- **clawmem**: `search` / `intent_search` / `find_similar` on the feature topic
- **git**: `git log --grep` and `git log -S`
- **tasks**: grep past diaries in `.tasks/`

Record findings in the diary. Reuse what exists, or state why you build anew.

## 2. Diary (`.tasks/`, gitignored)
Create `.tasks/YYYY-MM-DD-<slug>.md` first. One file per task. The agent only
creates and appends — it never deletes (the human cleans manually).

Structure:
- **Plan**: checklist of tickets (T1, T2, …)
- **Prior art**: clawmem / git / tasks findings + conclusion
- **Per ticket on close**: what done, how, deviations from plan + why, research,
commit hash (if git), clawmem id

## 3. Stages & commits
A **stage = an atomic, revertable unit** that can be described as one change.
Group tickets into a stage by this criterion, not by ticket count.

On closing a stage → commit. The message is detailed and natural, the way a
person writes it:
- **what** changed (files / modules)
- **why** (the problem it solves)
- **how** (approach, key decisions)
- **deviations** from plan, and research if it shaped the decision

The commit message MUST stay sterile: no task slug, no clawmem id, no mention of
`.tasks/`, clawmem, or this protocol, and no `Co-Authored-By` / "Generated with"
trailer. The commit is the only artifact that leaves the machine.

## 4. clawmem (per stage + final)
- **Per stage**: a durable entry mirroring the commit content (what / how /
deviations / research) plus the commit hash.
- **On task completion**: pin a final summary (`memory_pin`) — outcome, key
decisions, pitfalls. This survives diary cleanup and is what the next task's
prior-art search finds.

## 5. The linked graph (wiring lives on the private side only)
Join key = **commit hash** (a hash reveals nothing about the system).
- diary ticket stores: commit hash + clawmem id
- clawmem entry stores: commit hash + task slug
- commit stores: nothing pointing back

From any node, reach the other two via the hash. The commit stays clean; the
working artifacts (slug, ids, diaries) never leave the machine.
19 changes: 10 additions & 9 deletions messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,8 @@
"networksValue": "1000",
"ecosystems": "Ecosystems",
"ecosystemsValue": "2345",
"tvl": "TVL",
"tvlValue": "$74.6B",
"dominance": "Dominance:",
"pow": "POW 56%",
"cosmos": "Cosmos 56%",
"eth": "ETH 56%",
"polkadot": "Polkadot 56%"
"totalFdv": "Total FDV",
"dominance": "Dominance:"
},
"links": {
"forum": "Forum",
Expand All @@ -141,8 +136,14 @@
"infrastructureText": "Built and run on our own off-grid Atlantic bare-metal servers. Open-source. Ad-free. Privacy-respecting. By the Citizen Web3 team.",
"askExpert": "Ask the Validator Expert",
"topPerformers": "Top Performers & Highlights",
"placeholderName": "Name",
"topPerformersNote": "Short and visual overview of the top performers.",
"highlights": {
"stakeTop": "Top Validators by Stake",
"delegatorsTop": "Top Validators by Delegators",
"priceGainers": "Top Networks — 24h Price Gainers",
"aprTop": "Top Networks by APR",
"fdvTop": "Top Networks by FDV",
"uptimeTop": "Top Validators by Uptime"
},
"quickTools": {
"bestValidator": "Best Validator for Me",
"maxYield": "Max Yield Right Now",
Expand Down
19 changes: 10 additions & 9 deletions messages/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,8 @@
"networksValue": "1000",
"ecosystems": "Ecossistemas",
"ecosystemsValue": "2345",
"tvl": "TVL",
"tvlValue": "$74.6B",
"dominance": "Domínio:",
"pow": "POW 56%",
"cosmos": "Cosmos 56%",
"eth": "ETH 56%",
"polkadot": "Polkadot 56%"
"totalFdv": "FDV Total",
"dominance": "Domínio:"
},
"links": {
"forum": "Forum",
Expand All @@ -141,8 +136,14 @@
"infrastructureText": "Criado e operado em nossos próprios servidores bare-metal off-grid no Atlântico. Open-source. Sem anúncios. Respeita a privacidade. Pela equipe Citizen Web3.",
"askExpert": "Pergunte ao Especialista Validator",
"topPerformers": "Principais desempenhos e destaques",
"placeholderName": "Nome",
"topPerformersNote": "Visão curta e visual dos principais destaques.",
"highlights": {
"stakeTop": "Principais validadores por stake",
"delegatorsTop": "Principais validadores por delegadores",
"priceGainers": "Principais redes — maiores altas de 24h",
"aprTop": "Principais redes por APR",
"fdvTop": "Principais redes por FDV",
"uptimeTop": "Principais validadores por uptime"
},
"quickTools": {
"bestValidator": "Melhor validador para mim",
"maxYield": "Maior rendimento agora",
Expand Down
19 changes: 10 additions & 9 deletions messages/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,8 @@
"networksValue": "1000",
"ecosystems": "Экосистемы",
"ecosystemsValue": "2345",
"tvl": "TVL",
"tvlValue": "$74.6B",
"dominance": "Доминирование:",
"pow": "POW 56%",
"cosmos": "Cosmos 56%",
"eth": "ETH 56%",
"polkadot": "Polkadot 56%"
"totalFdv": "Общий FDV",
"dominance": "Доминирование:"
},
"links": {
"forum": "Forum",
Expand All @@ -141,8 +136,14 @@
"infrastructureText": "Построено и работает на наших собственных off-grid bare-metal серверах в Атлантике. Open-source. Без рекламы. Уважает приватность. Команда Citizen Web3.",
"askExpert": "Спросите эксперта Validator",
"topPerformers": "Лучшие показатели и основные моменты",
"placeholderName": "Имя",
"topPerformersNote": "Короткий и визуальный обзор лучших результатов.",
"highlights": {
"stakeTop": "Топ валидаторов по стейку",
"delegatorsTop": "Топ валидаторов по делегаторам",
"priceGainers": "Топ сетей — рост цены за 24ч",
"aprTop": "Топ сетей по APR",
"fdvTop": "Топ сетей по FDV",
"uptimeTop": "Топ валидаторов по аптайму"
},
"quickTools": {
"bestValidator": "Лучший валидатор для меня",
"maxYield": "Максимальная доходность сейчас",
Expand Down
34 changes: 19 additions & 15 deletions src/app/[locale]/components/home/stats-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@ import { getTranslations } from 'next-intl/server';
import ecosystemService from '@/services/ecosystem-service';
import HeaderInfoService from '@/services/headerInfo-service';
import MetricPair from '@/components/home/metic-pair';
import formatCash from '@/utils/format-cash';


const StatsTable = async () => {
const t = await getTranslations('HomePage');
const [headerInfo, ecosystems] = await Promise.all([
const [headerInfo, ecosystems, fdvInfo] = await Promise.all([
HeaderInfoService.getValidatorsAndChains(),
ecosystemService.getAll(),
HeaderInfoService.getFdvAndDominance(),
]);

const totalFdvValue = fdvInfo.totalFdv > 0 ? `$${formatCash(fdvInfo.totalFdv)}` : '—';

const metricPairs = [
{
label: t('stats.validators'),
Expand All @@ -35,8 +39,6 @@ const StatsTable = async () => {
},
];

const dominanceItems = ['pow', 'cosmos', 'eth', 'polkadot'] as const;

return (
<section className="min-w-0">
<div className="grid min-w-0 gap-x-10 2xl:grid-cols-2">
Expand All @@ -54,22 +56,24 @@ const StatsTable = async () => {
className="tvl-page-jump mt-2 flex w-full flex-col bg-table_row text-left transition-all duration-75 hover:bg-bgHover 2xl:flex-row"
>
<div
className="flex min-h-24 cursor-pointer items-center border-b border-bgSt py-7 pl-7 pr-4 font-sfpro text-5xl sm:min-h-16 sm:py-5 sm:pl-5 sm:text-3xl md:min-h-16 md:py-5 md:pl-10 md:pr-3 md:text-lg 2xl:w-32 2xl:border-r">
{t('stats.tvl')}
className="flex min-h-24 cursor-pointer items-center whitespace-nowrap border-b border-bgSt py-7 pl-7 pr-4 font-sfpro text-5xl sm:min-h-16 sm:py-5 sm:pl-5 sm:text-3xl md:min-h-16 md:py-5 md:pl-10 md:pr-3 md:text-lg 2xl:w-48 2xl:border-r">
{t('stats.totalFdv')}
</div>
<div
className="flex min-h-24 min-w-0 flex-1 flex-col gap-5 border-b border-bgSt py-7 pl-7 pr-5 sm:min-h-16 sm:gap-3 sm:py-5 sm:pl-5 md:min-h-16 md:py-5 md:pl-6 md:pr-4 2xl:flex-row 2xl:items-center">
<span
className="font-handjet text-5xl sm:text-3xl md:text-lg hover:text-highlight">{t('stats.tvlValue')}</span>
<div
className="flex min-w-0 flex-wrap items-center justify-center gap-x-7 gap-y-3 text-center sm:gap-y-2 2xl:flex-1">
<span className="font-sfpro text-5xl sm:text-3xl md:text-lg mr-10">{t('stats.dominance')}</span>
{dominanceItems.map((item) => (
<span key={item} className="font-handjet text-5xl sm:text-3xl md:text-lg px-10 hover:text-highlight">
{t(`stats.${item}`)}
</span>
))}
</div>
className="font-handjet text-5xl sm:text-3xl md:text-lg hover:text-highlight">{totalFdvValue}</span>
{fdvInfo.dominance.length > 0 && (
<div
className="flex min-w-0 flex-wrap items-center justify-center gap-x-7 gap-y-3 text-center sm:gap-y-2 2xl:flex-1">
<span className="font-sfpro text-5xl sm:text-3xl md:text-lg mr-10">{t('stats.dominance')}</span>
{fdvInfo.dominance.map((item) => (
<span key={item.name} className="font-handjet text-5xl sm:text-3xl md:text-lg px-10 hover:text-highlight">
{item.name} {item.share.toFixed(1)}%
</span>
))}
</div>
)}
</div>
</div>
</section>
Expand Down
60 changes: 45 additions & 15 deletions src/app/[locale]/components/home/top-performers.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,58 @@
import Image from 'next/image';
import Link from 'next/link';
import { getTranslations } from 'next-intl/server';

import icons from '@/components/icons';
import topPerformersService, { HighlightRow } from '@/services/top-performers-service';

const rowClassName =
'flex h-20 shrink-0 items-center gap-5 border-t border-bgSt px-6 hover:bg-bgHover last:border-b last:border-bgSt sm:h-14 sm:gap-4 sm:px-4 md:h-10 md:gap-5 md:px-3.5';

const RowContent = ({ row }: { row: HighlightRow }) => (
<>
<Image
src={row.logoUrl || icons.AvatarIcon}
alt={row.name}
width={40}
height={40}
className="h-10 w-10 shrink-0 rounded-full border border-white/40 object-contain sm:h-7 sm:w-7 md:h-5 md:w-5"
/>
<span className="min-w-0 flex-1 truncate font-sfpro text-5xl font-light tracking-normal text-white/90 sm:text-2xl md:text-base">
{row.name}
</span>
<span className="shrink-0 font-handjet text-5xl tracking-normal text-highlight sm:text-2xl md:text-base">
{row.value}
</span>
</>
);

const TopPerformers = async () => {
const t = await getTranslations('HomePage');
const { titleKey, rows } = await topPerformersService.getDailyHighlights();

return (
<section className="min-w-0 border border-bgSt bg-table_row shadow-button">
<div className="px-6 pb-5 pt-4 sm:px-4 sm:pb-3 sm:pt-2 md:px-4 md:pb-3 md:pt-2">
<section className="flex min-h-80 min-w-0 flex-col overflow-hidden border border-bgSt bg-table_row shadow-button md:h-[28rem] md:min-h-[28rem]">
<div className="shrink-0 px-6 pb-5 pt-4 sm:px-4 sm:pb-3 sm:pt-2 md:px-4 md:pb-3 md:pt-2">
<div className="inline-flex border-b border-bgSt pb-1 pr-5">
<h2 className="font-handjet text-5xl font-medium tracking-normal text-highlight sm:text-3xl md:text-xl">{t('topPerformers')}</h2>
<h2 className="font-handjet text-5xl font-medium tracking-normal text-highlight sm:text-3xl md:text-xl">
{t('topPerformers')}
</h2>
</div>
<p className="mt-2 font-sfpro text-2xl text-white/60 sm:text-lg md:text-sm">{t(`highlights.${titleKey}`)}</p>
</div>

<div className="flex max-h-[60rem] flex-col overflow-y-auto sm:max-h-[40rem] md:max-h-[24rem]">
{Array.from({ length: 15 }).map((_, index) => (
<div
key={index}
className="flex h-20 shrink-0 items-center gap-5 border-t border-bgSt px-6 hover:bg-bgHover last:border-b last:border-bgSt sm:h-14 sm:gap-4 sm:px-4 md:h-10 md:gap-5 md:px-3.5"
>
<span className="h-10 w-10 rounded-full border border-white/40 bg-white/80 sm:h-7 sm:w-7 md:h-5 md:w-5" aria-hidden />
<span className="font-sfpro text-5xl font-light tracking-normal text-white/90 sm:text-2xl md:text-base">
{t('placeholderName')}
</span>
</div>
))}
<div className="flex flex-1 flex-col overflow-y-auto">
{rows.map((row, index) =>
row.href ? (
<Link key={`${row.name}-${index}`} href={row.href} className={rowClassName}>
<RowContent row={row} />
</Link>
) : (
<div key={`${row.name}-${index}`} className={rowClassName}>
<RowContent row={row} />
</div>
),
)}
</div>
</section>
);
Expand Down
Loading
Loading