Apply some tweaks on Admin UI (#11011)

### What problem does this PR solve?

- Fix selected radio button text misaligned with radio button dot
- Fix `<ScrollArea>` scrollbar z-index issue
- Add backdrop blur effect on scrollbar thumbs
- Adjust some styles to match the design 


### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
Jimmy Ben Klieve
2025-11-05 12:58:43 +08:00
committed by GitHub
parent 89410d2381
commit f126875ec6
8 changed files with 46 additions and 18 deletions

View File

@ -13,6 +13,7 @@ const ScrollBar = React.forwardRef<
ref={ref} ref={ref}
orientation={orientation} orientation={orientation}
className={cn( className={cn(
'z-[100]',
'flex touch-none select-none transition-colors', 'flex touch-none select-none transition-colors',
orientation === 'vertical' && orientation === 'vertical' &&
'h-full w-2.5 border-l border-l-transparent p-[1px]', 'h-full w-2.5 border-l border-l-transparent p-[1px]',
@ -22,7 +23,7 @@ const ScrollBar = React.forwardRef<
)} )}
{...props} {...props}
> >
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" /> <ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border backdrop-blur-md" />
</ScrollAreaPrimitive.ScrollAreaScrollbar> </ScrollAreaPrimitive.ScrollAreaScrollbar>
)); ));
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName; ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;

View File

@ -1980,6 +1980,10 @@ Important structured information may include: names, dates, locations, events, k
deleteRole: 'Delete role', deleteRole: 'Delete role',
deleteRoleConfirmation: deleteRoleConfirmation:
'Are you sure you want to delete this role? This action cannot be undone.', 'Are you sure you want to delete this role? This action cannot be undone.',
alive: 'Alive',
timeout: 'Timeout',
fail: 'Fail',
}, },
}, },
}; };

View File

