From 1c8f1a15ab65328312044a732e096539463d7c7d Mon Sep 17 00:00:00 2001 From: Bruno Date: Thu, 13 Aug 2026 13:19:32 -0300 Subject: [PATCH 01/39] feat(dashboard): replace the panel header with the v2.1 hero The panel's TheSectionLayout title/description is replaced by the two-card hero from the Panel v2.1 spec: a judgment headline, a subhead framing the Stage system, and a link to the framework docs beside a "Governance risk, right now" card. DaoProtectionLevels moves from vertical Recharts bars to the horizontal Stage 0/1/2 bars in the design, sized against the busiest stage, with the per-stage hover kept on the design-system tooltip. Treasury Monitoring and Delegated Supply History are retired with no replacement cards, per spec. Co-Authored-By: Claude Opus 5 (1M context) --- .changeset/panel-v21-hero.md | 5 + .../dashboard/features/panel/PanelSection.tsx | 64 ++--- .../panel/components/DaoProtectionLevels.tsx | 248 +++++++----------- .../components/DelegatedSupplyHistory.tsx | 239 ----------------- .../features/panel/components/PanelHero.tsx | 40 +++ .../panel/components/TreasuryMonitoring.tsx | 81 ------ .../features/panel/components/index.ts | 3 +- .../tooltips/DaoProtectionLevelsTooltip.tsx | 57 ---- 8 files changed, 159 insertions(+), 578 deletions(-) create mode 100644 .changeset/panel-v21-hero.md delete mode 100644 apps/dashboard/features/panel/components/DelegatedSupplyHistory.tsx create mode 100644 apps/dashboard/features/panel/components/PanelHero.tsx delete mode 100644 apps/dashboard/features/panel/components/TreasuryMonitoring.tsx delete mode 100644 apps/dashboard/features/panel/components/tooltips/DaoProtectionLevelsTooltip.tsx diff --git a/.changeset/panel-v21-hero.md b/.changeset/panel-v21-hero.md new file mode 100644 index 0000000000..d51ced250c --- /dev/null +++ b/.changeset/panel-v21-hero.md @@ -0,0 +1,5 @@ +--- +"@anticapture/dashboard": minor +--- + +Replace the Panel section header with the v2.1 hero: a judgment headline, a subhead explaining the Stage framework, a link to the framework docs, and a "Governance risk, right now" card showing Stage 0/1/2 as horizontal bars with per-stage hover detail. Retires the Treasury Monitoring and Delegated Supply History cards. diff --git a/apps/dashboard/features/panel/PanelSection.tsx b/apps/dashboard/features/panel/PanelSection.tsx index b528b264ae..9d8bd2adb4 100644 --- a/apps/dashboard/features/panel/PanelSection.tsx +++ b/apps/dashboard/features/panel/PanelSection.tsx @@ -1,59 +1,25 @@ -import { BarChart4 } from "lucide-react"; - -import { - PanelTable, - DelegatedSupplyHistory, - DaoProtectionLevels, - TreasuryMonitoring, -} from "@/features/panel/components"; -import { TheSectionLayout } from "@/shared/components"; -import { Carousel } from "@/shared/components/design-system/carousel/Carousel"; -import { DividerDefault } from "@/shared/components/design-system/divider/DividerDefault"; +import { PanelHero } from "@/features/panel/components/PanelHero"; +import { PanelTable } from "@/features/panel/components/PanelTable"; import { SubSection, SubSectionsContainer, } from "@/shared/components/design-system/section"; -import { PAGES_CONSTANTS } from "@/shared/constants/pages-constants"; export const PanelSection = () => { return ( - } - description={PAGES_CONSTANTS.panel.description} - className="mt-12 lg:mt-0 lg:min-h-0" - > -
-
- , - , - , - ]} - /> -
-
- - - -
- -
- -
+
+ - - - - - -
- + + + + + +
); }; diff --git a/apps/dashboard/features/panel/components/DaoProtectionLevels.tsx b/apps/dashboard/features/panel/components/DaoProtectionLevels.tsx index 356c17726e..17da5d5bd2 100644 --- a/apps/dashboard/features/panel/components/DaoProtectionLevels.tsx +++ b/apps/dashboard/features/panel/components/DaoProtectionLevels.tsx @@ -1,14 +1,8 @@ "use client"; -import { ChevronRight } from "lucide-react"; import { useMemo } from "react"; -import { BarChart, Bar, XAxis, Cell, LabelList, Tooltip } from "recharts"; -import { DaoProtectionLevelsTooltip } from "@/features/panel/components/tooltips/DaoProtectionLevelsTooltip"; -import { DividerDefault } from "@/shared/components/design-system/divider/DividerDefault"; -import { DefaultLink } from "@/shared/components/design-system/links/default-link"; -import type { ChartConfig } from "@/shared/components/ui/chart"; -import { ChartContainer } from "@/shared/components/ui/chart"; +import { Tooltip } from "@/shared/components/design-system/tooltips/Tooltip"; import daoConfigByDaoId from "@/shared/dao-config"; import { fieldsToArray, @@ -16,164 +10,118 @@ import { } from "@/shared/dao-config/utils"; import { DaoIdEnum } from "@/shared/types/daos"; import { Stage } from "@/shared/types/enums/Stage"; +import { cn } from "@/shared/utils/cn"; -const chartConfig: ChartConfig = { - value: { - label: "Value", - color: "var(--color-primary)", +/* Bars are sized against the busiest stage, so the widest bar always fills the track. */ +const EMPTY_BAR_WIDTH = "0.5rem"; + +const STAGE_BARS = [ + { + stage: Stage.ZERO, + label: "Stage 0", + riskLevel: "High Risk", + labelClassName: "text-error", + barClassName: "bg-error", + description: + "DAOs that have a critical weakness that could let an attacker influence or take over governance", + }, + { + stage: Stage.ONE, + label: "Stage 1", + riskLevel: "Medium Risk", + labelClassName: "text-warning", + barClassName: "bg-warning", + description: + "DAOs that have no critical weaknesses, but still have a medium-risk issue that could affect governance.", + }, + { + stage: Stage.TWO, + label: "Stage 2", + riskLevel: "Low Risk", + labelClassName: "text-success", + barClassName: "bg-success", + description: + "DAOs with no significant risks and strong protection against governance attacks.", }, -} satisfies ChartConfig; +] as const; export const DaoProtectionLevels = () => { - // Calculate stage distribution from real DAO data - const stageData = useMemo(() => { - // Get all DAOs - const daoIds = Object.values(DaoIdEnum); + const stageCounts = useMemo(() => { + const counts: Partial> = {}; - // Count DAOs by stage - const stageCounts = { - [Stage.ZERO]: 0, - [Stage.ONE]: 0, - [Stage.TWO]: 0, - [Stage.UNKNOWN]: 0, - [Stage.NONE]: 0, - }; - - daoIds.forEach((daoId) => { + Object.values(DaoIdEnum).forEach((daoId) => { const daoConfig = daoConfigByDaoId[daoId]; - let stage: Stage; - - if (!daoConfig.governanceImplementation) { - stage = Stage.UNKNOWN; - } else { - stage = getDaoStageFromFields({ - fields: fieldsToArray(daoConfig.governanceImplementation?.fields), - noStage: daoConfig.noStage, - }); - } + const stage = daoConfig.governanceImplementation + ? getDaoStageFromFields({ + fields: fieldsToArray(daoConfig.governanceImplementation.fields), + noStage: daoConfig.noStage, + }) + : Stage.UNKNOWN; - stageCounts[stage] = (stageCounts[stage] || 0) + 1; + counts[stage] = (counts[stage] ?? 0) + 1; }); - // Map to chart data format - return [ - { - stage: "Stage 0", - value: stageCounts[Stage.ZERO], - riskLevel: "High Risk", - color: "var(--color-error)", - description: - "DAOs that have a critical weakness that could let an attacker influence or take over governance", - }, - { - stage: "Stage 1", - value: stageCounts[Stage.ONE], - riskLevel: "Medium Risk", - color: "var(--color-warning)", - description: - "DAOs that have no critical weaknesses, but still have a medium-risk issue that could affect governance.", - }, - { - stage: "Stage 2", - value: stageCounts[Stage.TWO], - riskLevel: "Low Risk", - color: "var(--color-success)", - description: - "DAOs with no significant risks and strong protection against governance attacks.", - }, - { - stage: "No Stage", - value: stageCounts[Stage.NONE], - riskLevel: "Doesn't apply", - color: "var(--color-surface-hover)", - description: - "DAOs that don't qualify for the staging system because they lack autonomous execution and rely on a centralized entity.", - }, - ]; + return counts; }, []); - // Calculate total monitored DAOs - const totalMonitored = useMemo(() => { - return Object.values(DaoIdEnum).length; - }, []); + const busiestStageCount = Math.max( + ...STAGE_BARS.map(({ stage }) => stageCounts[stage] ?? 0), + 1, + ); return ( -
-
-

- DAO Governance Risk Levels -

-

- This platform monitors DAO governance risks and rates them through - Anticapture's Stage system. -

- - Learn the Stage Criteria - - -
- - {/* Status indicators */} -
- -
-

- {totalMonitored} DAOs monitored by Anticapture -

-
- -
+
+

+ Governance risk, right now +

- {/* Bar Chart */} -
-
- - - - - - {stageData.map((entry, index) => ( - - ))} - value} - /> - - - -
+
+ {STAGE_BARS.map( + ({ + stage, + label, + riskLevel, + labelClassName, + barClassName, + description, + }) => { + const count = stageCounts[stage] ?? 0; - {/* Labels */} -
- {stageData.map((item, index) => ( -
-

- {item.stage} -

-

- {item.riskLevel} -

-
- ))} -
+ return ( +
+
+ {label} + {riskLevel} +
+ + {description} +

+ } + > +
+ + + {count} + +
+ ); + }, + )}
); diff --git a/apps/dashboard/features/panel/components/DelegatedSupplyHistory.tsx b/apps/dashboard/features/panel/components/DelegatedSupplyHistory.tsx deleted file mode 100644 index fc5ae256e5..0000000000 --- a/apps/dashboard/features/panel/components/DelegatedSupplyHistory.tsx +++ /dev/null @@ -1,239 +0,0 @@ -"use client"; - -import Lottie from "lottie-react"; -import { useMemo } from "react"; -import { - CartesianGrid, - Line, - LineChart, - XAxis, - YAxis, - Tooltip, -} from "recharts"; - -import loadingAnimation from "@/public/loading-animation.json"; -import { TooltipInfo } from "@/shared/components"; -import type { ChartConfig } from "@/shared/components/ui/chart"; -import { ChartContainer } from "@/shared/components/ui/chart"; -import { useDelegationPercentageByDay } from "@/shared/hooks"; - -const chartConfig: ChartConfig = { - delegatedSupply: { - label: "Delegated Supply", - color: "#FF6B6B", - }, -} satisfies ChartConfig; - -export const DelegatedSupplyHistory = () => { - // Calculate startDate as one year ago in seconds (Unix timestamp) - const startDate = useMemo(() => { - const oneYearAgo = new Date(); - oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1); - return Math.floor(oneYearAgo.getTime() / 1000); - }, []); - - // Calculate endDate as today at midnight UTC in seconds (Unix timestamp) - const endDate = useMemo(() => { - const today = new Date(); - today.setUTCHours(0, 0, 0, 0); - return Math.floor(today.getTime() / 1000); - }, []); - - const { data, loading, error } = useDelegationPercentageByDay( - startDate, - endDate, - ); - - // Transform data for chart - const chartData = useMemo(() => { - if (!data || data.length === 0) return []; - - return data - .map((item) => { - // Parse date string as Unix timestamp (seconds) and convert to Date - // Handle both string timestamps and ensure valid number - if (!item.date || item.date === "" || isNaN(Number(item.date))) { - console.warn("Invalid date value:", item.date); - return null; - } - - const timestamp = Number(item.date); - const date = new Date(timestamp * 1000); - - // Validate date - if (isNaN(date.getTime())) { - console.warn("Invalid date after parsing:", item.date, timestamp); - return null; - } - - const month = date.toLocaleDateString("en-US", { month: "short" }); - const year = date.getFullYear().toString().slice(-2); - const formattedDate = `${month} '${year}`; - - // Convert high (string) to percentage number - const percentage = parseFloat(item.high); - if (isNaN(percentage)) { - console.warn("Invalid percentage value:", item.high); - return null; - } - - return { - date: formattedDate, - percentage, - timestamp: date.getTime(), - originalDate: item.date, // Keep original for tooltip - }; - }) - .filter((item): item is NonNullable => item !== null); - }, [data]); - - // Calculate Y-axis domain and ticks with standard increments (5% or 10%) - const yAxisConfig = useMemo(() => { - if (!chartData || chartData.length === 0) { - return { - domain: [0, 10] as [number, number], - ticks: [0, 5, 10], - }; - } - - const percentages = chartData.map((item) => item.percentage); - const minValue = Math.min(...percentages); - const maxValue = Math.max(...percentages); - const range = maxValue - minValue; - - // Determine appropriate increment: use 5% for smaller ranges, 10% for larger ranges - const increment = range <= 15 ? 5 : 10; - - // Round down min to nearest multiple of increment, round up max to nearest multiple - const minDomain = Math.max(0, Math.floor(minValue / increment) * increment); - const maxDomain = Math.ceil(maxValue / increment) * increment; - - // Ensure minimum range for better visualization - const adjustedMaxDomain = - maxDomain - minDomain < increment * 2 - ? minDomain + increment * 2 - : maxDomain; - - // Generate ticks at standard intervals (5% or 10%) - const ticks: number[] = []; - for ( - let value = minDomain; - value <= adjustedMaxDomain; - value += increment - ) { - ticks.push(value); - } - - return { - domain: [minDomain, adjustedMaxDomain] as [number, number], - ticks, - }; - }, [chartData]); - - if (loading) { - return ( - -
- -
-
- ); - } - - if (error || !chartData || chartData.length === 0) { - return ( - -

No data available

-
- ); - } - - return ( - - - - - value} - /> - (value === 0 ? "0" : `${value}%`)} - tickLine={false} - axisLine={false} - tickMargin={8} - width={28} - tick={{ - fill: "var(--color-secondary)", - fontSize: 12, - fontFamily: "Inter", - fontWeight: 400, - }} - /> - { - if (!active || !payload?.length) return null; - const data = payload[0]; - return ( -
-

{label}

-

- {data.value}% -

-
- ); - }} - /> - -
-
-
- ); -}; - -const ContentWrapper = ({ children }: { children: React.ReactNode }) => { - const delegatedSupplyDescription = - "Shows how delegated supply changes over time in DAOs indexed by Anticapture. Lower delegation can make governance easier to influence."; - - const tooltipText = - "Delegation shows how much of the token supply actively participates in governance. When this share keeps falling, decisions depend on a shrinking group of voters, increasing the chance of concentrated influence across the ecosystem."; - - return ( -
-
-
-

- delegated supply history -

- -
-

- {delegatedSupplyDescription} -

-
-
- {children} -
-
- ); -}; diff --git a/apps/dashboard/features/panel/components/PanelHero.tsx b/apps/dashboard/features/panel/components/PanelHero.tsx new file mode 100644 index 0000000000..d32ce92f51 --- /dev/null +++ b/apps/dashboard/features/panel/components/PanelHero.tsx @@ -0,0 +1,40 @@ +import { ChevronRight } from "lucide-react"; + +import { DaoProtectionLevels } from "@/features/panel/components/DaoProtectionLevels"; +import { DefaultLink } from "@/shared/components/design-system/links/default-link/DefaultLink"; + +const FRAMEWORK_DOCS_URL = + "https://blockful.gitbook.io/anticapture/anticapture/framework"; + +export const PanelHero = () => { + return ( +
+
+
+

+ See which DAOs could be captured, and what it would cost an + attacker. +

+

+ Live governance-security risk for every DAO we monitor, scored by + our open Stage framework, showing how exposed each DAO is to hostile + capture. +

+
+ + How the framework works + + +
+ +
+ +
+
+ ); +}; diff --git a/apps/dashboard/features/panel/components/TreasuryMonitoring.tsx b/apps/dashboard/features/panel/components/TreasuryMonitoring.tsx deleted file mode 100644 index c8c4a0574e..0000000000 --- a/apps/dashboard/features/panel/components/TreasuryMonitoring.tsx +++ /dev/null @@ -1,81 +0,0 @@ -"use client"; - -import { TooltipInfo } from "@/shared/components"; -import { InlineAlert } from "@/shared/components/design-system/alerts/inline-alert/InlineAlert"; -import { formatNumberUserReadable } from "@/shared/utils"; - -// Fake data for now -const monitoringData = [ - { - title: "Treasury: Monitored vs Ecosystem total", - tooltip: - "Represents the funds held in DAO treasuries. The first value shows treasuries from DAOs monitored by Anticapture; the second shows the total across the ecosystem.", - current: 4100000000, // $4.1B - total: 16200000000, // $16.2B - percentage: 25, - }, - - // Fake data for now - { - title: "TVL: Monitored vs Ecosystem Total", - tooltip: - "Represents the total value locked in DAO contracts. The first value reflects DAOs monitored by Anticapture; the second shows the ecosystem-wide total.", - current: 5600000000, // $5.6B - total: 35100000000, // $35.1B - percentage: 16, - }, -]; - -export const TreasuryMonitoring = () => { - return ( -
-
- {monitoringData.map((item, index) => ( -
-
-

- {item.title} -

- - -
- -
- {/* Value display */} -
-

- {formatNumberUserReadable(item.current)} -

-

- / {formatNumberUserReadable(item.total)} -

-
- - {/* Progress bar */} -
-
-
-
-

- {item.percentage}% -

-
-
- {index < monitoringData.length - 1 && ( -
- )} -
- ))} -
- - {/* Alert */} - -
- ); -}; diff --git a/apps/dashboard/features/panel/components/index.ts b/apps/dashboard/features/panel/components/index.ts index 29a0403d94..fd2296f8d3 100644 --- a/apps/dashboard/features/panel/components/index.ts +++ b/apps/dashboard/features/panel/components/index.ts @@ -1,5 +1,4 @@ export * from "@/features/panel/components/PanelTable"; -export * from "@/features/panel/components/DelegatedSupplyHistory"; +export * from "@/features/panel/components/PanelHero"; export * from "@/features/panel/components/DaoProtectionLevels"; -export * from "@/features/panel/components/TreasuryMonitoring"; export * from "@/features/panel/components/TooltipCell"; diff --git a/apps/dashboard/features/panel/components/tooltips/DaoProtectionLevelsTooltip.tsx b/apps/dashboard/features/panel/components/tooltips/DaoProtectionLevelsTooltip.tsx deleted file mode 100644 index ffea5350bb..0000000000 --- a/apps/dashboard/features/panel/components/tooltips/DaoProtectionLevelsTooltip.tsx +++ /dev/null @@ -1,57 +0,0 @@ -"use client"; - -import type { TooltipProps } from "recharts"; - -type StageData = { - stage: string; - value: number; - riskLevel: string; - color: string; - description?: string; -}; - -export const DaoProtectionLevelsTooltip = ({ - active, - payload, - coordinate, -}: TooltipProps) => { - if ( - !active || - !payload?.length || - !coordinate || - coordinate.x === undefined || - coordinate.y === undefined - ) - return null; - - const data = payload[0]?.payload as StageData; - - return ( -
-
-
-
-

{data.stage}

-
- -

- {data.value} DAO{data.value !== 1 ? "s" : ""} -

-
- - {data.description && ( -

- {data.description} -

- )} -
- ); -}; From 8a21e306ddf5c947e1608150725b4ed257b0af10 Mon Sep 17 00:00:00 2001 From: Bruno Date: Thu, 13 Aug 2026 13:21:50 -0300 Subject: [PATCH 02/39] feat(dashboard): add the latest finding ticker to the panel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A one-line strip between the hero and the Monitored DAOs table: the LATEST FINDING label, the finding sentence, and a link out to the case write-up. The sentence and its URL come from a mock for now — swapping in a fetch of the newest Paragraph publication only has to replace the two fields the ticker reads. Co-Authored-By: Claude Opus 5 (1M context) --- .changeset/panel-v21-ticker.md | 5 ++++ .../dashboard/features/panel/PanelSection.tsx | 3 +++ .../panel/components/LatestFindingTicker.tsx | 25 +++++++++++++++++++ .../features/panel/components/index.ts | 1 + .../mocked-data/mocked-latest-finding.ts | 10 ++++++++ 5 files changed, 44 insertions(+) create mode 100644 .changeset/panel-v21-ticker.md create mode 100644 apps/dashboard/features/panel/components/LatestFindingTicker.tsx create mode 100644 apps/dashboard/shared/constants/mocked-data/mocked-latest-finding.ts diff --git a/.changeset/panel-v21-ticker.md b/.changeset/panel-v21-ticker.md new file mode 100644 index 0000000000..7a8b07fe91 --- /dev/null +++ b/.changeset/panel-v21-ticker.md @@ -0,0 +1,5 @@ +--- +"@anticapture/dashboard": minor +--- + +Add the "Latest finding" ticker between the panel hero and the Monitored DAOs table, linking out to the case write-up. The finding sentence is mocked until the Paragraph publication API is wired up. diff --git a/apps/dashboard/features/panel/PanelSection.tsx b/apps/dashboard/features/panel/PanelSection.tsx index 9d8bd2adb4..ecb05234e0 100644 --- a/apps/dashboard/features/panel/PanelSection.tsx +++ b/apps/dashboard/features/panel/PanelSection.tsx @@ -1,3 +1,4 @@ +import { LatestFindingTicker } from "@/features/panel/components/LatestFindingTicker"; import { PanelHero } from "@/features/panel/components/PanelHero"; import { PanelTable } from "@/features/panel/components/PanelTable"; import { @@ -10,6 +11,8 @@ export const PanelSection = () => {
+ + { + const { finding, caseUrl } = mockedLatestFinding; + + return ( +
+
+

+ Latest finding +

+

+ {finding} +

+
+ + Read the case + + +
+ ); +}; diff --git a/apps/dashboard/features/panel/components/index.ts b/apps/dashboard/features/panel/components/index.ts index fd2296f8d3..5262316659 100644 --- a/apps/dashboard/features/panel/components/index.ts +++ b/apps/dashboard/features/panel/components/index.ts @@ -1,4 +1,5 @@ export * from "@/features/panel/components/PanelTable"; export * from "@/features/panel/components/PanelHero"; +export * from "@/features/panel/components/LatestFindingTicker"; export * from "@/features/panel/components/DaoProtectionLevels"; export * from "@/features/panel/components/TooltipCell"; diff --git a/apps/dashboard/shared/constants/mocked-data/mocked-latest-finding.ts b/apps/dashboard/shared/constants/mocked-data/mocked-latest-finding.ts new file mode 100644 index 0000000000..443be9574f --- /dev/null +++ b/apps/dashboard/shared/constants/mocked-data/mocked-latest-finding.ts @@ -0,0 +1,10 @@ +/** + * Stand-in for the latest Paragraph publication rendered by the panel ticker. + * TODO(DEV-1148): replace with a server-side fetch of the newest post once the + * Paragraph API is wired up; the ticker only needs `finding` and `caseUrl`. + */ +export const mockedLatestFinding = { + finding: + "Uniswap: a low-cost path to a multi-billion-dollar treasury, quantified before it could be exploited.", + caseUrl: "https://paragraph.com/@blockful", +}; From 2c87e1eb62ab2d1c20b66e2cdda5c0c55c1ab4c4 Mon Sep 17 00:00:00 2001 From: Bruno Date: Thu, 13 Aug 2026 13:23:38 -0300 Subject: [PATCH 03/39] feat(dashboard): show every monitored DAO on the panel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v2.1 panel is a scrolling page, not a single viewport: drop the table's fillHeight and the min-h-0/flex-1 chain that made it scroll inside the section, and let main scroll on desktop the way it already does on mobile. The table itself is untouched — same columns, tooltips, and sorting. Co-Authored-By: Claude Opus 5 (1M context) --- .changeset/panel-v21-table-scroll.md | 5 +++++ apps/dashboard/app/page.tsx | 6 +++--- apps/dashboard/features/panel/PanelSection.tsx | 5 ++--- apps/dashboard/features/panel/components/PanelTable.tsx | 3 +-- 4 files changed, 11 insertions(+), 8 deletions(-) create mode 100644 .changeset/panel-v21-table-scroll.md diff --git a/.changeset/panel-v21-table-scroll.md b/.changeset/panel-v21-table-scroll.md new file mode 100644 index 0000000000..f3ac6c8a2c --- /dev/null +++ b/.changeset/panel-v21-table-scroll.md @@ -0,0 +1,5 @@ +--- +"@anticapture/dashboard": minor +--- + +Show every monitored DAO on the panel instead of scrolling the table inside a fixed-height viewport — the homepage itself now scrolls. diff --git a/apps/dashboard/app/page.tsx b/apps/dashboard/app/page.tsx index ba340f9a68..c686ea65d6 100644 --- a/apps/dashboard/app/page.tsx +++ b/apps/dashboard/app/page.tsx @@ -51,12 +51,12 @@ export default function Home() {
-
+
-
-
+
+