From eb8631160423f4e4548c1949590d34b07f95ccd8 Mon Sep 17 00:00:00 2001 From: t0ng7u Date: Tue, 16 Jun 2026 00:44:33 +0800 Subject: [PATCH] style(ui): align wallet and profile interactions --- .../data-table/core/data-table-header.tsx | 6 +- .../data-table/layout/data-table-page.tsx | 3 +- .../data-table/layout/mobile-card-list.tsx | 7 +- .../static/static-data-table-classnames.ts | 3 +- web/default/src/components/provider-badge.tsx | 10 +- web/default/src/components/ui/table.tsx | 2 +- web/default/src/components/ui/titled-card.tsx | 7 +- .../channels/components/channels-columns.tsx | 15 +- .../overview/overview-dashboard.tsx | 6 +- .../components/data-table-row-actions.tsx | 138 +++++++++--------- .../components/dynamic-pricing-breakdown.tsx | 8 +- .../pricing/components/model-card.tsx | 4 +- .../components/checkin-calendar-card.tsx | 17 +-- .../components/language-preferences-card.tsx | 1 + .../profile/components/passkey-card.tsx | 6 +- .../profile/components/profile-header.tsx | 31 ++-- .../components/profile-security-card.tsx | 9 +- .../components/profile-settings-card.tsx | 3 +- .../components/sidebar-modules-card.tsx | 4 +- .../components/tabs/account-bindings-tab.tsx | 2 +- .../components/tabs/notification-tab.tsx | 67 +++++---- .../profile/components/two-fa-card.tsx | 4 +- .../components/data-table-row-actions.tsx | 112 +++++++------- .../components/data-table-row-actions.tsx | 72 ++++----- .../content/uptime-kuma-section.tsx | 3 +- .../general/channel-affinity/index.tsx | 4 +- .../amount-discount-visual-editor.tsx | 4 +- .../payment-methods-visual-editor.tsx | 4 +- .../models/conflict-confirm-dialog.tsx | 16 +- .../models/tool-price-settings.tsx | 44 +++--- .../components/dialogs/details-dialog.tsx | 4 +- .../components/affiliate-rewards-card.tsx | 4 +- .../components/creem-products-section.tsx | 5 +- .../dialogs/billing-history-dialog.tsx | 2 +- .../dialogs/creem-confirm-dialog.tsx | 2 +- .../wallet/components/recharge-form-card.tsx | 5 +- .../components/subscription-plans-card.tsx | 9 +- web/default/src/styles/index.css | 6 +- web/default/src/tanstack-table.d.ts | 6 +- 39 files changed, 341 insertions(+), 314 deletions(-) diff --git a/web/default/src/components/data-table/core/data-table-header.tsx b/web/default/src/components/data-table/core/data-table-header.tsx index fbaca0bf3..f78479035 100644 --- a/web/default/src/components/data-table/core/data-table-header.tsx +++ b/web/default/src/components/data-table/core/data-table-header.tsx @@ -16,7 +16,11 @@ along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ -import { flexRender, type Header, type Table as TanstackTable } from '@tanstack/react-table' +import { + flexRender, + type Header, + type Table as TanstackTable, +} from '@tanstack/react-table' import { TableHead, TableHeader, TableRow } from '@/components/ui/table' import { DataTableColumnHeader } from './column-header' import type { DataTableColumnClassName } from './types' diff --git a/web/default/src/components/data-table/layout/data-table-page.tsx b/web/default/src/components/data-table/layout/data-table-page.tsx index cff241354..4b6a20bbc 100644 --- a/web/default/src/components/data-table/layout/data-table-page.tsx +++ b/web/default/src/components/data-table/layout/data-table-page.tsx @@ -344,7 +344,8 @@ function renderDesktop( splitHeader={fixedHeight} tableContainerClassName={fixedHeight ? 'h-full min-h-0' : undefined} tableHeaderClassName={cn( - fixedHeight && '[background-color:color-mix(in_oklch,var(--muted)_30%,var(--background))]', + fixedHeight && + '[background-color:color-mix(in_oklch,var(--muted)_30%,var(--background))]', props.tableHeaderClassName )} getColumnClassName={props.getColumnClassName} diff --git a/web/default/src/components/data-table/layout/mobile-card-list.tsx b/web/default/src/components/data-table/layout/mobile-card-list.tsx index 8eb319052..fe5fc9c1b 100644 --- a/web/default/src/components/data-table/layout/mobile-card-list.tsx +++ b/web/default/src/components/data-table/layout/mobile-card-list.tsx @@ -25,7 +25,6 @@ import { } from '@tanstack/react-table' import { Database } from 'lucide-react' import { useTranslation } from 'react-i18next' -import { StatusBadgeTypeContext } from '@/components/status-badge' import { cn } from '@/lib/utils' import { Empty, @@ -35,6 +34,7 @@ import { EmptyTitle, } from '@/components/ui/empty' import { Skeleton } from '@/components/ui/skeleton' +import { StatusBadgeTypeContext } from '@/components/status-badge' interface MobileCardListProps { table: Table @@ -211,7 +211,10 @@ function FallbackRow({ row }: { row: Row }) { if (!label) { return ( -
+
{renderCellContent(cell)} diff --git a/web/default/src/components/data-table/static/static-data-table-classnames.ts b/web/default/src/components/data-table/static/static-data-table-classnames.ts index ca057af87..382e149a7 100644 --- a/web/default/src/components/data-table/static/static-data-table-classnames.ts +++ b/web/default/src/components/data-table/static/static-data-table-classnames.ts @@ -22,7 +22,8 @@ export const staticDataTableClassNames = { embeddedContainer: 'rounded-none border-0', compactTable: 'text-sm', compactHeaderRow: 'hover:bg-transparent', - mutedHeaderRow: '[background-color:color-mix(in_oklch,var(--muted)_30%,var(--background))] hover:[background-color:color-mix(in_oklch,var(--muted)_30%,var(--background))]', + mutedHeaderRow: + '[background-color:color-mix(in_oklch,var(--muted)_30%,var(--background))] hover:[background-color:color-mix(in_oklch,var(--muted)_30%,var(--background))]', compactHeaderCell: 'text-muted-foreground py-2 text-[10px] font-medium tracking-wider uppercase', compactHeaderCellRight: diff --git a/web/default/src/components/provider-badge.tsx b/web/default/src/components/provider-badge.tsx index 61c219c11..f6885fe75 100644 --- a/web/default/src/components/provider-badge.tsx +++ b/web/default/src/components/provider-badge.tsx @@ -38,20 +38,14 @@ export function ProviderBadge({ return (
{icon && {icon}}
diff --git a/web/default/src/components/ui/table.tsx b/web/default/src/components/ui/table.tsx index eaa2d4226..8ed071dad 100644 --- a/web/default/src/components/ui/table.tsx +++ b/web/default/src/components/ui/table.tsx @@ -77,7 +77,7 @@ function TableRow({ className, ...props }: React.ComponentProps<'tr'>) { + diff --git a/web/default/src/features/channels/components/channels-columns.tsx b/web/default/src/features/channels/components/channels-columns.tsx index f49ada136..41213f238 100644 --- a/web/default/src/features/channels/components/channels-columns.tsx +++ b/web/default/src/features/channels/components/channels-columns.tsx @@ -622,7 +622,7 @@ export function useChannelsColumns(): ColumnDef[] { : undefined return ( -
+
{isMultiKey && ( @@ -641,7 +641,7 @@ export function useChannelsColumns(): ColumnDef[] { +
} > [] { label={typeName} copyable={false} showDot={false} - className='min-w-0 max-w-full overflow-hidden' + className='max-w-full min-w-0 overflow-hidden' /> {typeName} @@ -895,7 +895,14 @@ export function useChannelsColumns(): ColumnDef[] { if (!tag) return - - return + return ( + + ) }, size: 120, enableSorting: false, diff --git a/web/default/src/features/dashboard/components/overview/overview-dashboard.tsx b/web/default/src/features/dashboard/components/overview/overview-dashboard.tsx index 297bdbece..a280e89ea 100644 --- a/web/default/src/features/dashboard/components/overview/overview-dashboard.tsx +++ b/web/default/src/features/dashboard/components/overview/overview-dashboard.tsx @@ -190,7 +190,7 @@ function SetupGuideBackdrop(props: { compact?: boolean }) { /> ) } diff --git a/web/default/src/features/pricing/components/dynamic-pricing-breakdown.tsx b/web/default/src/features/pricing/components/dynamic-pricing-breakdown.tsx index 2ef4867de..7f479e980 100644 --- a/web/default/src/features/pricing/components/dynamic-pricing-breakdown.tsx +++ b/web/default/src/features/pricing/components/dynamic-pricing-breakdown.tsx @@ -322,13 +322,11 @@ export function DynamicPricingBreakdown({ className: 'text-muted-foreground py-2 font-medium', cellClassName: 'py-2.5 align-top', cell: (tier) => { - const condSummary = formatConditionSummary( - tier.conditions, - t - ) + const condSummary = formatConditionSummary(tier.conditions, t) const isMatched = normalizedMatchedTierLabel !== '' && - normalizeTierLabel(tier.label) === normalizedMatchedTierLabel + normalizeTierLabel(tier.label) === + normalizedMatchedTierLabel return ( <>
diff --git a/web/default/src/features/pricing/components/model-card.tsx b/web/default/src/features/pricing/components/model-card.tsx index 44f2debaa..e94122793 100644 --- a/web/default/src/features/pricing/components/model-card.tsx +++ b/web/default/src/features/pricing/components/model-card.tsx @@ -57,9 +57,7 @@ export const ModelCard = memo(function ModelCard(props: ModelCardProps) { const groups = props.model.enable_groups || [] const endpoints = props.model.supported_endpoint_types || [] const modelIconKey = props.model.icon || props.model.vendor_icon - const modelIcon = modelIconKey - ? getLobeIcon(modelIconKey, 28) - : null + const modelIcon = modelIconKey ? getLobeIcon(modelIconKey, 28) : null const initial = props.model.model_name?.charAt(0).toUpperCase() || '?' const isDynamicPricing = props.model.billing_mode === 'tiered_expr' && diff --git a/web/default/src/features/profile/components/checkin-calendar-card.tsx b/web/default/src/features/profile/components/checkin-calendar-card.tsx index 49cb8c916..2730e7c16 100644 --- a/web/default/src/features/profile/components/checkin-calendar-card.tsx +++ b/web/default/src/features/profile/components/checkin-calendar-card.tsx @@ -32,6 +32,7 @@ import { formatQuotaWithCurrency } from '@/lib/currency' import dayjs from '@/lib/dayjs' import { cn } from '@/lib/utils' import { Button } from '@/components/ui/button' +import { Card } from '@/components/ui/card' import { Skeleton } from '@/components/ui/skeleton' import { Tooltip, @@ -221,7 +222,7 @@ export function CheckinCalendarCard({ if (isLoading) { return ( -
+
@@ -234,7 +235,7 @@ export function CheckinCalendarCard({
-
+
) } @@ -270,14 +271,13 @@ export function CheckinCalendarCard({
-
+ {/* Header */}
- +
) : null} -
+
) } diff --git a/web/default/src/features/profile/components/language-preferences-card.tsx b/web/default/src/features/profile/components/language-preferences-card.tsx index 969ee84e7..de810baa8 100644 --- a/web/default/src/features/profile/components/language-preferences-card.tsx +++ b/web/default/src/features/profile/components/language-preferences-card.tsx @@ -105,6 +105,7 @@ export function LanguagePreferencesCard(props: LanguagePreferencesCardProps) { title={t('Language Preferences')} description={t('Set the language used across the interface')} icon={} + disableHoverEffect >
diff --git a/web/default/src/features/profile/components/passkey-card.tsx b/web/default/src/features/profile/components/passkey-card.tsx index ce5abe467..a68da07f9 100644 --- a/web/default/src/features/profile/components/passkey-card.tsx +++ b/web/default/src/features/profile/components/passkey-card.tsx @@ -187,7 +187,7 @@ export function PasskeyCard({ loading: pageLoading }: PasskeyCardProps) { if (pageLoading || loading) { return ( - + @@ -208,7 +208,7 @@ export function PasskeyCard({ loading: pageLoading }: PasskeyCardProps) { return ( <> - + {t('Passkey Login')} @@ -310,7 +310,7 @@ export function PasskeyCard({ loading: pageLoading }: PasskeyCardProps) { {t('Cancel')} { event.preventDefault() diff --git a/web/default/src/features/profile/components/profile-header.tsx b/web/default/src/features/profile/components/profile-header.tsx index 21106ebe2..7127f3513 100644 --- a/web/default/src/features/profile/components/profile-header.tsx +++ b/web/default/src/features/profile/components/profile-header.tsx @@ -18,12 +18,14 @@ For commercial licensing, please contact support@quantumnous.com */ import { Activity, BarChart3, WalletCards } from 'lucide-react' import { useTranslation } from 'react-i18next' +import { getUserAvatarFallback, getUserAvatarStyle } from '@/lib/avatar' import { formatCompactNumber, formatQuota } from '@/lib/format' import { getRoleLabel } from '@/lib/roles' import { Avatar, AvatarFallback } from '@/components/ui/avatar' +import { Card, CardContent } from '@/components/ui/card' import { Skeleton } from '@/components/ui/skeleton' import { StatusBadge } from '@/components/status-badge' -import { getUserInitials, getDisplayName } from '../lib' +import { getDisplayName } from '../lib' import type { UserProfile } from '../types' // ============================================================================ @@ -40,8 +42,8 @@ export function ProfileHeader({ profile, loading }: ProfileHeaderProps) { if (loading) { return ( -
-
+ +
@@ -56,7 +58,7 @@ export function ProfileHeader({ profile, loading }: ProfileHeaderProps) {
-
+
{Array.from({ length: 3 }).map((_, i) => ( @@ -68,14 +70,16 @@ export function ProfileHeader({ profile, loading }: ProfileHeaderProps) { ))}
-
+ ) } if (!profile) return null const displayName = getDisplayName(profile) - const initials = getUserInitials(profile) + const avatarName = profile.username || displayName + const avatarFallback = getUserAvatarFallback(avatarName) + const avatarFallbackStyle = getUserAvatarStyle(avatarName) const roleLabel = getRoleLabel(profile.role) const stats = [ { @@ -99,12 +103,15 @@ export function ProfileHeader({ profile, loading }: ProfileHeaderProps) { ] return ( -
-
+ +
- - {initials} + + {avatarFallback} @@ -142,7 +149,7 @@ export function ProfileHeader({ profile, loading }: ProfileHeaderProps) {
-
+
{stats.map((item) => ( @@ -164,6 +171,6 @@ export function ProfileHeader({ profile, loading }: ProfileHeaderProps) { ))}
-
+ ) } diff --git a/web/default/src/features/profile/components/profile-security-card.tsx b/web/default/src/features/profile/components/profile-security-card.tsx index 0329aed5d..137cfaf43 100644 --- a/web/default/src/features/profile/components/profile-security-card.tsx +++ b/web/default/src/features/profile/components/profile-security-card.tsx @@ -47,7 +47,7 @@ export function ProfileSecurityCard({ if (loading) { return ( - + @@ -93,6 +93,7 @@ export function ProfileSecurityCard({ title={t('Security')} description={t('Manage your security settings and account access')} icon={} + disableHoverEffect >
{securityActions.map((item) => ( @@ -100,10 +101,8 @@ export function ProfileSecurityCard({ key={item.title} type='button' onClick={item.action} - className={`hover:bg-muted/50 flex items-center gap-3 rounded-lg border p-3 text-left transition-colors md:flex-col md:gap-2 md:p-4 md:text-center ${ - item.variant === 'destructive' - ? 'border-destructive/30 hover:border-destructive/50 hover:bg-destructive/5' - : '' + className={`flex items-center gap-3 rounded-lg border p-3 text-left md:flex-col md:gap-2 md:p-4 md:text-center ${ + item.variant === 'destructive' ? 'border-destructive/30' : '' }`} >
+ @@ -67,6 +67,7 @@ export function ProfileSettingsCard({ title={t('Settings')} description={t('Configure your account preferences and integrations')} icon={} + disableHoverEffect > diff --git a/web/default/src/features/profile/components/sidebar-modules-card.tsx b/web/default/src/features/profile/components/sidebar-modules-card.tsx index 8e47bb751..72a4e719d 100644 --- a/web/default/src/features/profile/components/sidebar-modules-card.tsx +++ b/web/default/src/features/profile/components/sidebar-modules-card.tsx @@ -200,7 +200,7 @@ export function SidebarModulesCard() { } return ( - +
@@ -240,7 +240,7 @@ export function SidebarModulesCard() { {section.modules.map((mod) => (
diff --git a/web/default/src/features/profile/components/tabs/account-bindings-tab.tsx b/web/default/src/features/profile/components/tabs/account-bindings-tab.tsx index 014699175..d4b30d65d 100644 --- a/web/default/src/features/profile/components/tabs/account-bindings-tab.tsx +++ b/web/default/src/features/profile/components/tabs/account-bindings-tab.tsx @@ -350,7 +350,7 @@ export function AccountBindingsTab({ + ), }, ]} diff --git a/web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx b/web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx index 87571fe9e..d559ed1f0 100644 --- a/web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx +++ b/web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx @@ -487,7 +487,9 @@ export function DetailsDialog(props: DetailsDialogProps) { // Channel update records which fields changed (stable field tokens); render // them with their localized labels for admins. const changedFieldTokens = - isManage && props.isAdmin && Array.isArray(other?.op?.params?.changed_fields) + isManage && + props.isAdmin && + Array.isArray(other?.op?.params?.changed_fields) ? (other.op.params.changed_fields as string[]) : [] const changedFieldsText = changedFieldTokens diff --git a/web/default/src/features/wallet/components/affiliate-rewards-card.tsx b/web/default/src/features/wallet/components/affiliate-rewards-card.tsx index b0865ad3a..b3af98e17 100644 --- a/web/default/src/features/wallet/components/affiliate-rewards-card.tsx +++ b/web/default/src/features/wallet/components/affiliate-rewards-card.tsx @@ -44,7 +44,7 @@ export function AffiliateRewardsCard({ const { t } = useTranslation() if (loading) { return ( - +
@@ -60,7 +60,7 @@ export function AffiliateRewardsCard({ const hasRewards = (user?.aff_quota ?? 0) > 0 return ( - +
diff --git a/web/default/src/features/wallet/components/creem-products-section.tsx b/web/default/src/features/wallet/components/creem-products-section.tsx index 04e0655ab..a3daef2aa 100644 --- a/web/default/src/features/wallet/components/creem-products-section.tsx +++ b/web/default/src/features/wallet/components/creem-products-section.tsx @@ -55,7 +55,8 @@ export function CreemProductsSection({ {products.map((product) => ( onProductSelect(product)} > @@ -63,7 +64,7 @@ export function CreemProductsSection({
{t('Quota')}: {formatNumber(product.quota)}
-
+
{formatCreemPrice(product.price, product.currency)}
diff --git a/web/default/src/features/wallet/components/dialogs/billing-history-dialog.tsx b/web/default/src/features/wallet/components/dialogs/billing-history-dialog.tsx index 983b90e2c..e5d3d20e2 100644 --- a/web/default/src/features/wallet/components/dialogs/billing-history-dialog.tsx +++ b/web/default/src/features/wallet/components/dialogs/billing-history-dialog.tsx @@ -183,7 +183,7 @@ export function BillingHistoryDialog({ return (
{/* Header Row */}
diff --git a/web/default/src/features/wallet/components/dialogs/creem-confirm-dialog.tsx b/web/default/src/features/wallet/components/dialogs/creem-confirm-dialog.tsx index 5a1cf9a28..72aaaec98 100644 --- a/web/default/src/features/wallet/components/dialogs/creem-confirm-dialog.tsx +++ b/web/default/src/features/wallet/components/dialogs/creem-confirm-dialog.tsx @@ -76,7 +76,7 @@ export function CreemConfirmDialog({
{t('Price')} - + {formatCreemPrice(product.price, product.currency)}
diff --git a/web/default/src/features/wallet/components/recharge-form-card.tsx b/web/default/src/features/wallet/components/recharge-form-card.tsx index ad147dd4b..c1de6cff8 100644 --- a/web/default/src/features/wallet/components/recharge-form-card.tsx +++ b/web/default/src/features/wallet/components/recharge-form-card.tsx @@ -139,7 +139,7 @@ export function RechargeFormCard({ if (loading) { return ( - + @@ -191,6 +191,7 @@ export function RechargeFormCard({ title={t('Add Funds')} description={t('Choose an amount and payment method')} icon={} + disableHoverEffect action={ onOpenBilling ? (