diff --git a/webapp/index.html b/webapp/index.html index b7c2b76..525c0d7 100644 --- a/webapp/index.html +++ b/webapp/index.html @@ -3,6 +3,7 @@ + Subscriptions diff --git a/webapp/public/fonts/InterVariable.woff2 b/webapp/public/fonts/InterVariable.woff2 new file mode 100644 index 0000000..5a8d3e7 Binary files /dev/null and b/webapp/public/fonts/InterVariable.woff2 differ diff --git a/webapp/src/components/account/account-ui.tsx b/webapp/src/components/account/account-ui.tsx index 20b39fc..d48065d 100644 --- a/webapp/src/components/account/account-ui.tsx +++ b/webapp/src/components/account/account-ui.tsx @@ -15,7 +15,7 @@ import { useGetBalanceQuery, useGetTokenAccountsQuery, useAirdropSol, useAirdrop import { useDelegations, useIncomingDelegations } from '@/hooks/use-delegations'; import { useUsdcMint, useUsdcMintRaw } from '@/hooks/use-token-config'; import { useSubscriptionAuthorityStatus } from '@/hooks/use-subscription-authority-status'; -import { USDC_MULTIPLIER, recurringAvailable } from '@/lib/utils'; +import { USDC_MULTIPLIER, cn, recurringAvailable } from '@/lib/utils'; import { getBlockTimestamp } from '@/hooks/use-time-travel'; import { useClusterConfig } from '@/hooks/use-cluster-config'; import { useProgramAddress } from '@/hooks/use-token-config'; @@ -136,18 +136,18 @@ export function WalletBalanceCards({ address: addr }: { address: Address }) {
-

Wallet Overview

-
+

Wallet Overview

+
Program: - + {progAddr ? `${progAddr.slice(0, 8)}...${progAddr.slice(-4)}` : '...'}
{delegationId != null && ( -
+
Delegation ID: - {delegationId.toString()} + {delegationId.toString()}
)}
@@ -163,75 +163,75 @@ export function WalletBalanceCards({ address: addr }: { address: Address }) {
- + - Solana Balance -
- + Solana Balance +
+
-
+
{solQuery.data?.value ? ( - - {Number(lamportsToSol(solQuery.data.value)).toFixed(4)} - + {Number(lamportsToSol(solQuery.data.value)).toFixed(4)} ) : ( ... )}
-
SOL
+
SOL
- +
- USDC Balance + USDC Balance {usdcMint && ( -

+

{usdcMint.slice(0, 8)}...{usdcMint.slice(-4)}

)}
-
- +
+
{tokenQuery.isLoading ? ( -
+
...
) : (
-
+
{usdcBalance.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, })}
-
Wallet
+
Wallet
-
+
{(usdcBalance - reservedAmount + incomingAmount).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, })}
-
Spendable
+
+ Spendable +
{(reservedAmount > 0 || incomingAmount > 0) && ( -
incl. delegations
+
incl. delegations
)}
@@ -239,7 +239,7 @@ export function WalletBalanceCards({ address: addr }: { address: Address }) { {(reservedAmount > 0 || incomingAmount > 0) && (
{reservedAmount > 0 && ( - + {reservedAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, @@ -248,10 +248,10 @@ export function WalletBalanceCards({ address: addr }: { address: Address }) { )} {reservedAmount > 0 && incomingAmount > 0 && ( - | + | )} {incomingAmount > 0 && ( - + {incomingAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, @@ -290,23 +290,23 @@ export function SolFaucetCard() { return ( - SOL Airdrop - + SOL Airdrop + {isDevnet ? ( -

+

SOL airdrop is not available on devnet. Use{' '} faucet.solana.com {' '} @@ -377,23 +377,26 @@ export function UsdcFaucetCard() { return ( - USDC {isDevnet ? 'Faucet' : 'Airdrop'} - + USDC {isDevnet ? 'Faucet' : 'Airdrop'} + {showCircleLink ? ( -

+

USDC airdrop is not available on devnet. Use{' '} faucet.circle.com {' '} @@ -434,7 +437,7 @@ export function UsdcFaucetCard() { ))}

- {isDevnet &&

Mint authority wallet required

} + {isDevnet &&

Mint authority wallet required

}
-
- )} + + +
); diff --git a/webapp/src/components/app-layout.tsx b/webapp/src/components/app-layout.tsx index 1c3def1..e6ebe3b 100644 --- a/webapp/src/components/app-layout.tsx +++ b/webapp/src/components/app-layout.tsx @@ -1,24 +1,19 @@ +import React from 'react'; import { Toaster } from './ui/sonner'; import { AppHeader } from './app-header'; - -import { AppSidebar } from './app-sidebar'; -import React from 'react'; import { ClusterChecker } from './cluster/cluster-ui'; import { AccountChecker } from './account/account-ui'; export function AppLayout({ children }: { children: React.ReactNode }) { return ( -
- -
- -
- - - - {children} -
-
+
+ +
+ + + + {children} +
); diff --git a/webapp/src/components/app-providers.tsx b/webapp/src/components/app-providers.tsx index 4bb9ad3..d693a21 100644 --- a/webapp/src/components/app-providers.tsx +++ b/webapp/src/components/app-providers.tsx @@ -1,4 +1,3 @@ -import { ThemeProvider } from './theme-provider'; import { ReactQueryProvider } from './react-query-provider'; import { SolanaProvider } from './solana/solana-provider'; import { ErrorBoundary } from 'react-error-boundary'; @@ -11,8 +10,6 @@ function WalletErrorFallback({ error }: { error: unknown }) { } else { console.error('WalletErrorFallback caught non-Error:', error); } - // The cached wallet account can keep throwing across reloads, so clear - // ConnectorKit's persisted wallet state before reloading. const disconnectAndReload = () => { try { localStorage.removeItem('connector-kit:v1:account'); @@ -31,13 +28,13 @@ function WalletErrorFallback({ error }: { error: unknown }) {
@@ -49,11 +46,9 @@ function WalletErrorFallback({ error }: { error: unknown }) { export function AppProviders({ children }: Readonly<{ children: React.ReactNode }>) { return ( - - - {children} - - + + {children} + ); } diff --git a/webapp/src/components/app-sidebar.tsx b/webapp/src/components/app-sidebar.tsx deleted file mode 100644 index 478caeb..0000000 --- a/webapp/src/components/app-sidebar.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { Link, useLocation } from 'react-router'; -import { useCluster } from '@solana/connector/react'; -import { NAV_ITEMS, type NavItem } from './nav-items'; -import solanaLogo from '@/assets/solana-logo.svg'; -import { CURRENT_PROGRAM_VERSION } from '@subscriptions/client'; - -export function AppSidebar() { - const { pathname } = useLocation(); - const { cluster } = useCluster(); - const filteredItems = NAV_ITEMS.filter( - item => !item.clusterFilter || item.clusterFilter.includes(cluster?.id ?? ''), - ); - - function isActive(path: string) { - return path === '/' ? pathname === '/' : pathname === path; - } - - function isParentActive(item: NavItem) { - if (isActive(item.path)) return true; - return item.children?.some(c => isActive(c.path)) ?? false; - } - - return ( - - ); -} diff --git a/webapp/src/components/dashboard/summary-cards.tsx b/webapp/src/components/dashboard/summary-cards.tsx index ed27347..f287500 100644 --- a/webapp/src/components/dashboard/summary-cards.tsx +++ b/webapp/src/components/dashboard/summary-cards.tsx @@ -46,23 +46,23 @@ export function SummaryCards() { {/* Delegations Card */}
- -

Token Delegations

+ +

Token Delegations

- Outgoing - {outgoingCount} + Outgoing + {outgoingCount}
-
+
- Incoming - {incomingCount} + Incoming + {incomingCount}
@@ -71,23 +71,23 @@ export function SummaryCards() { {/* Subscriptions Card */}
- -

My Subscriptions

+ +

My Subscriptions

- Active - {subsCounts.active} + Active + {subsCounts.active}
-
+
- Amount - + Amount + $ {subsCounts.totalAmount.toLocaleString(undefined, { minimumFractionDigits: 2, @@ -103,23 +103,23 @@ export function SummaryCards() { {/* Plans Card */}
- -

My Plans

+ +

My Plans

- Active Plans - {plansCounts.active} + Active Plans + {plansCounts.active}
-
+
- Total Subscribers - {plansCounts.subs} + Total Subscribers + {plansCounts.subs}
diff --git a/webapp/src/components/delegation/active-delegations.tsx b/webapp/src/components/delegation/active-delegations.tsx index b8a33c9..d52adfd 100644 --- a/webapp/src/components/delegation/active-delegations.tsx +++ b/webapp/src/components/delegation/active-delegations.tsx @@ -119,7 +119,7 @@ function RevokeDelegationButton({ delegation }: RevokeDelegationButtonProps) { @@ -208,7 +208,7 @@ function TransferDelegationButton({ delegation, tokenMint, disabled, blockTime } @@ -295,26 +295,38 @@ function FixedDelegationTable({ Fixed {delegations.length}
-
+
- - - + + + {partyLabel} - + Amount - + Expiry - + Action @@ -328,42 +340,44 @@ function FixedDelegationTable({ return ( -
+
{formatAddress( isOutgoing ? d.data.header.delegatee : d.data.header.delegator, )}
- V{d.data.header.version} - | - + + V{d.data.header.version} + + | + ID: {d.data.header.initId.toString()} {isStale && ( <> - | - Stale + | + Stale )}
- + {formatAmount(d.data.amount)} USDC - + {rowExpired ? ( - Expired + Expired ) : d.data.expiryTs === 0n ? ( - No expiry + No expiry ) : (
{formatDelegationDateTime(d.data.expiryTs)}
{formatTimeRemaining(d.data.expiryTs, blockTime) && ( -
+
{formatTimeRemaining(d.data.expiryTs, blockTime)}
)} @@ -411,23 +425,38 @@ function RecurringDelegationTable({ Recurring {delegations.length}
-
+
- - - + + + {partyLabel} - + Amount - + Current Period - + Expiry - + Action @@ -448,51 +477,53 @@ function RecurringDelegationTable({ return ( -
+
{formatAddress( isOutgoing ? d.data.header.delegatee : d.data.header.delegator, )}
- V{d.data.header.version} - | - + + V{d.data.header.version} + + | + ID: {d.data.header.initId.toString()} {isStale && ( <> - | - Stale + | + Stale )}
- + {formatAmount(available)} USDC - + / {formatDuration(d.data.periodLengthS)} - + {formatPeriodRange( d.data.currentPeriodStartTs, d.data.periodLengthS, blockTime, )} - + {rowExpired ? ( - Expired + Expired ) : d.data.expiryTs === 0n ? ( - No expiry + No expiry ) : (
{formatDelegationDateTime(d.data.expiryTs)}
{formatTimeRemaining(d.data.expiryTs, blockTime) && ( -
+
{formatTimeRemaining(d.data.expiryTs, blockTime)}
)} @@ -563,19 +594,21 @@ function FilterCard({ active, onClick, label, count, subLabel, isActiveCard = tr ? isActiveCard ? 'border-blue-500/50 shadow-[0_0_20px_rgba(59,130,246,0.2)]' : 'border-gray-500/50 shadow-[0_0_20px_rgba(107,114,128,0.2)]' - : 'border-white/5 hover:border-white/10'; + : 'border-sand-200 hover:border-sand-300'; const textGlow = active && isActiveCard ? 'drop-shadow-[0_0_8px_rgba(59,130,246,0.5)]' : ''; return ( ); @@ -638,7 +671,7 @@ function InitPrompt({ const hasAta = !!userAtaAddress; const containerClass = compact - ? 'flex flex-col sm:flex-row sm:items-center justify-between gap-3 px-3 py-2.5 rounded-lg bg-amber-500/10 border border-amber-500/20' + ? 'flex flex-col sm:flex-row sm:items-center justify-between gap-3 px-3 py-2.5 rounded-lg bg-amber-100 border border-amber-300' : 'flex flex-col items-center justify-center py-8 text-center space-y-3'; const iconClass = compact ? 'h-5 w-5 text-amber-500 shrink-0' : 'h-10 w-10 text-amber-500/60'; const reapprovalText = @@ -722,9 +755,9 @@ function CloseSubscriptionAuthorityDialog({ return ( - + - Disable Delegations + Disable Delegations {hasActive ? 'You have active outgoing delegations. Closing the SubscriptionAuthority account will invalidate them.' @@ -733,30 +766,30 @@ function CloseSubscriptionAuthorityDialog({ {hasActive && (
-
+
{activeFixed > 0 && ( -

+

{activeFixed} outgoing fixed delegation{activeFixed > 1 ? 's' : ''}

)} {activeRecurring > 0 && ( -

+

{activeRecurring} outgoing recurring delegation{activeRecurring > 1 ? 's' : ''}

)} {activeSubscriptions > 0 && ( -

+

{activeSubscriptions} active subscription{activeSubscriptions > 1 ? 's' : ''}

)}
-

+

Delegatees will no longer be able to transfer from your outgoing delegations. Incoming delegations from others are not affected. If you re-initialize later, old delegations will remain stale.

- + setConfirmText(e.target.value)} @@ -927,7 +960,7 @@ export function ActiveDelegations({ size="sm" onClick={handleRevokeAllStale} disabled={revokeMultipleDelegations.isPending} - className="text-amber-400 border-amber-500/20 hover:bg-amber-500/10 hover:text-amber-300" + className="text-amber-600 border-amber-300 hover:bg-amber-100 hover:text-amber-700" > {revokeMultipleDelegations.isPending @@ -940,7 +973,7 @@ export function ActiveDelegations({ variant="outline" size="sm" onClick={() => setCloseDialogOpen(true)} - className="text-red-400 border-red-500/20 hover:bg-red-500/10 hover:text-red-300" + className="text-red-600 border-red-500/20 hover:bg-red-100 hover:text-red-700" > Disable diff --git a/webapp/src/components/delegation/create-delegation-dialog.tsx b/webapp/src/components/delegation/create-delegation-dialog.tsx index 3fdfa05..7e59b7c 100644 --- a/webapp/src/components/delegation/create-delegation-dialog.tsx +++ b/webapp/src/components/delegation/create-delegation-dialog.tsx @@ -30,12 +30,14 @@ function KindCard({ kind, selected, onClick }: KindCardProps) { onClick={onClick} className={cn( 'flex flex-col items-center p-4 rounded-lg border-2 transition-all duration-200', - 'hover:border-emerald-500/50', - selected ? 'border-emerald-500 bg-emerald-500/10' : 'border-border bg-card hover:bg-accent/50', + 'hover:border-foreground', + selected ? 'border-foreground bg-sand-200' : 'border-border bg-card hover:bg-accent/50', )} > - - {config.label} + + + {config.label} + {config.description} ); @@ -184,7 +186,7 @@ export function CreateDelegationDialog({ tokenMint, disabled }: CreateDelegation {step === 'kind' ? ( <> -

+

Choose Delegation Type

@@ -268,13 +270,13 @@ export function CreateDelegationDialog({ tokenMint, disabled }: CreateDelegation setNoExpiry(e.target.checked); if (e.target.checked) setExpiryDate(''); }} - className="h-4 w-4 rounded border-gray-600 bg-gray-800 text-emerald-500 focus:ring-emerald-500/30" + className="h-4 w-4 rounded border-sand-400 bg-card text-foreground focus:ring-foreground" />
{noExpiry ? ( -
- +
+ This delegation will not have an expiration time
diff --git a/webapp/src/components/delegation/delegation-management-panel.tsx b/webapp/src/components/delegation/delegation-management-panel.tsx index c13ae91..ccd73a4 100644 --- a/webapp/src/components/delegation/delegation-management-panel.tsx +++ b/webapp/src/components/delegation/delegation-management-panel.tsx @@ -81,11 +81,11 @@ export function DelegationManagementPanel() { return (
{subscriptionAuthorityInitId != null && ( -
-
+
+
Current Delegation ID - {subscriptionAuthorityInitId.toString()} -
+ {subscriptionAuthorityInitId.toString()} +
)} +
{isSuccess ? ( - + ) : ( - + )} {fmtDateTime(record.timestamp)} - + ${totalAmount.toFixed(2)} total from {record.subscribersCollected}/{record.subscribersTotal} subs {isSuccess && record.signatures[0] && ( @@ -43,11 +43,11 @@ export function HistoryEntry({ record }: { record: CollectionRecord }) { )} - {record.error && {record.error}} + {record.error && {record.error}}
); } @@ -132,12 +132,12 @@ function CollectPlanCard({ }, [rpcUrl, plan, planName, collectSubscriptionPayments, progAddr]); return ( -
+
- +
-

{planName}

+

{planName}

${amountUsd.toFixed(2)} / period - {subscriberCount} subscriber {subscriberCount !== 1 ? 's' : ''} @@ -162,7 +162,7 @@ function CollectPlanCard({

{expanded && history.length > 0 && ( -
+

Collection History

{history.slice(0, 10).map(record => ( @@ -187,7 +187,7 @@ export function CollectPaymentsPanel({ alwaysShow }: { alwaysShow?: boolean } = if (isLoading) { if (!alwaysShow) return null; return ( - +
Loading plans...
@@ -198,7 +198,7 @@ export function CollectPaymentsPanel({ alwaysShow }: { alwaysShow?: boolean } = if (plansWithSubs.length === 0) { if (!alwaysShow) return null; return ( - +

No plans with active subscribers

@@ -208,10 +208,10 @@ export function CollectPaymentsPanel({ alwaysShow }: { alwaysShow?: boolean } = } return ( - +
- + Payment Collection {plansWithSubs.length}
diff --git a/webapp/src/components/plan/create-plan-dialog.tsx b/webapp/src/components/plan/create-plan-dialog.tsx index c2c0897..d58a394 100644 --- a/webapp/src/components/plan/create-plan-dialog.tsx +++ b/webapp/src/components/plan/create-plan-dialog.tsx @@ -237,9 +237,7 @@ export function CreatePlanDialog({ open, onOpenChange }: CreatePlanDialogProps)
-

- Quick Templates -

+

Quick Templates

{PLAN_TEMPLATES.map(t => { const TIcon = PLAN_ICONS.find(i => i.name === t.icon)?.icon; @@ -248,7 +246,7 @@ export function CreatePlanDialog({ open, onOpenChange }: CreatePlanDialogProps) key={t.label} type="button" onClick={() => applyTemplate(t)} - className="flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-full border border-border hover:border-emerald-500 hover:text-emerald-400 transition-colors whitespace-nowrap shrink-0" + className="flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-full border border-border hover:border-foreground hover:text-foreground transition-colors whitespace-nowrap shrink-0" > {TIcon && } {t.label} @@ -261,7 +259,7 @@ export function CreatePlanDialog({ open, onOpenChange }: CreatePlanDialogProps)
-

Metadata

+

Metadata

@@ -325,7 +323,7 @@ export function CreatePlanDialog({ open, onOpenChange }: CreatePlanDialogProps)
-

+

Plan Parameters

@@ -390,13 +388,13 @@ export function CreatePlanDialog({ open, onOpenChange }: CreatePlanDialogProps) setNoEndDate(e.target.checked); if (e.target.checked) setEndDate(''); }} - className="h-4 w-4 rounded border-gray-600 bg-gray-800 text-emerald-500 focus:ring-emerald-500/30" + className="h-4 w-4 rounded border-sand-400 bg-card text-foreground focus:ring-foreground" />
{noEndDate ? ( -
- This plan will not have an end date +
+ This plan will not have an end date
) : ( <> diff --git a/webapp/src/components/plan/enhanced-collect-payments.tsx b/webapp/src/components/plan/enhanced-collect-payments.tsx index c05f941..e0439ac 100644 --- a/webapp/src/components/plan/enhanced-collect-payments.tsx +++ b/webapp/src/components/plan/enhanced-collect-payments.tsx @@ -79,22 +79,22 @@ function CollectSummaryCards({ {cards.map(card => (
- -

{card.title}

+ +

{card.title}

- {card.row1Label} - {card.row1Value} + {card.row1Label} + {card.row1Value}
-
+
- {card.row2Label} - {card.row2Value} + {card.row2Label} + {card.row2Value}
@@ -302,15 +302,15 @@ function EnhancedPlanCard({ planData, blockTs }: { planData: PlanSubscriberData; const periodHoursSec = Number(plan.data.terms.periodHours) * 3600; return ( -
+
@@ -518,7 +515,7 @@ export function EnhancedCollectPayments() { if (isLoading) { return ( - +
Loading plans...
@@ -529,7 +526,7 @@ export function EnhancedCollectPayments() { if (!allPlans || allPlans.length === 0 || plansWithSubs.length === 0) { return (
- +

No plans with active subscribers

diff --git a/webapp/src/components/plan/my-plans-panel.tsx b/webapp/src/components/plan/my-plans-panel.tsx index b75e640..7d35aa3 100644 --- a/webapp/src/components/plan/my-plans-panel.tsx +++ b/webapp/src/components/plan/my-plans-panel.tsx @@ -35,7 +35,7 @@ export function MyPlansPanel() { if (isLoading) { return ( - +
Loading plans...
@@ -46,11 +46,11 @@ export function MyPlansPanel() { const hasPlan = plans && plans.length > 0; return ( - +
- + My Plans
diff --git a/webapp/src/components/plan/plan-card.tsx b/webapp/src/components/plan/plan-card.tsx index 9450087..5811c45 100644 --- a/webapp/src/components/plan/plan-card.tsx +++ b/webapp/src/components/plan/plan-card.tsx @@ -149,7 +149,7 @@ function EditPlanDialog({ return ( - + Edit Plan: {meta.n || 'Unnamed'} @@ -160,7 +160,7 @@ function EditPlanDialog({
-

+

Metadata (editable)

@@ -226,7 +226,7 @@ function EditPlanDialog({
-

+

Plan Parameters

@@ -331,7 +331,7 @@ function EditPlanDialog({
{!isSunset && ( -
+
setSunsetMode(e.target.checked)} className="accent-amber-500" /> -
)} {sunsetMode && !endDate && (
-

Sunset requires an end date.

+

Sunset requires an end date.

)} {isSunset && ( -
-

+

+

This plan is in Sunset status. No further edits are allowed.

@@ -403,9 +403,9 @@ function DeletePlanDialog({ return ( - + - Delete Plan: {meta.n || 'Unnamed'} + Delete Plan: {meta.n || 'Unnamed'} {canDelete ? 'This plan has expired. Deleting will close the account and return rent to your wallet.' @@ -413,7 +413,7 @@ function DeletePlanDialog({ {!canDelete && ( -
+
{endTs === 0 ? (

This plan has no expiry. Set an end date via Edit first, then wait for it to expire.

) : ( @@ -482,9 +482,9 @@ function SubscribeDialog({ return ( - + - Subscribe to: {meta.n || 'Unnamed'} + Subscribe to: {meta.n || 'Unnamed'} ${amount} / {formatPeriod(plan.data.terms.periodHours)} from merchant {ellipsify(plan.owner, 4)} @@ -496,7 +496,7 @@ function SubscribeDialog({
) : !isInitialized ? (
-
+
Your SubscriptionAuthority account must be initialized for this token before subscribing.
@@ -563,7 +563,7 @@ function PlanExpandedDetails({ plan, isExpanded }: { plan: PlanItem; isExpanded: isExpanded ? 'translate-y-0 opacity-100' : 'translate-y-2 opacity-0', )} > -

+

Destinations

{activeDestinations.length > 0 ? ( @@ -573,12 +573,12 @@ function PlanExpandedDetails({ plan, isExpanded }: { plan: PlanItem; isExpanded: key={d} address={d} label={ellipsify(d, 6)} - className="bg-emerald-500/8 hover:bg-emerald-500/15 border border-emerald-500/20 hover:border-emerald-500/40 px-3 py-1.5 rounded-lg font-mono text-xs text-emerald-300 hover:text-emerald-200 shadow-[0_0_8px_rgba(16,185,129,0)] hover:shadow-[0_0_8px_rgba(16,185,129,0.15)] transition-all duration-300 no-underline" + className="bg-card hover:bg-sand-100 border border-sand-300 hover:border-sand-400 px-3 py-1.5 rounded-lg font-mono text-xs text-foreground transition-all duration-300 no-underline" /> ))}
) : ( -

Any destination (unrestricted)

+

Any destination (unrestricted)

)}
@@ -588,9 +588,7 @@ function PlanExpandedDetails({ plan, isExpanded }: { plan: PlanItem; isExpanded: isExpanded ? 'translate-y-0 opacity-100' : 'translate-y-2 opacity-0', )} > -

- Pullers -

+

Pullers

{activePullers.length > 0 ? (
{activePullers.map(p => ( @@ -598,12 +596,12 @@ function PlanExpandedDetails({ plan, isExpanded }: { plan: PlanItem; isExpanded: key={p} address={p} label={ellipsify(p, 6)} - className="bg-emerald-500/8 hover:bg-emerald-500/15 border border-emerald-500/20 hover:border-emerald-500/40 px-3 py-1.5 rounded-lg font-mono text-xs text-emerald-300 hover:text-emerald-200 shadow-[0_0_8px_rgba(16,185,129,0)] hover:shadow-[0_0_8px_rgba(16,185,129,0.15)] transition-all duration-300 no-underline" + className="bg-card hover:bg-sand-100 border border-sand-300 hover:border-sand-400 px-3 py-1.5 rounded-lg font-mono text-xs text-foreground transition-all duration-300 no-underline" /> ))}
) : ( -

Owner only

+

Owner only

)}
@@ -613,25 +611,27 @@ function PlanExpandedDetails({ plan, isExpanded }: { plan: PlanItem; isExpanded: isExpanded ? 'translate-y-0 opacity-100' : 'translate-y-2 opacity-0', )} > -

+

On-chain Details

-
-

Plan ID

-

{Number(plan.data.planId)}

+
+

Plan ID

+

{Number(plan.data.planId)}

-
-

Token Mint

+
+

Token Mint

-
-

Period

-

{formatPeriodLabel(plan.data.terms.periodHours)}

+
+

Period

+

+ {formatPeriodLabel(plan.data.terms.periodHours)} +

@@ -715,25 +715,22 @@ export function PlanCard({ : undefined; const borderClass = planExpired - ? 'border-red-500/40 hover:border-red-500/60 shadow-red-500/10' + ? 'border border-red-300' : isSunset - ? sunsetIntensity > 0.6 - ? 'border-orange-500/40 hover:border-orange-500/60 shadow-orange-500/10' - : 'border-amber-500/30 hover:border-amber-500/50 shadow-amber-500/5' - : 'border-emerald-500/25 hover:border-emerald-500/45 shadow-emerald-500/5'; + ? 'border border-amber-300' + : 'border-0 border-all-dashed-medium'; return ( <> {overlayStyle && (
)} -
-
- +
+
-

+

{meta.n || 'Unnamed Plan'}

-

+

{meta.d || 'No description'}

@@ -763,7 +760,7 @@ export function PlanCard({ {variant === 'owner' && onToggleExpand && ( @@ -773,26 +770,26 @@ export function PlanCard({
- + ${amount} - /{period} + /{period}
{hasExpiry ? ( planExpired ? ( -
- +
+ Expired {fmtDate(Number(plan.data.endTs))}
) : ( -
- +
+ Expires {fmtDate(Number(plan.data.endTs))}
) ) : ( -
+
No expiry
@@ -801,18 +798,18 @@ export function PlanCard({
{variant === 'owner' && ( -
+
- {subscriberCount ?? 0}{' '} + {subscriberCount ?? 0}{' '} subscriber{subscriberCount !== 1 ? 's' : ''} - | + | - {activeDestinations} dest. + {activeDestinations} dest. - | + | - {activePullers} puller + {activePullers} puller {activePullers !== 1 ? 's' : ''}
@@ -821,8 +818,8 @@ export function PlanCard({ {variant === 'owner' && } -
- +
+ {plan.address} {variant === 'marketplace' && meta.w && ( @@ -830,7 +827,7 @@ export function PlanCard({ href={meta.w} target="_blank" rel="noopener noreferrer" - className="flex items-center gap-1 text-sm text-emerald-400 hover:text-emerald-300 transition-colors shrink-0" + className="flex items-center gap-1 text-sm text-foreground hover:text-sand-1100 transition-colors shrink-0" > Website @@ -839,7 +836,7 @@ export function PlanCard({
{variant === 'marketplace' && ( -
+
{isCancelledSub ? ( Cancelled{' '} @@ -872,7 +869,7 @@ export function PlanCard({ )} {variant === 'owner' && ( -
+
{!planExpired && ( {expanded && ( -
+
- + { @@ -177,7 +177,7 @@ function TransferAuthoritySection() { />
- {newAuthority && !isValidInput &&

Invalid base58 address

} + {newAuthority && !isValidInput &&

Invalid base58 address

} {isValidInput && (
@@ -196,7 +196,7 @@ function TransferAuthoritySection() { onClick={handleGenerateBase58} disabled={generating} variant="outline" - className={`${isAuthority ? '' : 'flex-1'} border-purple-500/30 text-purple-400 hover:bg-purple-500/10`} + className={`${isAuthority ? '' : 'flex-1'} border-sand-400 text-foreground hover:bg-sand-100`} > {generating ? ( <> @@ -212,22 +212,22 @@ function TransferAuthoritySection() { {base58Output && !base58Output.startsWith('Error:') && (
- Raw Transaction (base58) + Raw Transaction (base58)
-
- +
+ {base58Output}
-

+

Import this transaction into your multisig app (Squads, Realms, etc.) to execute.

)} {base58Output && base58Output.startsWith('Error:') && ( -

{base58Output}

+

{base58Output}

)}
)} @@ -266,13 +266,13 @@ export function ProgramDeployCard() { }; return ( - + - {isUpgrade ? 'Upgrade Program' : 'Deploy Program'} + {isUpgrade ? 'Upgrade Program' : 'Deploy Program'} {authorityMismatch && ( -
+
Upgrade authority is{' '} {status?.upgradeAuthority?.slice(0, 8)}... which differs from your wallet. Use the Transfer Authority section below to change it, or generate a base58 @@ -302,13 +302,13 @@ export function ProgramDeployCard() { {progress.phase === 'error' && (
-

{progress.message}

+

{progress.message}

{lastFailedChunk !== null && lastFailedChunk > 0 ? ( @@ -319,7 +319,7 @@ export function ProgramDeployCard() { handleDeploy(); }} variant="outline" - className="flex-1 border-red-500/30 text-red-400 hover:bg-red-500/10" + className="flex-1 border-red-300 text-red-600 hover:bg-red-100" > Retry @@ -328,7 +328,7 @@ export function ProgramDeployCard() { onClick={() => closeBuffer.mutate()} disabled={closeBuffer.isPending} variant="outline" - className="border-gray-500/30 text-gray-400 hover:bg-gray-500/10" + className="border-gray-500/30 text-sand-1100 hover:bg-gray-500/10" title="Close buffer and reclaim SOL" > @@ -341,7 +341,7 @@ export function ProgramDeployCard() { diff --git a/webapp/src/components/program/program-status-card.tsx b/webapp/src/components/program/program-status-card.tsx index 9043ff6..108ca82 100644 --- a/webapp/src/components/program/program-status-card.tsx +++ b/webapp/src/components/program/program-status-card.tsx @@ -38,31 +38,31 @@ export function ProgramStatusCard() { if (isLoading) return ( - + -
+
); if (error) return ( - - Failed to load program status + + Failed to load program status ); return ( - + - Program Status + Program Status {status && } - + {progAddr ? truncateAddress(progAddr, 6) : '...'} {progAddr && } @@ -72,7 +72,7 @@ export function ProgramStatusCard() { <> {status.upgradeAuthority && ( - + {truncateAddress(status.upgradeAuthority, 6)} @@ -80,19 +80,19 @@ export function ProgramStatusCard() { )} {status.lastDeploySlot && ( - {status.lastDeploySlot.toLocaleString()} + {status.lastDeploySlot.toLocaleString()} )} {status.lastDeployTime && ( - + {new Date(status.lastDeployTime * 1000).toLocaleString()} )} {status.dataSize && ( - {(status.dataSize / 1024).toFixed(1)} KB + {(status.dataSize / 1024).toFixed(1)} KB )} @@ -101,10 +101,10 @@ export function ProgramStatusCard() { {binaryInfo && ( <> - {(binaryInfo.size / 1024).toFixed(1)} KB + {(binaryInfo.size / 1024).toFixed(1)} KB - {binaryInfo.hash.slice(0, 16)}... + {binaryInfo.hash.slice(0, 16)}... @@ -117,7 +117,7 @@ export function ProgramStatusCard() { function Row({ label, children }: { label: string; children: React.ReactNode }) { return (
- {label} + {label}
{children}
); diff --git a/webapp/src/components/solana/solana-provider.tsx b/webapp/src/components/solana/solana-provider.tsx index 68719ce..107a8cc 100644 --- a/webapp/src/components/solana/solana-provider.tsx +++ b/webapp/src/components/solana/solana-provider.tsx @@ -84,6 +84,7 @@ export function WalletButton() { disabled={pending} iconLeft={} iconRight={} + size="sm" variant="secondary" > {ellipsify(account, 4)} @@ -115,6 +116,7 @@ export function WalletButton() { iconLeft={} iconRight={} loading={pending} + size="sm" variant="secondary" > Connect Wallet diff --git a/webapp/src/components/subscription/my-subscriptions-panel.tsx b/webapp/src/components/subscription/my-subscriptions-panel.tsx index 23804cb..4f4dc5f 100644 --- a/webapp/src/components/subscription/my-subscriptions-panel.tsx +++ b/webapp/src/components/subscription/my-subscriptions-panel.tsx @@ -32,9 +32,9 @@ function CancelSubscriptionDialog({ return ( - + - Unsubscribe + Unsubscribe Are you sure you want to unsubscribe? Your subscription remains active until end of current billing period. @@ -56,7 +56,7 @@ function CancelSubscriptionDialog({ ) } disabled={cancelSubscription.isPending} - className="border-red-500/30 text-red-400 hover:bg-red-500/10 hover:text-red-300" + className="border-red-300 text-red-600 hover:bg-red-100 hover:text-red-700" > {cancelSubscription.isPending ? 'Cancelling...' : 'Yes, Unsubscribe'} @@ -91,9 +91,9 @@ function RevokeSubscriptionDialog({ return ( - + - Delete Subscription + Delete Subscription {canRevoke ? 'This subscription has expired. Deleting will close the account and return rent to your wallet.' @@ -101,7 +101,7 @@ function RevokeSubscriptionDialog({ {!canRevoke && ( -
+
Expires on {fmtDateTime(revokedTs)}. You can delete after that.
)} @@ -146,9 +146,9 @@ function CancelAndRevokeDialog({ return ( - + - Unsubscribe & Delete + Unsubscribe & Delete {isGhostPlan ? 'The plan terms have changed since you subscribed (ghost plan). Payments cannot be collected. This will cancel and immediately delete the subscription, returning rent to your wallet.' @@ -236,10 +236,10 @@ function SubscriptionCard({ className={cn( 'rounded-xl relative overflow-hidden transition-all duration-300', planDeleted - ? 'border-red-500/15 bg-gradient-to-br from-red-950/30 via-gray-900/20 to-gray-950/60 opacity-80' + ? 'border-red-200 bg-gradient-to-br from-red-100 via-sand-100 to-sand-200 opacity-80' : isCancelled - ? 'border-gray-500/20 bg-gradient-to-br from-gray-950/60 via-gray-900/20 to-gray-950/60 opacity-70' - : 'border-teal-500/25 bg-gradient-to-br from-slate-900/80 via-teal-900/15 to-slate-900/80 hover:border-teal-500/45', + ? 'border-sand-300 bg-gradient-to-br from-sand-200 via-sand-100 to-sand-200 opacity-70' + : 'border-0 border-all-dashed-medium bg-card hover:bg-sand-100', )} > {!isCancelled && !planDeleted && ( @@ -247,7 +247,7 @@ function SubscriptionCard({ )}
-

{planName}

+

{planName}

{planDeleted ? ( Plan Deleted @@ -268,28 +268,28 @@ function SubscriptionCard({
- ${amount} - /{period.toLowerCase()} + ${amount} + /{period.toLowerCase()}
-
+
{ellipsify(item.address, 4)} - | - V{item.subscription.header.version} - | - ID: {subInitId.toString()} + | + V{item.subscription.header.version} + | + ID: {subInitId.toString()} {isStale && ( <> - | - Stale + | + Stale )} - | + | Pulled: ${pulled.toFixed(2)} {isCancelled && !planDeleted && ( <> - | - + | + Expires: {fmtDate(revokedTs)} @@ -297,13 +297,13 @@ function SubscriptionCard({ )}
-
+
{(planDeleted || isGhostPlan) && isActive ? ( @@ -334,8 +334,8 @@ function SubscriptionCard({ className={cn( 'w-full', isExpired - ? 'border-red-500/30 text-red-400 hover:bg-red-500/10 hover:text-red-300' - : 'border-gray-600/30 text-gray-500 cursor-not-allowed', + ? 'border-red-300 text-red-600 hover:bg-red-100 hover:text-red-700' + : 'border-gray-600/30 text-sand-1000 cursor-not-allowed', )} > @@ -365,7 +365,7 @@ export function MySubscriptionsPanel() { if (isLoading) { return ( - +
Loading subscriptions...
@@ -376,11 +376,11 @@ export function MySubscriptionsPanel() { const hasSubs = subscriptions && subscriptions.length > 0; return ( - +
- + My Subscriptions
{hasSubs && {subscriptions.length}} diff --git a/webapp/src/components/theme-provider.tsx b/webapp/src/components/theme-provider.tsx deleted file mode 100644 index fd3ef3d..0000000 --- a/webapp/src/components/theme-provider.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import * as React from 'react'; -import { ThemeProvider as NextThemesProvider } from 'next-themes'; - -export function ThemeProvider({ children, ...props }: React.ComponentProps) { - return {children}; -} diff --git a/webapp/src/components/time-travel/time-travel-button.tsx b/webapp/src/components/time-travel/time-travel-button.tsx index c8f19ba..924dcec 100644 --- a/webapp/src/components/time-travel/time-travel-button.tsx +++ b/webapp/src/components/time-travel/time-travel-button.tsx @@ -145,31 +145,31 @@ function TimeTravelButtonInner() { }`} title="Time Travel (Dev)" > - + {currentTime !== null && ( {fmtDate(currentTime)} )} - + - + Time Travel
-
+
{currentTime !== null ? fmtDateTime(currentTime) : 'Fetching...'}
-