@ -1,8 +1,11 @@
import Spotlight from '@/components/spotlight';
import { Card, CardContent } from '@/components/ui/card'; import { Card, CardContent } from '@/components/ui/card';
function AdminMonitoring() { function AdminMonitoring() {
return ( return (
<Card className="!shadow-none h-full border border-border-button bg-transparent rounded-xl overflow-x-hidden overflow-y-auto"> <Card className="!shadow-none relative h-full border border-border-button bg-transparent rounded-xl overflow-x-hidden overflow-y-auto">
<Spotlight />
<CardContent className="size-full p-0"> <CardContent className="size-full p-0">
<iframe /> <iframe />
</CardContent> </CardContent>

View File

@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import Spotlight from '@/components/spotlight';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { import {
@ -29,7 +30,6 @@ import {
import { LucideEdit3, LucideTrash2, LucideUserPlus } from 'lucide-react'; import { LucideEdit3, LucideTrash2, LucideUserPlus } from 'lucide-react';
import { import {
AdminService,
assignRolePermissions, assignRolePermissions,
createRole, createRole,
deleteRole, deleteRole,
@ -149,7 +149,9 @@ function AdminRoles() {
return ( return (
<> <>
<Card className="!shadow-none w-full h-full border border-border-button bg-transparent rounded-xl"> <Card className="!shadow-none relative w-full h-full border border-border-button bg-transparent rounded-xl">
<Spotlight />
<ScrollArea className="size-full"> <ScrollArea className="size-full">
<CardHeader className="space-y-0 flex flex-row justify-between items-center"> <CardHeader className="space-y-0 flex flex-row justify-between items-center">
<CardTitle>{t('admin.roles')}</CardTitle> <CardTitle>{t('admin.roles')}</CardTitle>

View File

@ -23,6 +23,7 @@ import { useQuery } from '@tanstack/react-query';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import Spotlight from '@/components/spotlight';
import { TableEmpty } from '@/components/table-skeleton'; import { TableEmpty } from '@/components/table-skeleton';
import { Badge } from '@/components/ui/badge'; import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
@ -151,11 +152,11 @@ function AdminServiceStatus() {
alive: 'bg-state-success-5 text-state-success', alive: 'bg-state-success-5 text-state-success',
timeout: 'bg-state-error-5 text-state-error', timeout: 'bg-state-error-5 text-state-error',
fail: 'bg-gray-500/5 text-text-disable', fail: 'bg-gray-500/5 text-text-disable',
}[cell.getValue<string>()], }[cell.getValue()],
)} )}
> >
<LucideDot className="size-[1em] stroke-[8] mr-1" /> <LucideDot className="size-[1em] stroke-[8] mr-1" />
{cell.getValue()} {t(`admin.${cell.getValue()}`)}
</Badge> </Badge>
), ),
enableSorting: false, enableSorting: false,
@ -215,7 +216,9 @@ function AdminServiceStatus() {
return ( return (
<> <>
<Card className="!shadow-none h-full border border-border-button bg-transparent rounded-xl"> <Card className="!shadow-none relative h-full border border-border-button bg-transparent rounded-xl">
<Spotlight />
<ScrollArea className="size-full"> <ScrollArea className="size-full">
<CardHeader className="space-y-0 flex flex-row justify-between items-center"> <CardHeader className="space-y-0 flex flex-row justify-between items-center">
<CardTitle>{t('admin.serviceStatus')}</CardTitle> <CardTitle>{t('admin.serviceStatus')}</CardTitle>
@ -252,7 +255,7 @@ function AdminServiceStatus() {
table.getColumn('service_type')!?.setFilterValue table.getColumn('service_type')!?.setFilterValue
} }
> >
<Label className="space-x-2"> <Label className="flex items-center space-x-2">
<RadioGroupItem <RadioGroupItem
className="bg-bg-input border-border-button" className="bg-bg-input border-border-button"
value="" value=""
@ -261,7 +264,10 @@ function AdminServiceStatus() {
</Label> </Label>
{SERVICE_TYPE_FILTER_OPTIONS.map(({ label, value }) => ( {SERVICE_TYPE_FILTER_OPTIONS.map(({ label, value }) => (
<Label key={value} className="space-x-2"> <Label
key={value}
className="flex items-center space-x-2"
>
<RadioGroupItem <RadioGroupItem
className="bg-bg-input border-border-button" className="bg-bg-input border-border-button"
value={value} value={value}

View File

@ -16,6 +16,7 @@ import {
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { Routes } from '@/routes'; import { Routes } from '@/routes';
import Spotlight from '@/components/spotlight';
import { Avatar } from '@/components/ui/avatar'; import { Avatar } from '@/components/ui/avatar';
import { Badge } from '@/components/ui/badge'; import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
@ -322,7 +323,9 @@ function AdminUserDetail() {
</Button> </Button>
</nav> </nav>
<Card className="!shadow-none h-0 basis-0 grow flex flex-col bg-transparent border dark:border-border-button overflow-hidden"> <Card className="!shadow-none relative h-0 basis-0 grow flex flex-col bg-transparent border dark:border-border-button overflow-hidden">
<Spotlight />
<CardHeader className="pb-10 border-b dark:border-border-button space-y-8"> <CardHeader className="pb-10 border-b dark:border-border-button space-y-8">
<section className="flex items-center gap-4 text-base"> <section className="flex items-center gap-4 text-base">
<Avatar className="justify-center items-center bg-bg-group uppercase"> <Avatar className="justify-center items-center bg-bg-group uppercase">

View File

@ -25,6 +25,7 @@ import {
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { rsaPsw } from '@/utils'; import { rsaPsw } from '@/utils';
import Spotlight from '@/components/spotlight';
import { TableEmpty } from '@/components/table-skeleton'; import { TableEmpty } from '@/components/table-skeleton';
import { Badge } from '@/components/ui/badge'; import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
@ -357,7 +358,9 @@ function AdminUserManagement() {
return ( return (
<> <>
<Card className="!shadow-none h-full border border-border-button bg-transparent rounded-xl overflow-x-hidden overflow-y-auto"> <Card className="!shadow-none relative h-full border border-border-button bg-transparent rounded-xl overflow-x-hidden overflow-y-auto">
<Spotlight />
<ScrollArea className="size-full"> <ScrollArea className="size-full">
<CardHeader className="space-y-0 flex flex-row justify-between items-center"> <CardHeader className="space-y-0 flex flex-row justify-between items-center">
<CardTitle>{t('admin.userManagement')}</CardTitle> <CardTitle>{t('admin.userManagement')}</CardTitle>
@ -396,13 +399,16 @@ function AdminUserManagement() {
table.getColumn('role')?.setFilterValue(value) table.getColumn('role')?.setFilterValue(value)
} }
> >
<Label className="space-x-2"> <Label className="flex items-center space-x-2">
<RadioGroupItem value="" /> <RadioGroupItem value="" />
<span>{t('admin.all')}</span> <span>{t('admin.all')}</span>
</Label> </Label>
{roleList?.map(({ id, role_name }) => ( {roleList?.map(({ id, role_name }) => (
<Label key={id} className="space-x-2"> <Label
key={id}
className="flex items-center space-x-2"
>
<RadioGroupItem <RadioGroupItem
className="bg-bg-input border-border-button" className="bg-bg-input border-border-button"
value={role_name} value={role_name}
@ -429,7 +435,10 @@ function AdminUserManagement() {
} }
> >
{STATUS_FILTER_OPTIONS.map(({ label, value }) => ( {STATUS_FILTER_OPTIONS.map(({ label, value }) => (
<Label key={value} className="space-x-2"> <Label
key={value}
className="flex items-center space-x-2"
>
<RadioGroupItem <RadioGroupItem
className="bg-bg-input border-border-button" className="bg-bg-input border-border-button"
value={value} value={value}

View File

@ -22,6 +22,7 @@ import {
LucideUserPen, LucideUserPen,
} from 'lucide-react'; } from 'lucide-react';
import Spotlight from '@/components/spotlight';
import { TableEmpty } from '@/components/table-skeleton'; import { TableEmpty } from '@/components/table-skeleton';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { import {
@ -58,7 +59,6 @@ import {
importWhitelistFromExcel, importWhitelistFromExcel,
listWhitelist, listWhitelist,
updateWhitelistEntry, updateWhitelistEntry,
type AdminService,
} from '@/services/admin-service'; } from '@/services/admin-service';
import { EMPTY_DATA, createFuzzySearchFn, getSortIcon } from './utils'; import { EMPTY_DATA, createFuzzySearchFn, getSortIcon } from './utils';
@ -68,8 +68,6 @@ import useImportExcelForm, {
ImportExcelFormData, ImportExcelFormData,
} from './forms/import-excel-form'; } from './forms/import-excel-form';
// #endregion
const columnHelper = createColumnHelper<AdminService.ListWhitelistItem>(); const columnHelper = createColumnHelper<AdminService.ListWhitelistItem>();
const globalFilterFn = createFuzzySearchFn<AdminService.ListWhitelistItem>([ const globalFilterFn = createFuzzySearchFn<AdminService.ListWhitelistItem>([
'email', 'email',
@ -233,7 +231,9 @@ function AdminWhitelist() {
return ( return (
<> <>
<Card className="!shadow-none h-full border border-border-button bg-transparent rounded-xl overflow-x-hidden overflow-y-auto"> <Card className="!shadow-none relative h-full border border-border-button bg-transparent rounded-xl overflow-x-hidden overflow-y-auto">
<Spotlight />
<ScrollArea className="size-full"> <ScrollArea className="size-full">
<CardHeader className="space-y-0 flex flex-row justify-between items-center"> <CardHeader className="space-y-0 flex flex-row justify-between items-center">
<CardTitle>{t('admin.whitelistManagement')}</CardTitle> <CardTitle>{t('admin.whitelistManagement')}</CardTitle>