diff --git a/app/app/analytics/loading.tsx b/app/app/analytics/loading.tsx new file mode 100644 index 0000000..32a4ccc --- /dev/null +++ b/app/app/analytics/loading.tsx @@ -0,0 +1,22 @@ +'use client' + +import { ChartSkeleton } from '@/components/analytics/charts' + +export default function AnalyticsLoading() { + return ( +
+ {/* Header skeleton */} +
+
+
+
+ + {/* Charts skeleton */} +
+ {Array.from({ length: 4 }).map((_, i) => ( + + ))} +
+
+ ) +} diff --git a/app/app/create/batch/page.tsx b/app/app/create/batch/page.tsx index 430ada7..7fbd20f 100644 --- a/app/app/create/batch/page.tsx +++ b/app/app/create/batch/page.tsx @@ -301,7 +301,7 @@ export default function BatchCreatePage() { )} {parseErrors.length > 0 && ( -
+

CSV parse warnings

    {parseErrors.map((message, index) => ( @@ -344,7 +344,7 @@ export default function BatchCreatePage() { {rows.map((row) => ( 0 ? 'bg-red-50' : undefined} + className={row.errors.length > 0 ? 'bg-destructive/5 dark:bg-destructive/10' : undefined} > {row.index} @@ -361,7 +361,7 @@ export default function BatchCreatePage() { {row.errors.length === 0 ? ( - + Valid ) : ( diff --git a/app/app/create/loading.tsx b/app/app/create/loading.tsx new file mode 100644 index 0000000..86c991d --- /dev/null +++ b/app/app/create/loading.tsx @@ -0,0 +1,30 @@ +'use client' + +export default function CreateStreamLoading() { + return ( +
    + {/* Header skeleton */} +
    +
    +
    +
    + + {/* Form section skeleton */} +
    + {/* Form fields skeleton */} + {Array.from({ length: 6 }).map((_, i) => ( +
    +
    +
    +
    + ))} + + {/* Button skeleton */} +
    +
    +
    +
    +
    +
    + ) +} diff --git a/app/app/loading.tsx b/app/app/loading.tsx new file mode 100644 index 0000000..983b7e0 --- /dev/null +++ b/app/app/loading.tsx @@ -0,0 +1,26 @@ +'use client' + +import { DashboardStatsSkeleton } from '@/components/streams/dashboard-stats' +import { StreamCardSkeleton } from '@/components/streams/stream-card' + +export default function DashboardLoading() { + return ( +
    + {/* Header skeleton */} +
    +
    +
    +
    + + {/* Stats skeleton */} + + + {/* Stream list skeleton */} +
    + {Array.from({ length: 3 }).map((_, i) => ( + + ))} +
    +
    + ) +} diff --git a/app/app/settings/loading.tsx b/app/app/settings/loading.tsx new file mode 100644 index 0000000..d2cae16 --- /dev/null +++ b/app/app/settings/loading.tsx @@ -0,0 +1,28 @@ +'use client' + +export default function SettingsLoading() { + return ( +
    + {/* Header skeleton */} +
    +
    +
    +
    + + {/* Settings sections skeleton */} + {Array.from({ length: 3 }).map((_, i) => ( +
    +
    +
    + {Array.from({ length: 2 }).map((_, j) => ( +
    +
    +
    +
    + ))} +
    +
    + ))} +
    + ) +} diff --git a/app/app/stream/[id]/loading.tsx b/app/app/stream/[id]/loading.tsx new file mode 100644 index 0000000..24f5690 --- /dev/null +++ b/app/app/stream/[id]/loading.tsx @@ -0,0 +1,39 @@ +'use client' + +export default function StreamDetailLoading() { + return ( +
    + {/* Back button skeleton */} +
    + + {/* Header section skeleton */} +
    +
    +
    + {Array.from({ length: 4 }).map((_, i) => ( +
    +
    +
    +
    + ))} +
    +
    + + {/* Timeline/Activity section skeleton */} +
    +
    +
    + {Array.from({ length: 3 }).map((_, i) => ( +
    +
    +
    +
    +
    +
    +
    + ))} +
    +
    +
    + ) +} diff --git a/app/app/streams/loading.tsx b/app/app/streams/loading.tsx new file mode 100644 index 0000000..6121556 --- /dev/null +++ b/app/app/streams/loading.tsx @@ -0,0 +1,22 @@ +'use client' + +import { StreamCardSkeleton } from '@/components/streams/stream-card' + +export default function StreamsLoading() { + return ( +
    + {/* Header skeleton */} +
    +
    +
    +
    + + {/* Stream list skeleton */} +
    + {Array.from({ length: 5 }).map((_, i) => ( + + ))} +
    +
    + ) +} diff --git a/components/streams/dashboard-stats.tsx b/components/streams/dashboard-stats.tsx index 7d01be0..6b0413e 100644 --- a/components/streams/dashboard-stats.tsx +++ b/components/streams/dashboard-stats.tsx @@ -99,6 +99,7 @@ export function DashboardStats({ sent, received }: DashboardStatsProps) { amount={topWithdrawable.amount} token={topWithdrawable.token} maxFractionDigits={2} + truncate /> ) : ( diff --git a/components/ui/token-amount.tsx b/components/ui/token-amount.tsx index ae14a2c..ea60b98 100644 --- a/components/ui/token-amount.tsx +++ b/components/ui/token-amount.tsx @@ -11,6 +11,8 @@ interface TokenAmountProps { showSymbol?: boolean /** Display amount in compact notation (e.g., "1.2K"). @default false */ compact?: boolean + /** Truncate the display with ellipsis. @default false */ + truncate?: boolean } /** Formats a raw bigint token amount with correct decimals + symbol. */ @@ -22,13 +24,19 @@ export function TokenAmount({ maxFractionDigits = 4, showSymbol = true, compact = false, + truncate = false, }: TokenAmountProps) { const formattedAmount = compact ? formatCompactAmount(amount, token.decimals) : formatTokenAmount(amount, token.decimals, maxFractionDigits) + const fullValue = `${formattedAmount}${showSymbol ? ` ${token.symbol}` : ''}` + return ( - + {formattedAmount} {showSymbol && ( diff --git a/components/webhooks/webhook-settings.tsx b/components/webhooks/webhook-settings.tsx index 11ec5b1..0a6717f 100644 --- a/components/webhooks/webhook-settings.tsx +++ b/components/webhooks/webhook-settings.tsx @@ -1,7 +1,7 @@ 'use client' import { useState } from 'react' -import { Plus, Trash2, ToggleLeft, ToggleRight, Send, CheckCircle2, XCircle } from 'lucide-react' +import { Plus, Trash2, ToggleLeft, ToggleRight, Send, CheckCircle2, XCircle, Webhook } from 'lucide-react' import { toast } from 'sonner' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' @@ -74,7 +74,7 @@ export function WebhookSettings() { return (
    {/* Add webhook */} -
    +

    Register a webhook

    @@ -124,11 +124,28 @@ export function WebhookSettings() {
    {/* Registered webhooks */} - {webhooks.length > 0 && ( -
    -

    Registered webhooks

    - {webhooks.map((hook) => ( -
    +
    +

    Registered webhooks

    + {webhooks.length === 0 ? ( +
    + + + +

    No webhooks registered yet

    +

    + Register a webhook above to start receiving real-time event notifications for your streams. +

    + +
    + ) : ( +
    + {webhooks.map((hook) => ( +

    {hook.url}

    @@ -173,10 +190,11 @@ export function WebhookSettings() {
    -
    - ))} -
    - )} +
    + ))} +
    + )} +
    {/* Delivery history */} {history.length > 0 && (