mirror of
https://wget.la/https://github.com/Wxw-Gu/WechatExplorer
synced 2026-08-21 21:47:00 +08:00
feat: 统一界面视觉规范并优化导出交互
This commit is contained in:
@@ -177,7 +177,7 @@ export function ExportConfigurationPanel({
|
|||||||
aria-pressed={active}
|
aria-pressed={active}
|
||||||
className={`${
|
className={`${
|
||||||
active ? 'active border-2 border-primary bg-primary/10 hover:bg-primary/15' : ''
|
active ? 'active border-2 border-primary bg-primary/10 hover:bg-primary/15' : ''
|
||||||
} h-[78px] min-w-0 flex-col gap-1.5 whitespace-normal px-2 text-foreground`}
|
} !h-[78px] min-w-0 flex-col gap-1.5 whitespace-normal px-2 text-foreground`}
|
||||||
disabled={!exportAll && exportContactCount > 1 && value !== 'html'}
|
disabled={!exportAll && exportContactCount > 1 && value !== 'html'}
|
||||||
onClick={() => onFormatChange(value)}
|
onClick={() => onFormatChange(value)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import React from 'react'
|
import React, { useRef } from 'react'
|
||||||
|
import { useVirtualizer } from '@tanstack/react-virtual'
|
||||||
import type { ExportContactType } from '../../../../shared/export'
|
import type { ExportContactType } from '../../../../shared/export'
|
||||||
import { Button, Checkbox, Input, Tabs, TabsList, TabsTrigger } from '../ui'
|
import { Button, Checkbox, Input, Tabs, TabsList, TabsTrigger } from '../ui'
|
||||||
|
import { SearchIcon } from '../chat/icons'
|
||||||
import type { Contact, SelfInfo } from './exportTypes'
|
import type { Contact, SelfInfo } from './exportTypes'
|
||||||
import { displayName } from './exportUtils'
|
import { displayName } from './exportUtils'
|
||||||
|
|
||||||
@@ -27,6 +29,71 @@ interface ExportContactPanelProps {
|
|||||||
onOpenSettings: () => void
|
onOpenSettings: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ExportContactRowProps {
|
||||||
|
contact: Contact
|
||||||
|
active: boolean
|
||||||
|
pressed: boolean
|
||||||
|
selected: boolean
|
||||||
|
showSelection: boolean
|
||||||
|
disabled: boolean
|
||||||
|
style?: React.CSSProperties
|
||||||
|
onSelect: (contact: Contact) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
function ExportContactRow({
|
||||||
|
contact,
|
||||||
|
active,
|
||||||
|
pressed,
|
||||||
|
selected,
|
||||||
|
showSelection,
|
||||||
|
disabled,
|
||||||
|
style,
|
||||||
|
onSelect
|
||||||
|
}: ExportContactRowProps): React.ReactElement {
|
||||||
|
const name = displayName(contact)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`${style ? 'absolute left-0 top-0 ' : ''}flex w-full items-center gap-2.5 border-0 border-l-[3px] px-4 py-[11px] text-left text-foreground transition-colors hover:bg-surface/60 disabled:cursor-not-allowed disabled:opacity-50 ${
|
||||||
|
active ? 'border-l-primary bg-primary/10' : 'border-l-transparent bg-transparent'
|
||||||
|
}`}
|
||||||
|
style={style}
|
||||||
|
onClick={() => onSelect(contact)}
|
||||||
|
disabled={disabled}
|
||||||
|
aria-pressed={pressed}
|
||||||
|
>
|
||||||
|
<span className="grid h-[38px] w-[38px] shrink-0 place-items-center overflow-hidden rounded-lg bg-primary/10 font-bold text-primary">
|
||||||
|
{contact.avatar ? (
|
||||||
|
<img className="h-full w-full object-cover" src={contact.avatar} alt="" />
|
||||||
|
) : (
|
||||||
|
name.slice(0, 1)
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<span className="grid min-w-0 flex-1 gap-0.5">
|
||||||
|
<strong className="overflow-hidden text-ellipsis whitespace-nowrap text-[13px]">
|
||||||
|
{name}
|
||||||
|
</strong>
|
||||||
|
<small className="text-[11px] text-muted-foreground">
|
||||||
|
{contact.type === 'group' ? '群聊' : '联系人'}
|
||||||
|
</small>
|
||||||
|
</span>
|
||||||
|
{showSelection && (
|
||||||
|
<span
|
||||||
|
className={`grid h-[18px] w-[18px] shrink-0 place-items-center rounded border text-xs text-primary-foreground ${
|
||||||
|
selected ? 'border-primary bg-primary' : 'border-border-strong'
|
||||||
|
}`}
|
||||||
|
aria-hidden
|
||||||
|
>
|
||||||
|
{selected && (
|
||||||
|
<span className="h-2 w-1 -translate-y-px rotate-45 border-b-2 border-r-2 border-current" />
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function ExportContactPanel({
|
export function ExportContactPanel({
|
||||||
contacts,
|
contacts,
|
||||||
filteredContacts,
|
filteredContacts,
|
||||||
@@ -49,6 +116,17 @@ export function ExportContactPanel({
|
|||||||
onToggleAllContactType,
|
onToggleAllContactType,
|
||||||
onOpenSettings
|
onOpenSettings
|
||||||
}: ExportContactPanelProps): React.ReactElement {
|
}: ExportContactPanelProps): React.ReactElement {
|
||||||
|
const virtualizeContacts = filteredContacts.length >= 100
|
||||||
|
const contactListRef = useRef<HTMLDivElement>(null)
|
||||||
|
// TanStack Virtual owns mutable measurements, so React Compiler must skip this hook.
|
||||||
|
// eslint-disable-next-line react-hooks/incompatible-library
|
||||||
|
const contactVirtualizer = useVirtualizer({
|
||||||
|
count: virtualizeContacts ? filteredContacts.length : 0,
|
||||||
|
getScrollElement: () => contactListRef.current,
|
||||||
|
estimateSize: () => 60,
|
||||||
|
getItemKey: (index) => filteredContacts[index]?.md5 || index,
|
||||||
|
overscan: 10
|
||||||
|
})
|
||||||
const groupCount = contacts.filter((contact) => contact.type === 'group').length
|
const groupCount = contacts.filter((contact) => contact.type === 'group').length
|
||||||
const userCount = contacts.length - groupCount
|
const userCount = contacts.length - groupCount
|
||||||
const selectedAllCount =
|
const selectedAllCount =
|
||||||
@@ -69,7 +147,7 @@ export function ExportContactPanel({
|
|||||||
className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground"
|
className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground"
|
||||||
aria-hidden
|
aria-hidden
|
||||||
>
|
>
|
||||||
⌕
|
<SearchIcon className="h-3.5 w-3.5 fill-none stroke-current stroke-2" />
|
||||||
</span>
|
</span>
|
||||||
<Input
|
<Input
|
||||||
className="h-[38px] pl-9 text-[13px]"
|
className="h-[38px] pl-9 text-[13px]"
|
||||||
@@ -104,7 +182,7 @@ export function ExportContactPanel({
|
|||||||
</Tabs>
|
</Tabs>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className={`mt-2.5 h-auto w-full justify-between gap-3 px-2.5 py-2 text-left ${
|
className={`mt-2.5 !h-auto w-full justify-between gap-3 px-2.5 py-2 text-left ${
|
||||||
exportAll ? 'border-primary bg-primary/10 text-primary hover:bg-primary/15' : ''
|
exportAll ? 'border-primary bg-primary/10 text-primary hover:bg-primary/15' : ''
|
||||||
}`}
|
}`}
|
||||||
aria-pressed={exportAll}
|
aria-pressed={exportAll}
|
||||||
@@ -170,61 +248,71 @@ export function ExportContactPanel({
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<div className="export-contact-list min-h-0 flex-1 overflow-auto py-2">
|
<div ref={contactListRef} className="export-contact-list min-h-0 flex-1 overflow-auto py-2">
|
||||||
{filteredContacts.map((contact) => {
|
{virtualizeContacts ? (
|
||||||
const name = displayName(contact)
|
<div
|
||||||
const selected = selectedContactIds.includes(contact.md5)
|
className="relative w-full"
|
||||||
const selectedByAll = exportAll && allContactTypes.includes(contact.type)
|
style={{ height: `${contactVirtualizer.getTotalSize()}px` }}
|
||||||
const visuallySelected = exportAll ? selectedByAll : selected
|
>
|
||||||
const atLimit =
|
{contactVirtualizer.getVirtualItems().map((virtualItem) => {
|
||||||
!exportAll && selectionMode && !selected && selectedContactIds.length >= selectionLimit
|
const contact = filteredContacts[virtualItem.index]
|
||||||
return (
|
if (!contact) return null
|
||||||
<button
|
const selected = selectedContactIds.includes(contact.md5)
|
||||||
key={contact.md5}
|
const selectedByAll = exportAll && allContactTypes.includes(contact.type)
|
||||||
type="button"
|
const visuallySelected = exportAll ? selectedByAll : selected
|
||||||
className={`flex w-full items-center gap-2.5 border-0 border-l-[3px] px-4 py-[11px] text-left text-foreground transition-colors hover:bg-surface/60 disabled:cursor-not-allowed disabled:opacity-50 ${
|
const atLimit =
|
||||||
!exportAll && activeContact?.md5 === contact.md5
|
!exportAll &&
|
||||||
? 'border-l-primary bg-primary/10'
|
selectionMode &&
|
||||||
: 'border-l-transparent bg-transparent'
|
!selected &&
|
||||||
}`}
|
selectedContactIds.length >= selectionLimit
|
||||||
onClick={() => onSelectContact(contact)}
|
return (
|
||||||
disabled={atLimit}
|
<ExportContactRow
|
||||||
aria-pressed={visuallySelected}
|
key={virtualItem.key}
|
||||||
>
|
contact={contact}
|
||||||
<span className="grid h-[38px] w-[38px] shrink-0 place-items-center overflow-hidden rounded-lg bg-primary/10 font-bold text-primary">
|
active={!exportAll && activeContact?.md5 === contact.md5}
|
||||||
{contact.avatar ? (
|
pressed={visuallySelected}
|
||||||
<img className="h-full w-full object-cover" src={contact.avatar} alt="" />
|
selected={selected}
|
||||||
) : (
|
showSelection={!exportAll && selectionMode}
|
||||||
name.slice(0, 1)
|
disabled={atLimit}
|
||||||
)}
|
style={{
|
||||||
</span>
|
height: `${virtualItem.size}px`,
|
||||||
<span className="grid min-w-0 flex-1 gap-0.5">
|
transform: `translateY(${virtualItem.start}px)`
|
||||||
<strong className="overflow-hidden text-ellipsis whitespace-nowrap text-[13px]">
|
}}
|
||||||
{name}
|
onSelect={onSelectContact}
|
||||||
</strong>
|
/>
|
||||||
<small className="text-[11px] text-muted-foreground">
|
)
|
||||||
{contact.type === 'group' ? '群聊' : '联系人'}
|
})}
|
||||||
</small>
|
</div>
|
||||||
</span>
|
) : (
|
||||||
{!exportAll && selectionMode && (
|
filteredContacts.map((contact) => {
|
||||||
<span
|
const selected = selectedContactIds.includes(contact.md5)
|
||||||
className={`grid h-[18px] w-[18px] shrink-0 place-items-center rounded border text-xs text-primary-foreground ${
|
const selectedByAll = exportAll && allContactTypes.includes(contact.type)
|
||||||
selected ? 'border-primary bg-primary' : 'border-border-strong'
|
const visuallySelected = exportAll ? selectedByAll : selected
|
||||||
}`}
|
const atLimit =
|
||||||
aria-hidden
|
!exportAll &&
|
||||||
>
|
selectionMode &&
|
||||||
{selected ? '✓' : ''}
|
!selected &&
|
||||||
</span>
|
selectedContactIds.length >= selectionLimit
|
||||||
)}
|
return (
|
||||||
</button>
|
<ExportContactRow
|
||||||
)
|
key={contact.md5}
|
||||||
})}
|
contact={contact}
|
||||||
|
active={!exportAll && activeContact?.md5 === contact.md5}
|
||||||
|
pressed={visuallySelected}
|
||||||
|
selected={selected}
|
||||||
|
showSelection={!exportAll && selectionMode}
|
||||||
|
disabled={atLimit}
|
||||||
|
onSelect={onSelectContact}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
className="h-auto justify-start gap-2 border-t border-border px-4 py-3.5 text-left"
|
className="!h-auto justify-start gap-2 border-t border-border px-4 py-3.5 text-left"
|
||||||
onClick={onOpenSettings}
|
onClick={onOpenSettings}
|
||||||
>
|
>
|
||||||
<span className="grid h-[34px] w-[34px] shrink-0 place-items-center overflow-hidden rounded-full bg-primary/10 font-bold text-primary">
|
<span className="grid h-[34px] w-[34px] shrink-0 place-items-center overflow-hidden rounded-full bg-primary/10 font-bold text-primary">
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ export function ExportPreviewPanel({
|
|||||||
systemMessage
|
systemMessage
|
||||||
? 'max-w-[92%] bg-muted px-2.5 py-1 text-center text-[11px] text-muted-foreground shadow-none'
|
? 'max-w-[92%] bg-muted px-2.5 py-1 text-center text-[11px] text-muted-foreground shadow-none'
|
||||||
: message.isSender
|
: message.isSender
|
||||||
? 'bg-[#95ec69]'
|
? 'bg-accent'
|
||||||
: 'bg-surface'
|
: 'bg-surface'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -3,23 +3,27 @@ import { cva, type VariantProps } from 'class-variance-authority'
|
|||||||
import { cn } from '../../lib/cn'
|
import { cn } from '../../lib/cn'
|
||||||
|
|
||||||
const buttonVariants = cva(
|
const buttonVariants = cva(
|
||||||
'inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md border-0 bg-transparent text-sm font-medium transition-colors duration-fast ease-tm-standard focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',
|
'inline-flex shrink-0 items-center justify-center gap-1.5 whitespace-nowrap rounded-md border-0 bg-transparent text-sm font-medium transition-[color,background-color,border-color,transform] duration-fast ease-tm-standard active:translate-y-px disabled:pointer-events-none disabled:translate-y-0 disabled:!text-disabled-foreground disabled:opacity-100',
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default: 'bg-primary text-primary-foreground shadow-surface hover:bg-primary/90',
|
default:
|
||||||
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/75',
|
'bg-primary text-primary-foreground hover:bg-primary-hover disabled:bg-disabled-surface disabled:text-disabled-foreground',
|
||||||
ghost: 'text-foreground hover:bg-accent hover:text-accent-foreground',
|
secondary:
|
||||||
outline: 'border border-border bg-surface text-foreground shadow-surface hover:bg-accent',
|
'bg-secondary text-secondary-foreground hover:bg-secondary/75 active:bg-secondary/60 disabled:bg-disabled-surface disabled:text-disabled-foreground',
|
||||||
|
ghost:
|
||||||
|
'text-foreground hover:bg-accent hover:text-accent-foreground active:bg-accent/75 disabled:text-disabled-foreground',
|
||||||
|
outline:
|
||||||
|
'border border-border bg-surface text-foreground hover:border-primary/25 hover:bg-accent active:bg-accent/75 disabled:border-disabled-border disabled:bg-disabled-surface disabled:text-disabled-foreground',
|
||||||
destructive:
|
destructive:
|
||||||
'bg-destructive text-destructive-foreground shadow-surface hover:bg-destructive/90',
|
'bg-destructive text-destructive-foreground hover:bg-destructive/90 active:bg-destructive/80 disabled:bg-disabled-surface disabled:text-disabled-foreground',
|
||||||
link: 'text-primary underline-offset-4 hover:underline'
|
link: '!h-auto !p-0 text-primary underline-offset-4 hover:text-primary-hover hover:underline disabled:text-disabled-foreground'
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
sm: 'h-8 rounded-md px-3 text-xs',
|
sm: 'h-control-compact rounded-md px-2.5 text-xs',
|
||||||
default: 'h-9 px-4 py-2',
|
default: 'h-control-standard px-3.5',
|
||||||
lg: 'h-10 rounded-lg px-6',
|
lg: 'h-control-form rounded-lg px-5',
|
||||||
icon: 'h-9 w-9'
|
icon: 'h-control-standard w-8 p-0'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ const Checkbox = React.forwardRef<
|
|||||||
<CheckboxPrimitive.Root
|
<CheckboxPrimitive.Root
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'peer h-4 w-4 shrink-0 rounded-sm border border-border bg-surface shadow-surface transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
|
'peer h-4 w-4 shrink-0 rounded-sm border border-muted-foreground/60 bg-surface transition-colors duration-fast ease-tm-standard hover:border-primary/70 disabled:cursor-not-allowed disabled:border-disabled-border disabled:bg-disabled-surface disabled:text-disabled-foreground disabled:opacity-100 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground disabled:data-[state=checked]:border-disabled-border disabled:data-[state=checked]:bg-primary/40',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<CheckboxPrimitive.Indicator className="flex items-center justify-center text-[11px]">
|
<CheckboxPrimitive.Indicator className="flex items-center justify-center">
|
||||||
✓
|
<span className="h-2 w-1 -translate-y-px rotate-45 border-b-2 border-r-2 border-current" />
|
||||||
</CheckboxPrimitive.Indicator>
|
</CheckboxPrimitive.Indicator>
|
||||||
</CheckboxPrimitive.Root>
|
</CheckboxPrimitive.Root>
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export const Input = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
type={type}
|
type={type}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex h-9 w-full rounded-md border border-border bg-surface px-3 py-1 text-sm text-foreground shadow-surface transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',
|
'flex h-control-form w-full rounded-md border border-border bg-surface px-3 py-1 text-sm text-foreground transition-colors duration-fast ease-tm-standard placeholder:text-muted-foreground hover:border-primary/25 disabled:cursor-not-allowed disabled:border-disabled-border disabled:bg-disabled-surface disabled:text-disabled-foreground disabled:opacity-100 disabled:placeholder:text-disabled-foreground',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const RadioGroupItem = React.forwardRef<
|
|||||||
<RadioGroupPrimitive.Item
|
<RadioGroupPrimitive.Item
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'aspect-square h-4 w-4 rounded-full border border-border bg-surface text-primary shadow-surface focus:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',
|
'aspect-square h-4 w-4 rounded-full border border-muted-foreground/60 bg-surface text-primary transition-colors duration-fast ease-tm-standard hover:border-primary/70 disabled:cursor-not-allowed disabled:border-disabled-border disabled:bg-disabled-surface disabled:text-disabled-foreground disabled:opacity-100 data-[state=checked]:border-primary disabled:data-[state=checked]:border-disabled-border',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -13,14 +13,17 @@ const SelectTrigger = React.forwardRef<
|
|||||||
<SelectPrimitive.Trigger
|
<SelectPrimitive.Trigger
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex h-9 w-full items-center justify-between rounded-md border border-border bg-surface px-3 py-2 text-sm text-foreground shadow-surface focus:outline-none focus:ring-2 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
|
'flex h-control-form w-full items-center justify-between rounded-md border border-border bg-surface px-3 py-2 text-sm text-foreground transition-colors duration-fast ease-tm-standard hover:border-primary/25 disabled:cursor-not-allowed disabled:border-disabled-border disabled:bg-disabled-surface disabled:text-disabled-foreground disabled:opacity-100 [&>span]:line-clamp-1',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
<span aria-hidden="true" className="ml-2 text-muted-foreground">
|
<span
|
||||||
⌄
|
aria-hidden="true"
|
||||||
|
className="ml-2 flex h-4 w-4 shrink-0 items-center justify-center text-muted-foreground"
|
||||||
|
>
|
||||||
|
<span className="h-1.5 w-1.5 -translate-y-px rotate-45 border-b border-r border-current" />
|
||||||
</span>
|
</span>
|
||||||
</SelectPrimitive.Trigger>
|
</SelectPrimitive.Trigger>
|
||||||
))
|
))
|
||||||
@@ -66,13 +69,13 @@ const SelectItem = React.forwardRef<
|
|||||||
<SelectPrimitive.Item
|
<SelectPrimitive.Item
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
'relative flex min-h-8 w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors duration-fast ease-tm-standard focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:text-disabled-foreground data-[disabled]:opacity-100',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<SelectPrimitive.ItemIndicator className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
<SelectPrimitive.ItemIndicator className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center text-primary">
|
||||||
✓
|
<span className="h-2 w-1 rotate-45 border-b-2 border-r-2 border-current" />
|
||||||
</SelectPrimitive.ItemIndicator>
|
</SelectPrimitive.ItemIndicator>
|
||||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||||
</SelectPrimitive.Item>
|
</SelectPrimitive.Item>
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ const Switch = React.forwardRef<
|
|||||||
<SwitchPrimitive.Root
|
<SwitchPrimitive.Root
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent bg-muted transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary',
|
'peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent bg-muted transition-colors duration-fast ease-tm-standard hover:bg-muted/80 disabled:cursor-not-allowed disabled:bg-disabled-surface disabled:opacity-100 data-[state=checked]:bg-primary disabled:data-[state=checked]:bg-primary/40',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<SwitchPrimitive.Thumb className="pointer-events-none block h-4 w-4 rounded-full bg-white shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0" />
|
<SwitchPrimitive.Thumb className="pointer-events-none block h-4 w-4 rounded-full bg-white shadow-surface ring-0 transition-transform duration-fast ease-tm-standard data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0" />
|
||||||
</SwitchPrimitive.Root>
|
</SwitchPrimitive.Root>
|
||||||
))
|
))
|
||||||
Switch.displayName = SwitchPrimitive.Root.displayName
|
Switch.displayName = SwitchPrimitive.Root.displayName
|
||||||
|
|||||||
@@ -1,20 +1,21 @@
|
|||||||
:root {
|
:root {
|
||||||
--wxex-bg-app: #f4f6f5;
|
// Original TraceMemo brand tokens remain available while the UI Layer consumes --tm-*.
|
||||||
--wxex-bg-main: #fafbfa;
|
--wxex-bg-app: hsl(var(--tm-background));
|
||||||
--wxex-bg-sidebar: #eef2f0;
|
--wxex-bg-main: hsl(var(--tm-canvas));
|
||||||
--wxex-bg-elevated: #ffffff;
|
--wxex-bg-sidebar: hsl(var(--tm-surface-muted));
|
||||||
--wxex-text-primary: #202724;
|
--wxex-bg-elevated: hsl(var(--tm-surface-elevated));
|
||||||
--wxex-text-secondary: #66706b;
|
--wxex-text-primary: hsl(var(--tm-foreground));
|
||||||
--wxex-text-muted: #929a96;
|
--wxex-text-secondary: hsl(var(--tm-muted-foreground));
|
||||||
--wxex-border: #dde3e0;
|
--wxex-text-muted: hsl(var(--tm-subtle-foreground));
|
||||||
--wxex-brand: #247a63;
|
--wxex-border: hsl(var(--tm-border));
|
||||||
--wxex-brand-hover: #1d6754;
|
--wxex-brand: hsl(var(--tm-primary));
|
||||||
--wxex-brand-soft: #ddede7;
|
--wxex-brand-hover: hsl(var(--tm-primary-hover));
|
||||||
--wxex-ai: #686edc;
|
--wxex-brand-soft: hsl(var(--tm-accent));
|
||||||
--wxex-ai-soft: #eeeffd;
|
--wxex-ai: hsl(var(--tm-ai));
|
||||||
--wxex-success: #2e8b68;
|
--wxex-ai-soft: hsl(var(--tm-ai-soft));
|
||||||
--wxex-warning: #c68635;
|
--wxex-success: hsl(var(--tm-success));
|
||||||
--wxex-danger: #c85a5a;
|
--wxex-warning: hsl(var(--tm-warning));
|
||||||
|
--wxex-danger: hsl(var(--tm-destructive));
|
||||||
--wxex-font:
|
--wxex-font:
|
||||||
-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
||||||
--wxex-nav-width: 76px;
|
--wxex-nav-width: 76px;
|
||||||
|
|||||||
@@ -86,7 +86,6 @@
|
|||||||
}
|
}
|
||||||
.api-section-heading h2,
|
.api-section-heading h2,
|
||||||
.api-introduction h2,
|
.api-introduction h2,
|
||||||
.api-integrations h2,
|
|
||||||
.api-runtime-title h2 {
|
.api-runtime-title h2 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: var(--wxex-text-primary);
|
color: var(--wxex-text-primary);
|
||||||
@@ -150,7 +149,7 @@
|
|||||||
}
|
}
|
||||||
.api-skill-status.error {
|
.api-skill-status.error {
|
||||||
color: var(--wxex-danger);
|
color: var(--wxex-danger);
|
||||||
background: #fff1f1;
|
background: color-mix(in srgb, var(--wxex-danger) 10%, var(--wxex-bg-elevated));
|
||||||
}
|
}
|
||||||
.api-version {
|
.api-version {
|
||||||
color: var(--wxex-text-muted);
|
color: var(--wxex-text-muted);
|
||||||
@@ -166,21 +165,6 @@
|
|||||||
.api-header-actions {
|
.api-header-actions {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
.api-primary-button {
|
|
||||||
border-color: var(--wxex-brand) !important;
|
|
||||||
background: var(--wxex-brand) !important;
|
|
||||||
color: #fff !important;
|
|
||||||
}
|
|
||||||
.api-primary-button:hover:not(:disabled),
|
|
||||||
.api-primary-button:focus-visible,
|
|
||||||
.api-primary-button:active {
|
|
||||||
background: var(--wxex-brand-hover) !important;
|
|
||||||
color: #fff !important;
|
|
||||||
}
|
|
||||||
.api-primary-button:disabled {
|
|
||||||
cursor: not-allowed;
|
|
||||||
opacity: 0.55;
|
|
||||||
}
|
|
||||||
.api-trust-bar {
|
.api-trust-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
@@ -190,7 +174,7 @@
|
|||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
border: 1px solid var(--wxex-border);
|
border: 1px solid var(--wxex-border);
|
||||||
border-radius: var(--wxex-radius-md);
|
border-radius: var(--wxex-radius-md);
|
||||||
background: #f5f8f6;
|
background: var(--wxex-bg-sidebar);
|
||||||
color: var(--wxex-text-secondary);
|
color: var(--wxex-text-secondary);
|
||||||
font: 12px/18px var(--wxex-font);
|
font: 12px/18px var(--wxex-font);
|
||||||
}
|
}
|
||||||
@@ -228,7 +212,7 @@
|
|||||||
padding: 7px 10px;
|
padding: 7px 10px;
|
||||||
border: 1px solid var(--wxex-border);
|
border: 1px solid var(--wxex-border);
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
background: #fff;
|
background: var(--wxex-bg-elevated);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
.api-flow strong {
|
.api-flow strong {
|
||||||
@@ -360,7 +344,7 @@
|
|||||||
padding: 11px 14px;
|
padding: 11px 14px;
|
||||||
}
|
}
|
||||||
.api-endpoint-head {
|
.api-endpoint-head {
|
||||||
background: #f1f4f2;
|
background: var(--wxex-bg-sidebar);
|
||||||
color: var(--wxex-text-secondary);
|
color: var(--wxex-text-secondary);
|
||||||
font: 700 12px/18px var(--wxex-font);
|
font: 700 12px/18px var(--wxex-font);
|
||||||
}
|
}
|
||||||
@@ -371,7 +355,7 @@
|
|||||||
font: 12px/18px var(--wxex-font);
|
font: 12px/18px var(--wxex-font);
|
||||||
}
|
}
|
||||||
.api-endpoint-row.active {
|
.api-endpoint-row.active {
|
||||||
background: #f7faf8;
|
background: var(--wxex-brand-soft);
|
||||||
}
|
}
|
||||||
.api-endpoint-row code {
|
.api-endpoint-row code {
|
||||||
color: var(--wxex-text-primary);
|
color: var(--wxex-text-primary);
|
||||||
@@ -405,7 +389,7 @@
|
|||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
border: 1px solid var(--wxex-border);
|
border: 1px solid var(--wxex-border);
|
||||||
border-radius: var(--wxex-radius-md);
|
border-radius: var(--wxex-radius-md);
|
||||||
background: #f5f8f6;
|
background: var(--wxex-bg-sidebar);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.api-request-meta code {
|
.api-request-meta code {
|
||||||
@@ -446,7 +430,7 @@
|
|||||||
padding: 8px 10px;
|
padding: 8px 10px;
|
||||||
border: 1px solid rgba(200, 90, 90, 0.35);
|
border: 1px solid rgba(200, 90, 90, 0.35);
|
||||||
border-radius: var(--wxex-radius-sm);
|
border-radius: var(--wxex-radius-sm);
|
||||||
background: #fff4f4;
|
background: color-mix(in srgb, var(--wxex-danger) 10%, var(--wxex-bg-elevated));
|
||||||
color: var(--wxex-danger);
|
color: var(--wxex-danger);
|
||||||
font: 12px/18px var(--wxex-font);
|
font: 12px/18px var(--wxex-font);
|
||||||
}
|
}
|
||||||
@@ -512,8 +496,8 @@
|
|||||||
margin: 12px 16px;
|
margin: 12px 16px;
|
||||||
padding: 9px 10px;
|
padding: 9px 10px;
|
||||||
border-left: 3px solid var(--wxex-warning);
|
border-left: 3px solid var(--wxex-warning);
|
||||||
background: #fff8ec;
|
background: color-mix(in srgb, var(--wxex-warning) 10%, var(--wxex-bg-elevated));
|
||||||
color: #915d1e;
|
color: var(--wxex-warning);
|
||||||
font: 12px/18px var(--wxex-font);
|
font: 12px/18px var(--wxex-font);
|
||||||
}
|
}
|
||||||
.api-token-value {
|
.api-token-value {
|
||||||
@@ -595,7 +579,7 @@
|
|||||||
font: 11px/16px var(--wxex-font);
|
font: 11px/16px var(--wxex-font);
|
||||||
}
|
}
|
||||||
.api-privacy {
|
.api-privacy {
|
||||||
background: #f5f8f6;
|
background: var(--wxex-bg-sidebar);
|
||||||
}
|
}
|
||||||
.api-privacy p {
|
.api-privacy p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|||||||
@@ -162,7 +162,7 @@
|
|||||||
grid-template-columns: auto 1fr;
|
grid-template-columns: auto 1fr;
|
||||||
gap: 3px 10px;
|
gap: 3px 10px;
|
||||||
border-radius: var(--wxex-radius-md);
|
border-radius: var(--wxex-radius-md);
|
||||||
background: #f3f6f4;
|
background: var(--wxex-bg-sidebar);
|
||||||
padding: 12px 14px;
|
padding: 12px 14px;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
@@ -201,8 +201,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.blocked {
|
&.blocked {
|
||||||
border-color: rgba(190, 96, 60, 0.24);
|
border-color: color-mix(in srgb, var(--wxex-danger) 28%, transparent);
|
||||||
background: rgba(190, 96, 60, 0.06);
|
background: color-mix(in srgb, var(--wxex-danger) 7%, var(--wxex-bg-elevated));
|
||||||
}
|
}
|
||||||
|
|
||||||
strong,
|
strong,
|
||||||
@@ -230,7 +230,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
small.error {
|
small.error {
|
||||||
color: #b15338;
|
color: var(--wxex-danger);
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -287,11 +287,11 @@
|
|||||||
|
|
||||||
.ready & {
|
.ready & {
|
||||||
background: var(--wxex-success);
|
background: var(--wxex-success);
|
||||||
box-shadow: 0 0 0 3px rgba(36, 122, 99, 0.12);
|
box-shadow: 0 0 0 3px color-mix(in srgb, var(--wxex-success) 14%, transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.blocked & {
|
.blocked & {
|
||||||
background: #be603c;
|
background: var(--wxex-danger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,11 +406,11 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
gap: 3px;
|
gap: 3px;
|
||||||
border-radius: var(--wxex-radius-md);
|
border-radius: var(--wxex-radius-md);
|
||||||
background: rgba(190, 96, 60, 0.08);
|
background: color-mix(in srgb, var(--wxex-warning) 10%, var(--wxex-bg-elevated));
|
||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
|
|
||||||
&.ready {
|
&.ready {
|
||||||
background: rgba(36, 122, 99, 0.08);
|
background: color-mix(in srgb, var(--wxex-success) 9%, var(--wxex-bg-elevated));
|
||||||
}
|
}
|
||||||
|
|
||||||
strong {
|
strong {
|
||||||
@@ -559,8 +559,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.error {
|
&.error {
|
||||||
background: rgba(190, 96, 60, 0.1);
|
background: color-mix(in srgb, var(--wxex-danger) 10%, var(--wxex-bg-elevated));
|
||||||
color: #a84e32;
|
color: var(--wxex-danger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -621,7 +621,7 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
border-bottom: 1px solid var(--wxex-border);
|
border-bottom: 1px solid var(--wxex-border);
|
||||||
background: #f3f6f4;
|
background: var(--wxex-bg-sidebar);
|
||||||
color: var(--wxex-text-secondary);
|
color: var(--wxex-text-secondary);
|
||||||
padding: 0 18px;
|
padding: 0 18px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
@@ -769,11 +769,6 @@
|
|||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wechat-system-message-meta {
|
|
||||||
color: #a0a7ab;
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-avatar {
|
.message-avatar {
|
||||||
width: 38px;
|
width: 38px;
|
||||||
height: 38px;
|
height: 38px;
|
||||||
@@ -845,10 +840,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-meta {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-hover-time,
|
.message-hover-time,
|
||||||
.message-accessible-sender {
|
.message-accessible-sender {
|
||||||
color: var(--wxex-text-muted);
|
color: var(--wxex-text-muted);
|
||||||
@@ -1202,90 +1193,6 @@
|
|||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
font-size: 13px;
|
|
||||||
|
|
||||||
th {
|
|
||||||
text-align: left;
|
|
||||||
padding: 8px;
|
|
||||||
border-bottom: 1px solid var(--border-color);
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
color: #666;
|
|
||||||
font-weight: normal;
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 1;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
|
||||||
padding: 8px;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
vertical-align: top;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr:hover {
|
|
||||||
background-color: #f0f0f0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.column-resizer {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 5px;
|
|
||||||
cursor: col-resize;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.column-resizer:hover {
|
|
||||||
background-color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.col-sender {
|
|
||||||
width: 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.col-type {
|
|
||||||
width: 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.col-time {
|
|
||||||
width: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.col-content {
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-toolbar {
|
|
||||||
padding: 10px;
|
|
||||||
border-top: 1px solid var(--border-color);
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
background-color: #fff;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
.toolbar-btn {
|
|
||||||
padding: 4px 12px;
|
|
||||||
border: 1px solid #dcdcdc;
|
|
||||||
border-radius: 4px;
|
|
||||||
background-color: #fff;
|
|
||||||
font-size: 12px;
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 4px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-state {
|
.empty-state {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -1970,143 +1877,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-overlay {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
background: white;
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
||||||
min-width: 400px;
|
|
||||||
max-width: 90vw;
|
|
||||||
max-height: 90vh;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-settings-modal {
|
|
||||||
width: min(460px, 90vw);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-settings-modal h3 {
|
|
||||||
margin: 0 0 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-filter-section {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-filter-label {
|
|
||||||
margin-bottom: 7px;
|
|
||||||
color: #333;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-date-options {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
||||||
gap: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-date-options label {
|
|
||||||
display: flex;
|
|
||||||
min-width: 0;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 5px;
|
|
||||||
padding: 8px 6px;
|
|
||||||
border: 1px solid #d8dcdf;
|
|
||||||
border-radius: 6px;
|
|
||||||
background: #fff;
|
|
||||||
color: #4a5257;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-date-options label.selected {
|
|
||||||
border-color: #07c160;
|
|
||||||
background: #eefaf3;
|
|
||||||
color: #078f49;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-date-options input,
|
|
||||||
.ai-type-options input {
|
|
||||||
margin: 0;
|
|
||||||
accent-color: #07c160;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-type-options {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
||||||
gap: 8px 10px;
|
|
||||||
padding: 11px;
|
|
||||||
border: 1px solid #e1e4e6;
|
|
||||||
border-radius: 6px;
|
|
||||||
background: #f8f9fa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-type-options label {
|
|
||||||
display: flex;
|
|
||||||
min-width: 0;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
color: #3f474c;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 13px;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-preview-modal {
|
|
||||||
width: min(520px, 92vw);
|
|
||||||
max-height: 88vh;
|
|
||||||
background: #f7f8fa;
|
|
||||||
box-shadow: 0 18px 48px rgba(0, 0, 0, 0.18);
|
|
||||||
padding: 16px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.report-preview-frame {
|
|
||||||
border: 1px solid #d8dde3;
|
|
||||||
border-radius: 10px;
|
|
||||||
background: #eef1f4;
|
|
||||||
padding: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.report-preview-scroller {
|
|
||||||
max-height: calc(88vh - 120px);
|
|
||||||
overflow-y: auto;
|
|
||||||
overflow-x: hidden;
|
|
||||||
padding-right: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.report-preview-image {
|
|
||||||
display: block;
|
|
||||||
width: min(430px, 100%);
|
|
||||||
height: auto;
|
|
||||||
margin: 0 auto;
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid #ccd3d9;
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.report-preview-actions {
|
|
||||||
margin-top: 12px;
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.database-account-list {
|
.database-account-list {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
|||||||
@@ -109,39 +109,6 @@
|
|||||||
stroke-linejoin: round;
|
stroke-linejoin: round;
|
||||||
}
|
}
|
||||||
|
|
||||||
.conversation-date-range {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
|
||||||
gap: 6px;
|
|
||||||
margin-top: 10px;
|
|
||||||
-webkit-app-region: no-drag;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conversation-date-range-button {
|
|
||||||
box-sizing: border-box;
|
|
||||||
height: 30px;
|
|
||||||
min-width: 0;
|
|
||||||
border: 1px solid var(--wxex-border);
|
|
||||||
border-radius: var(--wxex-radius-md);
|
|
||||||
background: var(--wxex-bg-elevated);
|
|
||||||
color: var(--wxex-text-secondary);
|
|
||||||
cursor: pointer;
|
|
||||||
font: 12px/16px var(--wxex-font);
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-color: rgba(36, 122, 99, 0.28);
|
|
||||||
color: var(--wxex-text-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
border-color: var(--wxex-brand);
|
|
||||||
background: var(--wxex-brand);
|
|
||||||
color: #ffffff;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.conversation-list {
|
.conversation-list {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
@@ -320,15 +287,6 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.conversation-item-meta {
|
|
||||||
overflow: hidden;
|
|
||||||
color: var(--wxex-text-muted);
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 16px;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conversation-sidebar-account {
|
.conversation-sidebar-account {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
@@ -345,153 +303,6 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
background-color: var(--sidebar-bg);
|
|
||||||
border-right: 1px solid var(--border-color);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
min-height: 0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
/* Prevent shrinking */
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-header {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
padding: 10px;
|
|
||||||
border-bottom: 1px solid var(--border-color);
|
|
||||||
-webkit-app-region: drag;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-footer {
|
|
||||||
padding: 10px;
|
|
||||||
border-top: 1px solid var(--border-color);
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-btn {
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 5px;
|
|
||||||
color: #666;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-status {
|
|
||||||
color: #07c160;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-input {
|
|
||||||
width: 100%;
|
|
||||||
padding: 5px;
|
|
||||||
border-radius: 4px;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
-webkit-app-region: no-drag;
|
|
||||||
}
|
|
||||||
|
|
||||||
.date-range-selector {
|
|
||||||
display: flex;
|
|
||||||
gap: 5px;
|
|
||||||
margin-top: 8px;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.range-btn {
|
|
||||||
padding: 2px 6px;
|
|
||||||
font-size: 10px;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: 10px;
|
|
||||||
background: #fff;
|
|
||||||
cursor: pointer;
|
|
||||||
color: #666;
|
|
||||||
flex: 1;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
background: #07c160;
|
|
||||||
color: #fff;
|
|
||||||
border-color: #07c160;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-list {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-header {
|
|
||||||
padding: 8px 10px;
|
|
||||||
background-color: #f0f0f0;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #666;
|
|
||||||
font-weight: bold;
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
user-select: none;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: #e0e0e0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arrow {
|
|
||||||
margin-right: 5px;
|
|
||||||
font-size: 10px;
|
|
||||||
width: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-empty {
|
|
||||||
padding: 10px 14px 12px 27px;
|
|
||||||
color: #888;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-item {
|
|
||||||
padding: 10px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--sidebar-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
background-color: var(--sidebar-active);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-avatar {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
border-radius: 4px;
|
|
||||||
background-color: #ccc;
|
|
||||||
margin-right: 10px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #fff;
|
|
||||||
overflow: hidden;
|
|
||||||
flex-shrink: 0;
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-avatar {
|
.message-avatar {
|
||||||
img {
|
img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -501,18 +312,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.contact-info {
|
|
||||||
flex: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-name {
|
|
||||||
font-weight: 500;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.resizer {
|
.resizer {
|
||||||
width: 4px;
|
width: 4px;
|
||||||
cursor: col-resize;
|
cursor: col-resize;
|
||||||
|
|||||||
-34
@@ -361,40 +361,6 @@ body {
|
|||||||
background: var(--wxex-bg-main);
|
background: var(--wxex-bg-main);
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-page-placeholder {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 24px;
|
|
||||||
color: var(--wxex-text-secondary);
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin: 0 0 8px;
|
|
||||||
color: var(--wxex-text-primary);
|
|
||||||
font-size: 20px;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 28px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 13px;
|
|
||||||
line-height: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.app-page-placeholder-eyebrow {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
color: var(--wxex-brand);
|
|
||||||
font-size: 11px;
|
|
||||||
font-weight: 700;
|
|
||||||
letter-spacing: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.app-container {
|
.app-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -226,7 +226,7 @@
|
|||||||
padding: 8px 10px;
|
padding: 8px 10px;
|
||||||
border: 1px solid rgba(200, 90, 90, 0.35);
|
border: 1px solid rgba(200, 90, 90, 0.35);
|
||||||
border-radius: var(--wxex-radius-md);
|
border-radius: var(--wxex-radius-md);
|
||||||
background: #fff4f4;
|
background: color-mix(in srgb, var(--wxex-danger) 10%, var(--wxex-bg-elevated));
|
||||||
color: var(--wxex-danger);
|
color: var(--wxex-danger);
|
||||||
font: 12px/17px var(--wxex-font);
|
font: 12px/17px var(--wxex-font);
|
||||||
}
|
}
|
||||||
@@ -248,7 +248,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.report-empty-state,
|
.report-empty-state,
|
||||||
.report-config-section,
|
|
||||||
.report-privacy-note,
|
.report-privacy-note,
|
||||||
.report-result-panel {
|
.report-result-panel {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
@@ -258,6 +257,11 @@
|
|||||||
background: var(--wxex-bg-elevated);
|
background: var(--wxex-bg-elevated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.report-config-section {
|
||||||
|
margin-bottom: 22px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.report-empty-state h2,
|
.report-empty-state h2,
|
||||||
.report-privacy-note h3,
|
.report-privacy-note h3,
|
||||||
.report-config-section h3,
|
.report-config-section h3,
|
||||||
@@ -317,7 +321,11 @@
|
|||||||
.report-density-options {
|
.report-density-options {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
gap: 8px;
|
gap: 2px;
|
||||||
|
padding: 3px;
|
||||||
|
border: 1px solid var(--wxex-border);
|
||||||
|
border-radius: var(--wxex-radius-md);
|
||||||
|
background: var(--wxex-bg-sidebar);
|
||||||
}
|
}
|
||||||
|
|
||||||
.report-density-options {
|
.report-density-options {
|
||||||
@@ -334,7 +342,11 @@
|
|||||||
.report-type-grid {
|
.report-type-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
gap: 8px;
|
gap: 1px;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--wxex-border);
|
||||||
|
border-radius: var(--wxex-radius-md);
|
||||||
|
background: var(--wxex-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.report-check-row {
|
.report-check-row {
|
||||||
@@ -342,11 +354,17 @@
|
|||||||
grid-template-columns: auto minmax(0, 1fr) auto;
|
grid-template-columns: auto minmax(0, 1fr) auto;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding: 10px;
|
min-width: 0;
|
||||||
border: 1px solid var(--wxex-border);
|
padding: 11px 12px;
|
||||||
border-radius: var(--wxex-radius-md);
|
border: 0;
|
||||||
background: #fbfcfb;
|
border-radius: 0;
|
||||||
|
background: var(--wxex-bg-elevated);
|
||||||
color: var(--wxex-text-primary);
|
color: var(--wxex-text-primary);
|
||||||
|
transition: background-color var(--tm-motion-fast) var(--tm-ease-standard);
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-check-row:hover {
|
||||||
|
background: var(--wxex-bg-sidebar);
|
||||||
}
|
}
|
||||||
|
|
||||||
.report-check-row span {
|
.report-check-row span {
|
||||||
@@ -372,7 +390,11 @@
|
|||||||
.report-readonly-modules {
|
.report-readonly-modules {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
gap: 8px;
|
gap: 1px;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--wxex-border);
|
||||||
|
border-radius: var(--wxex-radius-md);
|
||||||
|
background: var(--wxex-border);
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,10 +403,10 @@
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding: 8px 10px;
|
padding: 9px 10px;
|
||||||
border: 1px solid #e9eeeb;
|
border: 0;
|
||||||
border-radius: var(--wxex-radius-md);
|
border-radius: 0;
|
||||||
background: #f7f9f8;
|
background: var(--wxex-bg-elevated);
|
||||||
color: var(--wxex-text-secondary);
|
color: var(--wxex-text-secondary);
|
||||||
font: 12px/17px var(--wxex-font);
|
font: 12px/17px var(--wxex-font);
|
||||||
cursor: default;
|
cursor: default;
|
||||||
@@ -477,11 +499,11 @@
|
|||||||
.ai-report-footer {
|
.ai-report-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
min-height: 66px;
|
min-height: 64px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
padding: 12px 28px;
|
padding: 10px 28px;
|
||||||
border-top: 1px solid var(--wxex-border);
|
border-top: 1px solid var(--wxex-border);
|
||||||
background: var(--wxex-bg-main);
|
background: var(--wxex-bg-main);
|
||||||
}
|
}
|
||||||
@@ -494,7 +516,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.report-footer-note {
|
.report-footer-note {
|
||||||
|
flex: 1 1 auto;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
color: var(--wxex-text-muted);
|
||||||
|
font-size: 11px;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
@@ -504,12 +529,14 @@
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 12px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.report-footer-actions span {
|
.report-footer-actions span {
|
||||||
max-width: 280px;
|
max-width: 240px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
color: var(--wxex-text-muted);
|
||||||
|
font-size: 11px;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
@@ -522,7 +549,7 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-left: 1px solid var(--wxex-border);
|
border-left: 1px solid var(--wxex-border);
|
||||||
background: #f7f9f8;
|
background: var(--wxex-bg-sidebar);
|
||||||
}
|
}
|
||||||
|
|
||||||
.report-task-header {
|
.report-task-header {
|
||||||
@@ -657,7 +684,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.report-image-insight-list article.failed {
|
.report-image-insight-list article.failed {
|
||||||
background: #fff7f3;
|
background: color-mix(in srgb, var(--wxex-danger) 8%, var(--wxex-bg-main));
|
||||||
}
|
}
|
||||||
|
|
||||||
.report-image-insight-list article > div {
|
.report-image-insight-list article > div {
|
||||||
@@ -687,7 +714,7 @@
|
|||||||
|
|
||||||
.report-image-decision {
|
.report-image-decision {
|
||||||
border-color: rgba(197, 137, 48, 0.4);
|
border-color: rgba(197, 137, 48, 0.4);
|
||||||
background: #fffaf0;
|
background: color-mix(in srgb, var(--wxex-warning) 10%, var(--wxex-bg-main));
|
||||||
}
|
}
|
||||||
|
|
||||||
.report-image-decision p {
|
.report-image-decision p {
|
||||||
@@ -796,7 +823,7 @@
|
|||||||
|
|
||||||
.report-task-error {
|
.report-task-error {
|
||||||
border: 1px solid rgba(200, 90, 90, 0.35);
|
border: 1px solid rgba(200, 90, 90, 0.35);
|
||||||
background: #fff4f4;
|
background: color-mix(in srgb, var(--wxex-danger) 10%, var(--wxex-bg-sidebar));
|
||||||
color: var(--wxex-danger);
|
color: var(--wxex-danger);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -846,16 +873,17 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: 34px 40px 48px;
|
padding: 26px 32px 36px;
|
||||||
background: #fafbfa;
|
background: var(--wxex-bg-main);
|
||||||
|
color: var(--wxex-text-primary);
|
||||||
}
|
}
|
||||||
.agent-hub-header {
|
.agent-hub-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 24px;
|
gap: 20px;
|
||||||
max-width: 1080px;
|
max-width: 1080px;
|
||||||
margin: 0 auto 28px;
|
margin: 0 auto 20px;
|
||||||
}
|
}
|
||||||
.agent-hub-eyebrow,
|
.agent-hub-eyebrow,
|
||||||
.agent-hub-card-kicker {
|
.agent-hub-card-kicker {
|
||||||
@@ -867,7 +895,7 @@
|
|||||||
.agent-hub-header h1 {
|
.agent-hub-header h1 {
|
||||||
margin: 4px 0 6px;
|
margin: 4px 0 6px;
|
||||||
color: var(--wxex-text-primary);
|
color: var(--wxex-text-primary);
|
||||||
font: 750 28px/36px var(--wxex-font);
|
font: 750 24px/32px var(--wxex-font);
|
||||||
}
|
}
|
||||||
.agent-hub-header p,
|
.agent-hub-header p,
|
||||||
.agent-hub-card p {
|
.agent-hub-card p {
|
||||||
@@ -880,22 +908,22 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 6px 10px;
|
padding: 6px 10px;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
background: #f0f2f0;
|
background: var(--wxex-bg-sidebar);
|
||||||
color: var(--wxex-text-muted);
|
color: var(--wxex-text-muted);
|
||||||
font: 700 12px/18px var(--wxex-font);
|
font: 700 12px/18px var(--wxex-font);
|
||||||
}
|
}
|
||||||
.agent-hub-runtime.online {
|
.agent-hub-runtime.online {
|
||||||
background: #e8f6ed;
|
background: color-mix(in srgb, var(--wxex-success) 12%, var(--wxex-bg-elevated));
|
||||||
color: #24864b;
|
color: var(--wxex-success);
|
||||||
}
|
}
|
||||||
.agent-hub-runtime.error {
|
.agent-hub-runtime.error {
|
||||||
background: #fff0ef;
|
background: color-mix(in srgb, var(--wxex-danger) 10%, var(--wxex-bg-elevated));
|
||||||
color: var(--wxex-danger);
|
color: var(--wxex-danger);
|
||||||
}
|
}
|
||||||
.agent-hub-grid {
|
.agent-hub-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(0, 1.55fr) minmax(280px, 0.75fr);
|
grid-template-columns: minmax(0, 1.55fr) minmax(280px, 0.75fr);
|
||||||
gap: 20px;
|
gap: 16px;
|
||||||
max-width: 1080px;
|
max-width: 1080px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
@@ -903,18 +931,17 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
border: 1px solid var(--wxex-border);
|
border: 1px solid var(--wxex-border);
|
||||||
border-radius: 18px;
|
border-radius: var(--wxex-radius-lg);
|
||||||
background: var(--wxex-bg-elevated);
|
background: var(--wxex-bg-elevated);
|
||||||
box-shadow: 0 8px 28px rgba(28, 38, 31, 0.045);
|
|
||||||
}
|
}
|
||||||
.agent-hub-login-card {
|
.agent-hub-login-card {
|
||||||
min-height: 520px;
|
min-height: 420px;
|
||||||
padding: 26px;
|
padding: 22px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
.agent-hub-capability-card {
|
.agent-hub-capability-card {
|
||||||
padding: 26px;
|
padding: 22px;
|
||||||
align-self: start;
|
align-self: start;
|
||||||
}
|
}
|
||||||
.agent-hub-card-heading {
|
.agent-hub-card-heading {
|
||||||
@@ -922,7 +949,7 @@
|
|||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
padding-bottom: 20px;
|
padding-bottom: 16px;
|
||||||
border-bottom: 1px solid var(--wxex-border);
|
border-bottom: 1px solid var(--wxex-border);
|
||||||
}
|
}
|
||||||
.agent-hub-card h2 {
|
.agent-hub-card h2 {
|
||||||
@@ -936,7 +963,7 @@
|
|||||||
gap: 7px;
|
gap: 7px;
|
||||||
padding: 5px 9px;
|
padding: 5px 9px;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
background: #f2f3f2;
|
background: var(--wxex-bg-sidebar);
|
||||||
color: var(--wxex-text-secondary);
|
color: var(--wxex-text-secondary);
|
||||||
font: 650 12px/18px var(--wxex-font);
|
font: 650 12px/18px var(--wxex-font);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@@ -945,28 +972,28 @@
|
|||||||
width: 7px;
|
width: 7px;
|
||||||
height: 7px;
|
height: 7px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: #9aa39d;
|
background: var(--wxex-text-muted);
|
||||||
}
|
}
|
||||||
.agent-hub-status.online {
|
.agent-hub-status.online {
|
||||||
background: #e8f6ed;
|
background: color-mix(in srgb, var(--wxex-success) 12%, var(--wxex-bg-elevated));
|
||||||
color: #24864b;
|
color: var(--wxex-success);
|
||||||
}
|
}
|
||||||
.agent-hub-status.online i {
|
.agent-hub-status.online i {
|
||||||
background: #35a663;
|
background: var(--wxex-success);
|
||||||
}
|
}
|
||||||
.agent-hub-status.waiting_scan,
|
.agent-hub-status.waiting_scan,
|
||||||
.agent-hub-status.scanned,
|
.agent-hub-status.scanned,
|
||||||
.agent-hub-status.starting {
|
.agent-hub-status.starting {
|
||||||
background: #fff5de;
|
background: color-mix(in srgb, var(--wxex-warning) 12%, var(--wxex-bg-elevated));
|
||||||
color: #9b6a12;
|
color: var(--wxex-warning);
|
||||||
}
|
}
|
||||||
.agent-hub-status.waiting_scan i,
|
.agent-hub-status.waiting_scan i,
|
||||||
.agent-hub-status.scanned i,
|
.agent-hub-status.scanned i,
|
||||||
.agent-hub-status.starting i {
|
.agent-hub-status.starting i {
|
||||||
background: #d89b2b;
|
background: var(--wxex-warning);
|
||||||
}
|
}
|
||||||
.agent-hub-status.error {
|
.agent-hub-status.error {
|
||||||
background: #fff0ef;
|
background: color-mix(in srgb, var(--wxex-danger) 10%, var(--wxex-bg-elevated));
|
||||||
color: var(--wxex-danger);
|
color: var(--wxex-danger);
|
||||||
}
|
}
|
||||||
.agent-hub-status.error i {
|
.agent-hub-status.error i {
|
||||||
@@ -978,13 +1005,13 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
min-height: 280px;
|
min-height: 210px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.agent-hub-empty-login h3,
|
.agent-hub-empty-login h3,
|
||||||
.agent-hub-connected h3,
|
.agent-hub-connected h3,
|
||||||
.agent-hub-qr-copy h3 {
|
.agent-hub-qr-copy h3 {
|
||||||
margin: 18px 0 6px;
|
margin: 14px 0 5px;
|
||||||
color: var(--wxex-text-primary);
|
color: var(--wxex-text-primary);
|
||||||
font: 700 16px/24px var(--wxex-font);
|
font: 700 16px/24px var(--wxex-font);
|
||||||
}
|
}
|
||||||
@@ -992,26 +1019,26 @@
|
|||||||
max-width: 360px;
|
max-width: 360px;
|
||||||
}
|
}
|
||||||
.agent-hub-phone {
|
.agent-hub-phone {
|
||||||
width: 64px;
|
width: 56px;
|
||||||
height: 88px;
|
height: 76px;
|
||||||
position: relative;
|
position: relative;
|
||||||
border: 2px solid #9eb3a5;
|
border: 2px solid color-mix(in srgb, var(--wxex-brand) 45%, var(--wxex-border));
|
||||||
border-radius: 13px;
|
border-radius: 11px;
|
||||||
background: linear-gradient(145deg, #f6fbf7, #eaf4ed);
|
background: var(--wxex-brand-soft);
|
||||||
}
|
}
|
||||||
.agent-hub-phone::before {
|
.agent-hub-phone::before {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 8px;
|
top: 8px;
|
||||||
left: 22px;
|
left: 19px;
|
||||||
width: 18px;
|
width: 16px;
|
||||||
height: 3px;
|
height: 3px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
background: #b8c8bd;
|
background: color-mix(in srgb, var(--wxex-brand) 30%, var(--wxex-bg-elevated));
|
||||||
}
|
}
|
||||||
.agent-hub-phone span {
|
.agent-hub-phone span {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 23px;
|
left: 19px;
|
||||||
bottom: 8px;
|
bottom: 8px;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
@@ -1023,7 +1050,7 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
padding-top: 18px;
|
padding-top: 14px;
|
||||||
}
|
}
|
||||||
.agent-hub-qr-panel {
|
.agent-hub-qr-panel {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@@ -1076,17 +1103,17 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: #e4f5ea;
|
background: color-mix(in srgb, var(--wxex-success) 14%, var(--wxex-bg-elevated));
|
||||||
color: #23834a;
|
color: var(--wxex-success);
|
||||||
font: 800 22px/1 var(--wxex-font);
|
font: 800 22px/1 var(--wxex-font);
|
||||||
}
|
}
|
||||||
.agent-hub-capability-card > p {
|
.agent-hub-capability-card > p {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
.agent-hub-example {
|
.agent-hub-example {
|
||||||
margin: 24px 0 20px;
|
margin: 18px 0 14px;
|
||||||
padding: 16px;
|
padding: 14px;
|
||||||
border-radius: 12px;
|
border-radius: var(--wxex-radius-md);
|
||||||
background: var(--wxex-brand-soft);
|
background: var(--wxex-brand-soft);
|
||||||
}
|
}
|
||||||
.agent-hub-example span {
|
.agent-hub-example span {
|
||||||
@@ -1109,7 +1136,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 9px;
|
gap: 9px;
|
||||||
padding: 9px 0;
|
padding: 7px 0;
|
||||||
border-bottom: 1px solid var(--wxex-border);
|
border-bottom: 1px solid var(--wxex-border);
|
||||||
color: var(--wxex-text-secondary);
|
color: var(--wxex-text-secondary);
|
||||||
font: 13px/19px var(--wxex-font);
|
font: 13px/19px var(--wxex-font);
|
||||||
@@ -1133,8 +1160,8 @@
|
|||||||
}
|
}
|
||||||
.agent-hub-log-card {
|
.agent-hub-log-card {
|
||||||
max-width: 1080px;
|
max-width: 1080px;
|
||||||
margin: 20px auto 0;
|
margin: 16px auto 0;
|
||||||
padding: 22px;
|
padding: 20px 22px;
|
||||||
}
|
}
|
||||||
.agent-hub-log-heading {
|
.agent-hub-log-heading {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -1245,13 +1272,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ai-vision-test h2 {
|
.ai-vision-test h2 {
|
||||||
color: #202724;
|
color: var(--wxex-text-primary);
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-vision-test header h3 {
|
.ai-vision-test header h3 {
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
color: #35403b;
|
color: var(--wxex-text-primary);
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1259,22 +1286,22 @@
|
|||||||
.ai-vision-model,
|
.ai-vision-model,
|
||||||
.ai-vision-upload small {
|
.ai-vision-upload small {
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
color: #66706b;
|
color: var(--wxex-text-secondary);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-vision-capability {
|
.ai-vision-capability {
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
padding: 5px 9px;
|
padding: 5px 9px;
|
||||||
background: #f1f3f2;
|
background: var(--wxex-bg-sidebar);
|
||||||
color: #66706b;
|
color: var(--wxex-text-secondary);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-vision-capability.supported {
|
.ai-vision-capability.supported {
|
||||||
background: #eaf5f1;
|
background: var(--wxex-brand-soft);
|
||||||
color: #2e8b68;
|
color: var(--wxex-brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-vision-model {
|
.ai-vision-model {
|
||||||
@@ -1288,18 +1315,18 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 14px;
|
gap: 14px;
|
||||||
border: 1px dashed #bfc9c4;
|
border: 1px dashed var(--wxex-border);
|
||||||
border-radius: 10px;
|
border-radius: var(--wxex-radius-md);
|
||||||
padding: 14px;
|
padding: 14px;
|
||||||
background: #f7f9f8;
|
background: var(--wxex-bg-sidebar);
|
||||||
color: #35403b;
|
color: var(--wxex-text-primary);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-vision-upload:hover {
|
.ai-vision-upload:hover {
|
||||||
border-color: #247a63;
|
border-color: var(--wxex-brand);
|
||||||
background: #f2f8f5;
|
background: var(--wxex-brand-soft);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-vision-upload input {
|
.ai-vision-upload input {
|
||||||
@@ -1333,26 +1360,26 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ai-vision-privacy {
|
.ai-vision-privacy {
|
||||||
color: #66706b;
|
color: var(--wxex-text-secondary);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-vision-error {
|
.ai-vision-error {
|
||||||
border-left: 3px solid #c85a5a;
|
border-left: 3px solid var(--wxex-danger);
|
||||||
padding: 9px 11px;
|
padding: 9px 11px;
|
||||||
background: #fff2f2;
|
background: color-mix(in srgb, var(--wxex-danger) 12%, transparent);
|
||||||
color: #a84444;
|
color: var(--wxex-danger);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-vision-result {
|
.ai-vision-result {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
border: 1px solid #dce7e2;
|
border: 1px solid var(--wxex-border);
|
||||||
border-radius: 9px;
|
border-radius: var(--wxex-radius-md);
|
||||||
padding: 14px;
|
padding: 14px;
|
||||||
background: #f7faf9;
|
background: var(--wxex-bg-sidebar);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-vision-result dl {
|
.ai-vision-result dl {
|
||||||
@@ -1363,20 +1390,20 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ai-vision-result dt {
|
.ai-vision-result dt {
|
||||||
color: #929a96;
|
color: var(--wxex-text-muted);
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-vision-result dd {
|
.ai-vision-result dd {
|
||||||
margin: 4px 0 0;
|
margin: 4px 0 0;
|
||||||
color: #35403b;
|
color: var(--wxex-text-primary);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-vision-result > p {
|
.ai-vision-result > p {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
color: #3d4742;
|
color: var(--wxex-text-secondary);
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
line-height: 1.7;
|
line-height: 1.7;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -555,7 +555,7 @@
|
|||||||
padding: 12px 14px;
|
padding: 12px 14px;
|
||||||
border: 1.5px solid var(--wxex-border);
|
border: 1.5px solid var(--wxex-border);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
background: #fff;
|
background: var(--wxex-bg-elevated);
|
||||||
transition:
|
transition:
|
||||||
border-color 0.2s,
|
border-color 0.2s,
|
||||||
background 0.2s;
|
background 0.2s;
|
||||||
@@ -563,7 +563,7 @@
|
|||||||
|
|
||||||
.report-template-item.active {
|
.report-template-item.active {
|
||||||
border-color: var(--wxex-primary, #07c160);
|
border-color: var(--wxex-primary, #07c160);
|
||||||
background: #f0fbf3;
|
background: var(--wxex-brand-soft);
|
||||||
}
|
}
|
||||||
|
|
||||||
.report-template-item.disabled {
|
.report-template-item.disabled {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
min-height: var(--ai-search-header-height);
|
min-height: var(--ai-search-header-height);
|
||||||
padding: 14px 22px 12px;
|
padding: 14px 22px 12px;
|
||||||
border-bottom: 1px solid var(--wxex-border);
|
border-bottom: 1px solid var(--wxex-border);
|
||||||
background: rgba(250, 251, 250, 0.94);
|
background: color-mix(in srgb, var(--wxex-bg-main) 94%, transparent);
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -334,50 +334,6 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-search-local-badge {
|
|
||||||
border-radius: var(--wxex-radius-sm);
|
|
||||||
background: var(--wxex-ai-soft);
|
|
||||||
color: var(--wxex-ai);
|
|
||||||
font-size: 10px;
|
|
||||||
font-weight: 700;
|
|
||||||
line-height: 16px;
|
|
||||||
padding: 2px 6px;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-scope-toggle,
|
|
||||||
.ai-search-range-grid {
|
|
||||||
display: grid;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-scope-toggle {
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
margin-bottom: 18px;
|
|
||||||
padding: 3px;
|
|
||||||
border-radius: var(--wxex-radius-sm);
|
|
||||||
background: var(--wxex-bg-elevated);
|
|
||||||
|
|
||||||
button {
|
|
||||||
padding: 7px 4px;
|
|
||||||
font-size: 11px;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
background: var(--wxex-brand);
|
|
||||||
color: #fff;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-scope-help {
|
|
||||||
min-height: 30px;
|
|
||||||
margin: -10px 2px 12px;
|
|
||||||
color: var(--wxex-text-muted);
|
|
||||||
font-size: 10px;
|
|
||||||
line-height: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-field-label {
|
.ai-search-field-label {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0 0 7px;
|
margin: 0 0 7px;
|
||||||
@@ -387,178 +343,6 @@
|
|||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-search-filter-input {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 7px;
|
|
||||||
min-width: 0;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
padding: 7px 9px;
|
|
||||||
border: 1px solid var(--wxex-border);
|
|
||||||
border-radius: var(--wxex-radius-sm);
|
|
||||||
background: var(--wxex-bg-elevated);
|
|
||||||
|
|
||||||
svg {
|
|
||||||
width: 15px;
|
|
||||||
height: 15px;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
color: var(--wxex-text-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
width: 100%;
|
|
||||||
min-width: 0;
|
|
||||||
border: 0;
|
|
||||||
outline: 0;
|
|
||||||
background: transparent;
|
|
||||||
color: var(--wxex-text-primary);
|
|
||||||
font: inherit;
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-contact-list {
|
|
||||||
display: flex;
|
|
||||||
max-height: 168px;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 3px;
|
|
||||||
margin-bottom: 18px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-contact {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
min-width: 0;
|
|
||||||
padding: 7px;
|
|
||||||
border: 0;
|
|
||||||
border-radius: var(--wxex-radius-sm);
|
|
||||||
background: transparent;
|
|
||||||
color: var(--wxex-text-primary);
|
|
||||||
cursor: pointer;
|
|
||||||
font: inherit;
|
|
||||||
text-align: left;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&.active {
|
|
||||||
background: var(--wxex-brand-soft);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-contact-avatar {
|
|
||||||
width: 28px;
|
|
||||||
height: 28px;
|
|
||||||
display: grid;
|
|
||||||
place-items: center;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
overflow: hidden;
|
|
||||||
border-radius: var(--wxex-radius-sm);
|
|
||||||
background: var(--wxex-bg-elevated);
|
|
||||||
color: var(--wxex-brand);
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 700;
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-contact > span:last-child {
|
|
||||||
display: flex;
|
|
||||||
min-width: 0;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-contact strong,
|
|
||||||
.ai-search-contact small {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-contact strong {
|
|
||||||
font-size: 11px;
|
|
||||||
font-weight: 700;
|
|
||||||
line-height: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-contact small {
|
|
||||||
color: var(--wxex-text-muted);
|
|
||||||
font-size: 10px;
|
|
||||||
line-height: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-range-grid {
|
|
||||||
padding: 4px;
|
|
||||||
border: 1px solid var(--wxex-border);
|
|
||||||
border-radius: var(--wxex-radius-md);
|
|
||||||
background: var(--wxex-bg-elevated);
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
|
|
||||||
button {
|
|
||||||
border: 0;
|
|
||||||
border-radius: var(--wxex-radius-sm);
|
|
||||||
background: transparent;
|
|
||||||
color: var(--wxex-text-secondary);
|
|
||||||
cursor: pointer;
|
|
||||||
font: inherit;
|
|
||||||
min-height: 34px;
|
|
||||||
padding: 7px 4px;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
font-size: 11px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-color: var(--wxex-brand);
|
|
||||||
color: var(--wxex-brand);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
border-color: var(--wxex-brand);
|
|
||||||
background: var(--wxex-brand);
|
|
||||||
color: #fff;
|
|
||||||
box-shadow: 0 1px 3px rgba(34, 89, 74, 0.2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-field-heading {
|
|
||||||
display: flex;
|
|
||||||
align-items: baseline;
|
|
||||||
justify-content: space-between;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-field-heading .ai-search-field-label {
|
|
||||||
margin-bottom: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-field-heading > span {
|
|
||||||
color: var(--wxex-brand);
|
|
||||||
font-size: 10px;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-filter-note {
|
|
||||||
display: flex;
|
|
||||||
gap: 6px;
|
|
||||||
padding: 9px;
|
|
||||||
border: 1px solid var(--wxex-border);
|
|
||||||
border-radius: var(--wxex-radius-sm);
|
|
||||||
background: rgba(255, 255, 255, 0.48);
|
|
||||||
color: var(--wxex-text-secondary);
|
|
||||||
font-size: 10px;
|
|
||||||
line-height: 16px;
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: var(--wxex-success);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-main {
|
.ai-search-main {
|
||||||
display: flex;
|
display: flex;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
@@ -640,41 +424,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-search-spinner {
|
|
||||||
width: 42px;
|
|
||||||
height: 42px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
border: 3px solid var(--wxex-brand-soft);
|
|
||||||
border-top-color: var(--wxex-brand);
|
|
||||||
border-radius: 50%;
|
|
||||||
animation: ai-search-spin 0.9s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes ai-search-spin {
|
|
||||||
to {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-loading-steps {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 9px;
|
|
||||||
margin-top: 24px;
|
|
||||||
color: var(--wxex-text-muted);
|
|
||||||
font-size: 11px;
|
|
||||||
text-align: left;
|
|
||||||
|
|
||||||
.done {
|
|
||||||
color: var(--wxex-success);
|
|
||||||
}
|
|
||||||
|
|
||||||
.active {
|
|
||||||
color: var(--wxex-brand);
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-loading {
|
.ai-search-loading {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
@@ -745,7 +494,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.error {
|
&.error {
|
||||||
background: #fff8ef;
|
background: color-mix(in srgb, var(--wxex-warning) 10%, var(--wxex-bg-elevated));
|
||||||
|
|
||||||
strong,
|
strong,
|
||||||
p {
|
p {
|
||||||
@@ -782,7 +531,7 @@
|
|||||||
|
|
||||||
.ai-search-pipeline-step.error .ai-search-pipeline-mark {
|
.ai-search-pipeline-step.error .ai-search-pipeline-mark {
|
||||||
border-color: var(--wxex-warning);
|
border-color: var(--wxex-warning);
|
||||||
background: #fff1df;
|
background: color-mix(in srgb, var(--wxex-warning) 12%, var(--wxex-bg-elevated));
|
||||||
color: var(--wxex-warning);
|
color: var(--wxex-warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1062,55 +811,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-search-knowledge-status {
|
|
||||||
display: grid;
|
|
||||||
gap: 4px;
|
|
||||||
margin: 0 0 16px;
|
|
||||||
padding: 10px;
|
|
||||||
border: 1px solid var(--wxex-border);
|
|
||||||
border-radius: var(--wxex-radius-md);
|
|
||||||
background: var(--wxex-bg-elevated);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-knowledge-status > div {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-knowledge-status > div span,
|
|
||||||
.ai-search-knowledge-status p,
|
|
||||||
.ai-search-knowledge-status small {
|
|
||||||
margin: 0;
|
|
||||||
color: var(--wxex-text-muted);
|
|
||||||
font-size: 10px;
|
|
||||||
line-height: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-knowledge-status > div span {
|
|
||||||
font-weight: 700;
|
|
||||||
letter-spacing: 0.04em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-knowledge-status strong {
|
|
||||||
color: var(--wxex-text-primary);
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-knowledge-status.building,
|
|
||||||
.ai-search-knowledge-status.syncing {
|
|
||||||
border-color: var(--wxex-ai);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-knowledge-status.ready strong {
|
|
||||||
color: var(--wxex-success);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-knowledge-status.error {
|
|
||||||
border-color: var(--wxex-warning);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-insufficient-icon {
|
.ai-search-insufficient-icon {
|
||||||
width: 44px;
|
width: 44px;
|
||||||
height: 44px;
|
height: 44px;
|
||||||
@@ -1141,7 +841,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
.ai-search-spinner,
|
|
||||||
.ai-search-result,
|
.ai-search-result,
|
||||||
.ai-search-summary-block,
|
.ai-search-summary-block,
|
||||||
.ai-search-answer > *,
|
.ai-search-answer > *,
|
||||||
@@ -1158,12 +857,6 @@
|
|||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
.ai-search-muted {
|
|
||||||
color: var(--wxex-text-muted);
|
|
||||||
font-size: 10px;
|
|
||||||
line-height: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1120px) {
|
@media (max-width: 1120px) {
|
||||||
.ai-search-workspace {
|
.ai-search-workspace {
|
||||||
--ai-search-sidebar-width: 210px;
|
--ai-search-sidebar-width: 210px;
|
||||||
@@ -1190,10 +883,6 @@
|
|||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-search-contact-list {
|
|
||||||
max-height: 148px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-empty,
|
.ai-search-empty,
|
||||||
.ai-search-loading,
|
.ai-search-loading,
|
||||||
.ai-search-insufficient {
|
.ai-search-insufficient {
|
||||||
@@ -1217,7 +906,7 @@
|
|||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
padding: 10px 22px 12px;
|
padding: 10px 22px 12px;
|
||||||
border-bottom: 1px solid var(--wxex-border);
|
border-bottom: 1px solid var(--wxex-border);
|
||||||
background: #f7faf8;
|
background: var(--wxex-bg-sidebar);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-search-debug-header {
|
.ai-search-debug-header {
|
||||||
@@ -1263,7 +952,7 @@
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
border: 1px solid var(--wxex-border);
|
border: 1px solid var(--wxex-border);
|
||||||
border-radius: var(--wxex-radius-sm);
|
border-radius: var(--wxex-radius-sm);
|
||||||
background: #fff;
|
background: var(--wxex-bg-elevated);
|
||||||
color: var(--wxex-text-secondary);
|
color: var(--wxex-text-secondary);
|
||||||
font:
|
font:
|
||||||
10px/16px ui-monospace,
|
10px/16px ui-monospace,
|
||||||
@@ -1274,127 +963,6 @@
|
|||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-search-task-button {
|
|
||||||
padding: 7px 10px;
|
|
||||||
border: 1px solid var(--wxex-border);
|
|
||||||
border-radius: var(--wxex-radius-sm);
|
|
||||||
background: var(--wxex-bg-elevated);
|
|
||||||
color: var(--wxex-text-secondary);
|
|
||||||
cursor: pointer;
|
|
||||||
font: inherit;
|
|
||||||
font-size: 11px;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-task-button.active,
|
|
||||||
.ai-search-task-button:hover {
|
|
||||||
border-color: var(--wxex-brand);
|
|
||||||
color: var(--wxex-brand);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-task-center {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
max-height: 218px;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 10px 22px 8px;
|
|
||||||
border-bottom: 1px solid var(--wxex-border);
|
|
||||||
background: var(--wxex-bg-elevated);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-task-center-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
justify-content: space-between;
|
|
||||||
gap: 16px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
border-bottom: 1px solid var(--wxex-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-task-center-header div {
|
|
||||||
display: grid;
|
|
||||||
gap: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-task-center-header strong {
|
|
||||||
color: var(--wxex-text-primary);
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-task-center-header span,
|
|
||||||
.ai-search-task-center-header > span {
|
|
||||||
color: var(--wxex-text-muted);
|
|
||||||
font-size: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-task-row {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 8px minmax(0, 1fr) auto;
|
|
||||||
align-items: center;
|
|
||||||
gap: 9px;
|
|
||||||
padding: 10px 0;
|
|
||||||
border-bottom: 1px solid var(--wxex-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-task-row:last-child {
|
|
||||||
border-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-task-status {
|
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: var(--wxex-text-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-task-status.running {
|
|
||||||
background: var(--wxex-brand);
|
|
||||||
box-shadow: 0 0 0 3px var(--wxex-brand-soft);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-task-status.completed {
|
|
||||||
background: var(--wxex-success);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-task-status.failed {
|
|
||||||
background: var(--wxex-warning);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-task-row > div {
|
|
||||||
display: grid;
|
|
||||||
min-width: 0;
|
|
||||||
gap: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-task-row strong,
|
|
||||||
.ai-search-task-row small {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-task-row strong {
|
|
||||||
color: var(--wxex-text-primary);
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-task-row small {
|
|
||||||
color: var(--wxex-text-muted);
|
|
||||||
font-size: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-task-result {
|
|
||||||
color: var(--wxex-text-secondary);
|
|
||||||
font-size: 10px;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-task-empty {
|
|
||||||
margin: 12px 0 2px;
|
|
||||||
color: var(--wxex-text-muted);
|
|
||||||
font-size: 11px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-search-markdown-spacer {
|
.ai-search-markdown-spacer {
|
||||||
height: 8px;
|
height: 8px;
|
||||||
}
|
}
|
||||||
@@ -1442,8 +1010,4 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-search-task-row {
|
|
||||||
grid-template-columns: 8px minmax(0, 1fr) auto;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +1,3 @@
|
|||||||
.settings-primary-button,
|
|
||||||
.settings-danger-button {
|
|
||||||
border: 1px solid var(--wxex-border);
|
|
||||||
border-radius: var(--wxex-radius-sm);
|
|
||||||
background: var(--wxex-bg-elevated);
|
|
||||||
color: var(--wxex-text-primary);
|
|
||||||
cursor: pointer;
|
|
||||||
font: 12px/18px var(--wxex-font);
|
|
||||||
padding: 8px 12px;
|
|
||||||
|
|
||||||
&:hover:not(:disabled) {
|
|
||||||
border-color: var(--wxex-brand);
|
|
||||||
color: var(--wxex-brand);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:disabled {
|
|
||||||
cursor: not-allowed;
|
|
||||||
opacity: 0.55;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings-primary-button {
|
|
||||||
border-color: var(--wxex-brand);
|
|
||||||
background: var(--wxex-brand);
|
|
||||||
color: #fff;
|
|
||||||
font-weight: 600;
|
|
||||||
|
|
||||||
&:hover:not(:disabled) {
|
|
||||||
background: var(--wxex-brand-hover);
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings-danger-button {
|
|
||||||
color: var(--wxex-danger);
|
|
||||||
|
|
||||||
&:hover:not(:disabled) {
|
|
||||||
border-color: var(--wxex-danger);
|
|
||||||
color: var(--wxex-danger);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings-card-kicker {
|
.settings-card-kicker {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
@@ -306,7 +264,7 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: var(--wxex-surface-muted, #f7f9f8);
|
background: var(--wxex-bg-sidebar);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
@@ -322,7 +280,7 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1px solid var(--wxex-border);
|
border: 1px solid var(--wxex-border);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: var(--wxex-surface-muted, #f7f9f8);
|
background: var(--wxex-bg-sidebar);
|
||||||
color: var(--wxex-text-secondary);
|
color: var(--wxex-text-secondary);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
@@ -383,7 +341,7 @@
|
|||||||
align-content: start;
|
align-content: start;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
padding: 14px;
|
padding: 14px;
|
||||||
background: var(--wxex-surface-muted, #f7f9f8);
|
background: var(--wxex-bg-sidebar);
|
||||||
}
|
}
|
||||||
|
|
||||||
.voice-batch-field {
|
.voice-batch-field {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: #fafbfa;
|
background: var(--wxex-bg-main);
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-page-panel {
|
.settings-page-panel {
|
||||||
@@ -244,9 +244,9 @@
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
.settings-card {
|
.settings-card {
|
||||||
border: 1px solid #dde3e0;
|
border: 1px solid var(--wxex-border);
|
||||||
border-radius: 10px;
|
border-radius: var(--wxex-radius-md);
|
||||||
background: #fff;
|
background: var(--wxex-bg-elevated);
|
||||||
padding: 24px 26px;
|
padding: 24px 26px;
|
||||||
}
|
}
|
||||||
.settings-account-overview {
|
.settings-account-overview {
|
||||||
@@ -505,34 +505,6 @@
|
|||||||
.database-key-muted {
|
.database-key-muted {
|
||||||
color: #66706b !important;
|
color: #66706b !important;
|
||||||
}
|
}
|
||||||
.database-key-primary,
|
|
||||||
.database-key-secondary {
|
|
||||||
min-height: 36px;
|
|
||||||
padding: 0 15px;
|
|
||||||
border: 1px solid #247a63;
|
|
||||||
border-radius: 8px;
|
|
||||||
cursor: pointer;
|
|
||||||
font: 600 13px/1 inherit;
|
|
||||||
}
|
|
||||||
.database-key-primary {
|
|
||||||
background: #247a63;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
.database-key-secondary {
|
|
||||||
background: #fff;
|
|
||||||
color: #247a63;
|
|
||||||
}
|
|
||||||
.database-key-primary:hover:not(:disabled) {
|
|
||||||
background: #1d6754;
|
|
||||||
}
|
|
||||||
.database-key-secondary:hover:not(:disabled) {
|
|
||||||
background: #f0f7f4;
|
|
||||||
}
|
|
||||||
.database-key-primary:disabled,
|
|
||||||
.database-key-secondary:disabled {
|
|
||||||
cursor: not-allowed;
|
|
||||||
opacity: 0.45;
|
|
||||||
}
|
|
||||||
.database-key-editor label {
|
.database-key-editor label {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 9px;
|
margin-bottom: 9px;
|
||||||
@@ -841,52 +813,6 @@
|
|||||||
color: #786868;
|
color: #786868;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
.database-key-confirm-backdrop {
|
|
||||||
position: fixed;
|
|
||||||
z-index: 30;
|
|
||||||
inset: 0;
|
|
||||||
display: grid;
|
|
||||||
place-items: center;
|
|
||||||
padding: 24px;
|
|
||||||
background: rgba(25, 32, 29, 0.34);
|
|
||||||
}
|
|
||||||
.database-key-confirm {
|
|
||||||
width: min(100%, 430px);
|
|
||||||
padding: 22px;
|
|
||||||
border-radius: 12px;
|
|
||||||
background: #fff;
|
|
||||||
box-shadow: 0 18px 50px rgba(24, 35, 30, 0.2);
|
|
||||||
}
|
|
||||||
.database-key-confirm h2 {
|
|
||||||
margin: 0;
|
|
||||||
color: #202724;
|
|
||||||
font-size: 17px;
|
|
||||||
}
|
|
||||||
.database-key-confirm p {
|
|
||||||
margin: 12px 0 22px;
|
|
||||||
color: #66706b;
|
|
||||||
font-size: 13px;
|
|
||||||
line-height: 1.7;
|
|
||||||
}
|
|
||||||
.database-key-confirm > div {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
.database-key-confirm button {
|
|
||||||
min-height: 34px;
|
|
||||||
border: 1px solid #dde3e0;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 0 14px;
|
|
||||||
background: #fff;
|
|
||||||
color: #46514c;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.database-key-confirm button.danger {
|
|
||||||
border-color: #c85a5a;
|
|
||||||
background: #c85a5a;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
/* SETTINGS-03: image decryption */
|
/* SETTINGS-03: image decryption */
|
||||||
.image-decryption-content {
|
.image-decryption-content {
|
||||||
padding-bottom: 48px;
|
padding-bottom: 48px;
|
||||||
@@ -1102,29 +1028,6 @@
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
.image-test-result {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 8px 18px;
|
|
||||||
margin-top: 14px;
|
|
||||||
padding: 12px 14px;
|
|
||||||
border-radius: 8px;
|
|
||||||
color: #2e765d;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
.image-test-result.success {
|
|
||||||
border: 1px solid #bfded3;
|
|
||||||
background: #eaf5f1;
|
|
||||||
}
|
|
||||||
.image-test-result.error {
|
|
||||||
border: 1px solid #efcaca;
|
|
||||||
background: #fff2f2;
|
|
||||||
color: #a84444;
|
|
||||||
}
|
|
||||||
.image-test-result p {
|
|
||||||
width: 100%;
|
|
||||||
margin: 2px 0 0;
|
|
||||||
}
|
|
||||||
.image-step-list {
|
.image-step-list {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
margin: 14px 0 0;
|
margin: 14px 0 0;
|
||||||
|
|||||||
@@ -1,71 +1,3 @@
|
|||||||
/* Sidebar 自助卡片 + 入口 */
|
|
||||||
.sidebar-footer {
|
|
||||||
padding: 10px 12px;
|
|
||||||
border-top: 1px solid var(--border-color);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: #f3f4f5;
|
|
||||||
transition: background-color 0.15s ease;
|
|
||||||
user-select: none;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: #e6e9eb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-self-avatar {
|
|
||||||
width: 36px;
|
|
||||||
height: 36px;
|
|
||||||
border-radius: 6px;
|
|
||||||
background-color: #07c160;
|
|
||||||
color: #fff;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
overflow: hidden;
|
|
||||||
flex-shrink: 0;
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-self-info {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-self-nickname {
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #1f2429;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-self-wxid {
|
|
||||||
font-size: 11px;
|
|
||||||
color: #8a9298;
|
|
||||||
margin-top: 2px;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-self-arrow {
|
|
||||||
color: #8a9298;
|
|
||||||
font-size: 18px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 启动自动连接 Splash */
|
/* 启动自动连接 Splash */
|
||||||
.boot-splash {
|
.boot-splash {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|||||||
@@ -4,26 +4,34 @@
|
|||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
:root {
|
:root {
|
||||||
--tm-background: 150 18% 96%;
|
--tm-background: 150 10% 96.0784%;
|
||||||
--tm-foreground: 150 12% 15%;
|
--tm-canvas: 120 11.1111% 98.2353%;
|
||||||
|
--tm-foreground: 154.2857 9.8592% 13.9216%;
|
||||||
--tm-surface: 0 0% 100%;
|
--tm-surface: 0 0% 100%;
|
||||||
--tm-surface-muted: 150 14% 94%;
|
--tm-surface-muted: 150 13.3333% 94.1176%;
|
||||||
--tm-surface-elevated: 0 0% 100%;
|
--tm-surface-elevated: 0 0% 100%;
|
||||||
--tm-border: 150 13% 87%;
|
--tm-border: 150 9.6774% 87.8431%;
|
||||||
--tm-border-subtle: 150 10% 92%;
|
--tm-border-subtle: 150 10% 92%;
|
||||||
--tm-primary: 161 54% 31%;
|
--tm-primary: 163.9535 54.4304% 30.9804%;
|
||||||
|
--tm-primary-hover: 164.5946 56.0606% 25.8824%;
|
||||||
--tm-primary-foreground: 0 0% 100%;
|
--tm-primary-foreground: 0 0% 100%;
|
||||||
--tm-secondary: 150 13% 91%;
|
--tm-secondary: 150 13.3333% 94.1176%;
|
||||||
--tm-secondary-foreground: 150 12% 20%;
|
--tm-secondary-foreground: 154.2857 9.8592% 13.9216%;
|
||||||
--tm-muted: 150 11% 92%;
|
--tm-muted: 150 10% 92%;
|
||||||
--tm-muted-foreground: 150 8% 44%;
|
--tm-muted-foreground: 150 4.6729% 41.9608%;
|
||||||
--tm-accent: 157 39% 89%;
|
--tm-subtle-foreground: 150 3.8095% 58.8235%;
|
||||||
--tm-accent-foreground: 161 54% 25%;
|
--tm-accent: 157.5 30.7692% 89.8039%;
|
||||||
--tm-success: 155 51% 37%;
|
--tm-accent-foreground: 163.9535 54.4304% 30.9804%;
|
||||||
--tm-warning: 34 57% 49%;
|
--tm-ai: 236.8966 62.3656% 63.5294%;
|
||||||
--tm-destructive: 0 51% 54%;
|
--tm-ai-soft: 236 78.9474% 96.2745%;
|
||||||
|
--tm-success: 157.4194 50.2703% 36.2745%;
|
||||||
|
--tm-warning: 33.5172 57.7689% 49.2157%;
|
||||||
|
--tm-destructive: 0 50% 56.8627%;
|
||||||
--tm-destructive-foreground: 0 0% 100%;
|
--tm-destructive-foreground: 0 0% 100%;
|
||||||
--tm-focus-ring: 161 54% 38%;
|
--tm-focus-ring: 164 54.4% 31%;
|
||||||
|
--tm-disabled-surface: 150 13.3333% 94.1176%;
|
||||||
|
--tm-disabled-foreground: 150 3.8095% 58.8235%;
|
||||||
|
--tm-disabled-border: 150 10% 92%;
|
||||||
--tm-radius-sm: 0.375rem;
|
--tm-radius-sm: 0.375rem;
|
||||||
--tm-radius-md: 0.5rem;
|
--tm-radius-md: 0.5rem;
|
||||||
--tm-radius-lg: 0.75rem;
|
--tm-radius-lg: 0.75rem;
|
||||||
@@ -37,6 +45,9 @@
|
|||||||
--tm-motion-slow: 260ms;
|
--tm-motion-slow: 260ms;
|
||||||
--tm-ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
--tm-ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||||
--tm-ease-emphasized: cubic-bezier(0.16, 1, 0.3, 1);
|
--tm-ease-emphasized: cubic-bezier(0.16, 1, 0.3, 1);
|
||||||
|
--tm-control-height-compact: 1.75rem;
|
||||||
|
--tm-control-height-standard: 2rem;
|
||||||
|
--tm-control-height-form: 2.25rem;
|
||||||
--tm-z-base: 0;
|
--tm-z-base: 0;
|
||||||
--tm-z-dropdown: 40;
|
--tm-z-dropdown: 40;
|
||||||
--tm-z-popover: 50;
|
--tm-z-popover: 50;
|
||||||
@@ -45,26 +56,34 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
[data-theme='dark'] {
|
[data-theme='dark'] {
|
||||||
--tm-background: 150 15% 10%;
|
--tm-background: 165 8% 9.8039%;
|
||||||
--tm-foreground: 145 25% 94%;
|
--tm-canvas: 160 9.0909% 12.9412%;
|
||||||
|
--tm-foreground: 145.7143 24.1379% 94.3137%;
|
||||||
--tm-surface: 150 13% 15%;
|
--tm-surface: 150 13% 15%;
|
||||||
--tm-surface-muted: 150 12% 18%;
|
--tm-surface-muted: 153.3333 12.3288% 14.3137%;
|
||||||
--tm-surface-elevated: 150 12% 19%;
|
--tm-surface-elevated: 160 10.3448% 17.0588%;
|
||||||
--tm-border: 150 12% 28%;
|
--tm-border: 152.3077 10.2362% 24.902%;
|
||||||
--tm-border-subtle: 150 10% 22%;
|
--tm-border-subtle: 150 10% 22%;
|
||||||
--tm-primary: 157 48% 52%;
|
--tm-primary: 163.9535 54.4304% 30.9804%;
|
||||||
--tm-primary-foreground: 150 15% 10%;
|
--tm-primary-hover: 157.4194 50.2703% 36.2745%;
|
||||||
--tm-secondary: 150 12% 24%;
|
--tm-primary-foreground: 0 0% 100%;
|
||||||
--tm-secondary-foreground: 145 25% 94%;
|
--tm-secondary: 150 10% 22%;
|
||||||
--tm-muted: 150 12% 24%;
|
--tm-secondary-foreground: 145.7143 24.1379% 94.3137%;
|
||||||
--tm-muted-foreground: 150 10% 66%;
|
--tm-muted: 150 10% 22%;
|
||||||
--tm-accent: 157 31% 25%;
|
--tm-muted-foreground: 150 10% 72.549%;
|
||||||
--tm-accent-foreground: 157 48% 82%;
|
--tm-subtle-foreground: 153.75 6.7797% 53.7255%;
|
||||||
|
--tm-accent: 158.8235 30.9091% 21.5686%;
|
||||||
|
--tm-accent-foreground: 145.7143 24.1379% 94.3137%;
|
||||||
|
--tm-ai: 236.8966 62.3656% 63.5294%;
|
||||||
|
--tm-ai-soft: 236 24% 20%;
|
||||||
--tm-success: 155 51% 55%;
|
--tm-success: 155 51% 55%;
|
||||||
--tm-warning: 34 75% 63%;
|
--tm-warning: 34 75% 63%;
|
||||||
--tm-destructive: 0 65% 66%;
|
--tm-destructive: 0 65% 66%;
|
||||||
--tm-destructive-foreground: 150 15% 10%;
|
--tm-destructive-foreground: 165 8% 9.8039%;
|
||||||
--tm-focus-ring: 157 48% 62%;
|
--tm-focus-ring: 157 48% 62%;
|
||||||
|
--tm-disabled-surface: 150 10% 18%;
|
||||||
|
--tm-disabled-foreground: 153.75 6.7797% 53.7255%;
|
||||||
|
--tm-disabled-border: 150 10% 22%;
|
||||||
--tm-shadow-surface: 0 1px 2px rgb(0 0 0 / 0.2);
|
--tm-shadow-surface: 0 1px 2px rgb(0 0 0 / 0.2);
|
||||||
--tm-shadow-floating: 0 8px 24px rgb(0 0 0 / 0.28);
|
--tm-shadow-floating: 0 8px 24px rgb(0 0 0 / 0.28);
|
||||||
--tm-shadow-popover: 0 12px 32px rgb(0 0 0 / 0.38);
|
--tm-shadow-popover: 0 12px 32px rgb(0 0 0 / 0.38);
|
||||||
@@ -73,30 +92,48 @@
|
|||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
[data-theme='system'] {
|
[data-theme='system'] {
|
||||||
--tm-background: 150 15% 10%;
|
--tm-background: 165 8% 9.8039%;
|
||||||
--tm-foreground: 145 25% 94%;
|
--tm-canvas: 160 9.0909% 12.9412%;
|
||||||
|
--tm-foreground: 145.7143 24.1379% 94.3137%;
|
||||||
--tm-surface: 150 13% 15%;
|
--tm-surface: 150 13% 15%;
|
||||||
--tm-surface-muted: 150 12% 18%;
|
--tm-surface-muted: 153.3333 12.3288% 14.3137%;
|
||||||
--tm-surface-elevated: 150 12% 19%;
|
--tm-surface-elevated: 160 10.3448% 17.0588%;
|
||||||
--tm-border: 150 12% 28%;
|
--tm-border: 152.3077 10.2362% 24.902%;
|
||||||
--tm-border-subtle: 150 10% 22%;
|
--tm-border-subtle: 150 10% 22%;
|
||||||
--tm-primary: 157 48% 52%;
|
--tm-primary: 163.9535 54.4304% 30.9804%;
|
||||||
--tm-primary-foreground: 150 15% 10%;
|
--tm-primary-hover: 157.4194 50.2703% 36.2745%;
|
||||||
--tm-secondary: 150 12% 24%;
|
--tm-primary-foreground: 0 0% 100%;
|
||||||
--tm-secondary-foreground: 145 25% 94%;
|
--tm-secondary: 150 10% 22%;
|
||||||
--tm-muted: 150 12% 24%;
|
--tm-secondary-foreground: 145.7143 24.1379% 94.3137%;
|
||||||
--tm-muted-foreground: 150 10% 66%;
|
--tm-muted: 150 10% 22%;
|
||||||
--tm-accent: 157 31% 25%;
|
--tm-muted-foreground: 150 10% 72.549%;
|
||||||
--tm-accent-foreground: 157 48% 82%;
|
--tm-subtle-foreground: 153.75 6.7797% 53.7255%;
|
||||||
|
--tm-accent: 158.8235 30.9091% 21.5686%;
|
||||||
|
--tm-accent-foreground: 145.7143 24.1379% 94.3137%;
|
||||||
|
--tm-ai: 236.8966 62.3656% 63.5294%;
|
||||||
|
--tm-ai-soft: 236 24% 20%;
|
||||||
--tm-success: 155 51% 55%;
|
--tm-success: 155 51% 55%;
|
||||||
--tm-warning: 34 75% 63%;
|
--tm-warning: 34 75% 63%;
|
||||||
--tm-destructive: 0 65% 66%;
|
--tm-destructive: 0 65% 66%;
|
||||||
--tm-destructive-foreground: 150 15% 10%;
|
--tm-destructive-foreground: 165 8% 9.8039%;
|
||||||
--tm-focus-ring: 157 48% 62%;
|
--tm-focus-ring: 157 48% 62%;
|
||||||
|
--tm-disabled-surface: 150 10% 18%;
|
||||||
|
--tm-disabled-foreground: 153.75 6.7797% 53.7255%;
|
||||||
|
--tm-disabled-border: 150 10% 22%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:where(button, input, textarea, select):focus-visible {
|
:where(
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
textarea,
|
||||||
|
select,
|
||||||
|
[role='button'],
|
||||||
|
[role='checkbox'],
|
||||||
|
[role='radio'],
|
||||||
|
[role='switch'],
|
||||||
|
[role='tab']
|
||||||
|
):focus-visible {
|
||||||
outline: 2px solid hsl(var(--tm-focus-ring) / 0.75);
|
outline: 2px solid hsl(var(--tm-focus-ring) / 0.75);
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
@mixin dark-theme {
|
@mixin dark-theme {
|
||||||
--wxex-bg-app: #171b1a;
|
--wxex-bg-app: hsl(var(--tm-background));
|
||||||
--wxex-bg-main: #1e2422;
|
--wxex-bg-main: hsl(var(--tm-canvas));
|
||||||
--wxex-bg-sidebar: #202925;
|
--wxex-bg-sidebar: hsl(var(--tm-surface-muted));
|
||||||
--wxex-bg-elevated: #27302d;
|
--wxex-bg-elevated: hsl(var(--tm-surface-elevated));
|
||||||
--wxex-text-primary: #edf4f0;
|
--wxex-text-primary: hsl(var(--tm-foreground));
|
||||||
--wxex-text-secondary: #b2c0b9;
|
--wxex-text-secondary: hsl(var(--tm-muted-foreground));
|
||||||
--wxex-text-muted: #81918a;
|
--wxex-text-muted: hsl(var(--tm-subtle-foreground));
|
||||||
--wxex-border: #394640;
|
--wxex-border: hsl(var(--tm-border));
|
||||||
--wxex-brand-soft: #26483c;
|
--wxex-brand: hsl(var(--tm-primary));
|
||||||
|
--wxex-brand-hover: hsl(var(--tm-primary-hover));
|
||||||
|
--wxex-brand-soft: hsl(var(--tm-accent));
|
||||||
|
--wxex-ai: hsl(var(--tm-ai));
|
||||||
|
--wxex-ai-soft: hsl(var(--tm-ai-soft));
|
||||||
|
--wxex-success: hsl(var(--tm-success));
|
||||||
|
--wxex-warning: hsl(var(--tm-warning));
|
||||||
|
--wxex-danger: hsl(var(--tm-destructive));
|
||||||
|
|
||||||
.conversation-section-header:hover,
|
.conversation-section-header:hover,
|
||||||
.conversation-item:hover,
|
.conversation-item:hover,
|
||||||
@@ -52,7 +59,6 @@
|
|||||||
color: var(--wxex-text-secondary);
|
color: var(--wxex-text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.wechat-system-message-meta,
|
|
||||||
.message-sender-name,
|
.message-sender-name,
|
||||||
.message-hover-time,
|
.message-hover-time,
|
||||||
.message-accessible-sender {
|
.message-accessible-sender {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ module.exports = {
|
|||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
background: 'hsl(var(--tm-background) / <alpha-value>)',
|
background: 'hsl(var(--tm-background) / <alpha-value>)',
|
||||||
|
canvas: 'hsl(var(--tm-canvas) / <alpha-value>)',
|
||||||
foreground: 'hsl(var(--tm-foreground) / <alpha-value>)',
|
foreground: 'hsl(var(--tm-foreground) / <alpha-value>)',
|
||||||
surface: 'hsl(var(--tm-surface) / <alpha-value>)',
|
surface: 'hsl(var(--tm-surface) / <alpha-value>)',
|
||||||
'surface-muted': 'hsl(var(--tm-surface-muted) / <alpha-value>)',
|
'surface-muted': 'hsl(var(--tm-surface-muted) / <alpha-value>)',
|
||||||
@@ -18,19 +19,29 @@ module.exports = {
|
|||||||
border: 'hsl(var(--tm-border) / <alpha-value>)',
|
border: 'hsl(var(--tm-border) / <alpha-value>)',
|
||||||
'border-subtle': 'hsl(var(--tm-border-subtle) / <alpha-value>)',
|
'border-subtle': 'hsl(var(--tm-border-subtle) / <alpha-value>)',
|
||||||
primary: 'hsl(var(--tm-primary) / <alpha-value>)',
|
primary: 'hsl(var(--tm-primary) / <alpha-value>)',
|
||||||
|
'primary-hover': 'hsl(var(--tm-primary-hover) / <alpha-value>)',
|
||||||
'primary-foreground': 'hsl(var(--tm-primary-foreground) / <alpha-value>)',
|
'primary-foreground': 'hsl(var(--tm-primary-foreground) / <alpha-value>)',
|
||||||
secondary: 'hsl(var(--tm-secondary) / <alpha-value>)',
|
secondary: 'hsl(var(--tm-secondary) / <alpha-value>)',
|
||||||
'secondary-foreground': 'hsl(var(--tm-secondary-foreground) / <alpha-value>)',
|
'secondary-foreground': 'hsl(var(--tm-secondary-foreground) / <alpha-value>)',
|
||||||
muted: 'hsl(var(--tm-muted) / <alpha-value>)',
|
muted: 'hsl(var(--tm-muted) / <alpha-value>)',
|
||||||
'muted-foreground': 'hsl(var(--tm-muted-foreground) / <alpha-value>)',
|
'muted-foreground': 'hsl(var(--tm-muted-foreground) / <alpha-value>)',
|
||||||
|
'subtle-foreground': 'hsl(var(--tm-subtle-foreground) / <alpha-value>)',
|
||||||
accent: 'hsl(var(--tm-accent) / <alpha-value>)',
|
accent: 'hsl(var(--tm-accent) / <alpha-value>)',
|
||||||
'accent-foreground': 'hsl(var(--tm-accent-foreground) / <alpha-value>)',
|
'accent-foreground': 'hsl(var(--tm-accent-foreground) / <alpha-value>)',
|
||||||
success: 'hsl(var(--tm-success) / <alpha-value>)',
|
success: 'hsl(var(--tm-success) / <alpha-value>)',
|
||||||
warning: 'hsl(var(--tm-warning) / <alpha-value>)',
|
warning: 'hsl(var(--tm-warning) / <alpha-value>)',
|
||||||
destructive: 'hsl(var(--tm-destructive) / <alpha-value>)',
|
destructive: 'hsl(var(--tm-destructive) / <alpha-value>)',
|
||||||
'destructive-foreground': 'hsl(var(--tm-destructive-foreground) / <alpha-value>)',
|
'destructive-foreground': 'hsl(var(--tm-destructive-foreground) / <alpha-value>)',
|
||||||
|
'disabled-surface': 'hsl(var(--tm-disabled-surface) / <alpha-value>)',
|
||||||
|
'disabled-foreground': 'hsl(var(--tm-disabled-foreground) / <alpha-value>)',
|
||||||
|
'disabled-border': 'hsl(var(--tm-disabled-border) / <alpha-value>)',
|
||||||
ring: 'hsl(var(--tm-focus-ring) / <alpha-value>)'
|
ring: 'hsl(var(--tm-focus-ring) / <alpha-value>)'
|
||||||
},
|
},
|
||||||
|
height: {
|
||||||
|
'control-compact': 'var(--tm-control-height-compact)',
|
||||||
|
'control-standard': 'var(--tm-control-height-standard)',
|
||||||
|
'control-form': 'var(--tm-control-height-form)'
|
||||||
|
},
|
||||||
borderRadius: {
|
borderRadius: {
|
||||||
sm: 'var(--tm-radius-sm)',
|
sm: 'var(--tm-radius-sm)',
|
||||||
md: 'var(--tm-radius-md)',
|
md: 'var(--tm-radius-md)',
|
||||||
|
|||||||
@@ -16,6 +16,32 @@ const baseProps = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe('export progress panel', () => {
|
describe('export progress panel', () => {
|
||||||
|
it('uses the semantic accent surface for outgoing preview messages', () => {
|
||||||
|
render(
|
||||||
|
<ExportPreviewPanel
|
||||||
|
{...baseProps}
|
||||||
|
status="idle"
|
||||||
|
previewItems={[
|
||||||
|
{
|
||||||
|
id: 'outgoing-preview',
|
||||||
|
from: 'self',
|
||||||
|
type: '文字',
|
||||||
|
datetime: '',
|
||||||
|
content: '已发送的消息',
|
||||||
|
isSender: true
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
progress={null}
|
||||||
|
includeVoiceTranscripts={false}
|
||||||
|
zip={false}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(screen.getByText('已发送的消息').closest('.export-preview-bubble')).toHaveClass(
|
||||||
|
'bg-accent'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
it('shows an indeterminate bar while the first message scan is still at zero', () => {
|
it('shows an indeterminate bar while the first message scan is still at zero', () => {
|
||||||
render(
|
render(
|
||||||
<ExportPreviewPanel
|
<ExportPreviewPanel
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
import { render, screen } from '@testing-library/react'
|
||||||
|
import userEvent from '@testing-library/user-event'
|
||||||
|
import { describe, expect, it } from 'vitest'
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Checkbox,
|
||||||
|
Input,
|
||||||
|
RadioGroup,
|
||||||
|
RadioGroupItem,
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
Switch
|
||||||
|
} from '../../src/renderer/src/components/ui'
|
||||||
|
|
||||||
|
describe('TraceMemo UI control states', () => {
|
||||||
|
it('uses the compact, standard, and form control height contract', () => {
|
||||||
|
render(
|
||||||
|
<>
|
||||||
|
<Button size="sm">紧凑</Button>
|
||||||
|
<Button>标准</Button>
|
||||||
|
<Button size="lg">表单</Button>
|
||||||
|
<Input aria-label="表单输入" />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(screen.getByRole('button', { name: '紧凑' })).toHaveClass('h-control-compact')
|
||||||
|
expect(screen.getByRole('button', { name: '标准' })).toHaveClass('h-control-standard')
|
||||||
|
expect(screen.getByRole('button', { name: '表单' })).toHaveClass('h-control-form')
|
||||||
|
expect(screen.getByRole('textbox', { name: '表单输入' })).toHaveClass('h-control-form')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('keeps disabled controls readable without the old opacity and surface shadow', () => {
|
||||||
|
render(
|
||||||
|
<>
|
||||||
|
<Button disabled>不可用操作</Button>
|
||||||
|
<Input aria-label="不可用输入" value="仍可读取" disabled readOnly />
|
||||||
|
<Checkbox aria-label="不可用多选" disabled />
|
||||||
|
<RadioGroup aria-label="不可用单选组">
|
||||||
|
<RadioGroupItem value="disabled" aria-label="不可用单选" disabled />
|
||||||
|
</RadioGroup>
|
||||||
|
<Switch aria-label="不可用开关" disabled />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
|
||||||
|
for (const control of [
|
||||||
|
screen.getByRole('button', { name: '不可用操作' }),
|
||||||
|
screen.getByRole('textbox', { name: '不可用输入' }),
|
||||||
|
screen.getByRole('checkbox', { name: '不可用多选' }),
|
||||||
|
screen.getByRole('radio', { name: '不可用单选' }),
|
||||||
|
screen.getByRole('switch', { name: '不可用开关' })
|
||||||
|
]) {
|
||||||
|
expect(control).toHaveClass('disabled:opacity-100')
|
||||||
|
expect(control).not.toHaveClass('shadow-surface')
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(screen.getByRole('button', { name: '不可用操作' })).toHaveClass(
|
||||||
|
'disabled:bg-disabled-surface',
|
||||||
|
'disabled:text-disabled-foreground',
|
||||||
|
'disabled:!text-disabled-foreground'
|
||||||
|
)
|
||||||
|
expect(screen.getByRole('checkbox', { name: '不可用多选' })).toHaveClass(
|
||||||
|
'border-muted-foreground/60'
|
||||||
|
)
|
||||||
|
expect(screen.getByRole('radio', { name: '不可用单选' })).toHaveClass(
|
||||||
|
'border-muted-foreground/60'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('keeps selection semantics while removing text glyph indicators', async () => {
|
||||||
|
const user = userEvent.setup()
|
||||||
|
render(
|
||||||
|
<>
|
||||||
|
<Select defaultValue="recent">
|
||||||
|
<SelectTrigger aria-label="时间范围">
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="recent">最近 30 天</SelectItem>
|
||||||
|
<SelectItem value="all">全部时间</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
<Checkbox aria-label="包含图片" />
|
||||||
|
<RadioGroup aria-label="密度" defaultValue="compact">
|
||||||
|
<RadioGroupItem value="compact" aria-label="紧凑密度" />
|
||||||
|
<RadioGroupItem value="comfortable" aria-label="舒适密度" />
|
||||||
|
</RadioGroup>
|
||||||
|
<Switch aria-label="显示头像" />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
|
||||||
|
const trigger = screen.getByRole('combobox', { name: '时间范围' })
|
||||||
|
expect(trigger).not.toHaveTextContent('⌄')
|
||||||
|
await user.click(trigger)
|
||||||
|
expect(await screen.findByRole('option', { name: '最近 30 天' })).not.toHaveTextContent('✓')
|
||||||
|
await user.keyboard('{Escape}')
|
||||||
|
|
||||||
|
const checkbox = screen.getByRole('checkbox', { name: '包含图片' })
|
||||||
|
await user.click(checkbox)
|
||||||
|
expect(checkbox).toBeChecked()
|
||||||
|
expect(checkbox).not.toHaveTextContent('✓')
|
||||||
|
|
||||||
|
await user.click(screen.getByRole('radio', { name: '舒适密度' }))
|
||||||
|
expect(screen.getByRole('radio', { name: '舒适密度' })).toBeChecked()
|
||||||
|
|
||||||
|
const toggle = screen.getByRole('switch', { name: '显示头像' })
|
||||||
|
await user.click(toggle)
|
||||||
|
expect(toggle).toBeChecked()
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -649,6 +649,62 @@ test('EXPORT-01 multi-chat selection stays local to export and forces HTML', asy
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('EXPORT-02 large contact list stays bounded and searchable', async () => {
|
||||||
|
const fixture = await launchTestApp({ largeContacts: 1500 })
|
||||||
|
const pageErrors: Error[] = []
|
||||||
|
fixture.page.on('pageerror', (error) => pageErrors.push(error))
|
||||||
|
try {
|
||||||
|
await fixture.setWindowContentSize({ width: 1400, height: 772 })
|
||||||
|
await fixture.page.getByRole('button', { name: '导出' }).click()
|
||||||
|
await expect(fixture.page.getByText('共 1,503 个')).toBeVisible()
|
||||||
|
|
||||||
|
const contactList = fixture.page.locator('.export-contact-list')
|
||||||
|
expect(await contactList.getByRole('button').count()).toBeLessThan(50)
|
||||||
|
|
||||||
|
const compositeButtons = [
|
||||||
|
fixture.page.getByRole('button', { name: /^全部导出/ }),
|
||||||
|
fixture.page.getByRole('button', { name: /HTML/ }),
|
||||||
|
fixture.page.locator('.export-workspace > aside:first-child > button:last-child')
|
||||||
|
]
|
||||||
|
for (const button of compositeButtons) {
|
||||||
|
await expect(button).toBeVisible()
|
||||||
|
expect(
|
||||||
|
await button.evaluate(
|
||||||
|
(element) => element.scrollHeight <= element.clientHeight && element.clientHeight > 32
|
||||||
|
)
|
||||||
|
).toBe(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const previewGeometryIsStable = await fixture.page
|
||||||
|
.locator('.export-workspace > aside:last-child')
|
||||||
|
.evaluate((previewPanel) => {
|
||||||
|
const scrollRegion = previewPanel.children.item(1)
|
||||||
|
const statistics = previewPanel.children.item(2)
|
||||||
|
if (!(scrollRegion instanceof HTMLElement) || !(statistics instanceof HTMLElement)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const panelRect = previewPanel.getBoundingClientRect()
|
||||||
|
const scrollRect = scrollRegion.getBoundingClientRect()
|
||||||
|
const statisticsRect = statistics.getBoundingClientRect()
|
||||||
|
return (
|
||||||
|
scrollRect.bottom <= statisticsRect.top &&
|
||||||
|
statisticsRect.bottom <= panelRect.bottom &&
|
||||||
|
statistics.scrollHeight <= statistics.clientHeight
|
||||||
|
)
|
||||||
|
})
|
||||||
|
expect(previewGeometryIsStable).toBe(true)
|
||||||
|
|
||||||
|
await fixture.page.getByRole('textbox', { name: '搜索聊天' }).fill('性能样本 1499')
|
||||||
|
const target = contactList.getByRole('button', { name: /性能样本 1499/ })
|
||||||
|
await expect(target).toBeVisible()
|
||||||
|
await target.click()
|
||||||
|
await expect(target).toHaveAttribute('aria-pressed', 'true')
|
||||||
|
expect(pageErrors).toEqual([])
|
||||||
|
} finally {
|
||||||
|
await fixture.close()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
test('LAYOUT-01 core workspaces fit a narrow desktop viewport without page errors', async () => {
|
test('LAYOUT-01 core workspaces fit a narrow desktop viewport without page errors', async () => {
|
||||||
const fixture = await launchTestApp()
|
const fixture = await launchTestApp()
|
||||||
const pageErrors: Error[] = []
|
const pageErrors: Error[] = []
|
||||||
|
|||||||
@@ -23,10 +23,16 @@ export async function launchTestApp(
|
|||||||
aiFailure?: string
|
aiFailure?: string
|
||||||
now?: number
|
now?: number
|
||||||
appearanceTheme?: 'light' | 'dark'
|
appearanceTheme?: 'light' | 'dark'
|
||||||
|
stableUserData?: string
|
||||||
} = {}
|
} = {}
|
||||||
): Promise<TestApplication> {
|
): Promise<TestApplication> {
|
||||||
const ownsDirectory = !options.userData
|
const ownsDirectory = !options.userData || Boolean(options.stableUserData)
|
||||||
const userData = options.userData || mkdtempSync(resolve(tmpdir(), 'wxe-e2e-'))
|
const userData =
|
||||||
|
options.userData ||
|
||||||
|
(options.stableUserData
|
||||||
|
? resolve(options.stableUserData)
|
||||||
|
: mkdtempSync(resolve(tmpdir(), 'wxe-e2e-')))
|
||||||
|
if (options.stableUserData) rmSync(userData, { recursive: true, force: true })
|
||||||
const localTestEnv = loadEnv('test', process.cwd(), 'WXE_E2E_')
|
const localTestEnv = loadEnv('test', process.cwd(), 'WXE_E2E_')
|
||||||
const configuredCloseDelay = Number(
|
const configuredCloseDelay = Number(
|
||||||
process.env.WXE_E2E_CLOSE_DELAY_MS ?? localTestEnv.WXE_E2E_CLOSE_DELAY_MS
|
process.env.WXE_E2E_CLOSE_DELAY_MS ?? localTestEnv.WXE_E2E_CLOSE_DELAY_MS
|
||||||
@@ -50,15 +56,21 @@ export async function launchTestApp(
|
|||||||
const page = await app.firstWindow()
|
const page = await app.firstWindow()
|
||||||
await page.waitForLoadState('domcontentloaded')
|
await page.waitForLoadState('domcontentloaded')
|
||||||
const setWindowContentSize = async (size: { width: number; height: number }): Promise<void> => {
|
const setWindowContentSize = async (size: { width: number; height: number }): Promise<void> => {
|
||||||
await app.evaluate(({ BrowserWindow }, nextSize) => {
|
await app.evaluate(({ BrowserWindow, screen }, nextSize) => {
|
||||||
const [window] = BrowserWindow.getAllWindows()
|
const [window] = BrowserWindow.getAllWindows()
|
||||||
if (!window) throw new Error('E2E BrowserWindow is unavailable')
|
if (!window) throw new Error('E2E BrowserWindow is unavailable')
|
||||||
|
const { workArea } = screen.getPrimaryDisplay()
|
||||||
|
window.setPosition(workArea.x + 40, workArea.y + 40)
|
||||||
window.setContentSize(nextSize.width, nextSize.height)
|
window.setContentSize(nextSize.width, nextSize.height)
|
||||||
}, size)
|
}, size)
|
||||||
await page.waitForFunction(
|
await page.waitForFunction(
|
||||||
(nextSize) => window.innerWidth === nextSize.width && window.innerHeight === nextSize.height,
|
(nextSize) => window.innerWidth === nextSize.width && window.innerHeight === nextSize.height,
|
||||||
size
|
size
|
||||||
)
|
)
|
||||||
|
await page.evaluate(
|
||||||
|
() =>
|
||||||
|
new Promise<void>((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve)))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
app,
|
app,
|
||||||
|
|||||||
+118
-68
@@ -4,7 +4,7 @@ import { resolve } from 'path'
|
|||||||
import { launchTestApp } from './support/electron'
|
import { launchTestApp } from './support/electron'
|
||||||
|
|
||||||
const baselineDirectory = resolve(`tests/e2e/__screenshots__/${process.platform}/visual.spec.ts`)
|
const baselineDirectory = resolve(`tests/e2e/__screenshots__/${process.platform}/visual.spec.ts`)
|
||||||
const visualViewport = { width: 1000, height: 650 }
|
const visualViewport = { width: 1400, height: 772 }
|
||||||
const visualNow = Date.parse('2026-08-19T14:46:40+08:00')
|
const visualNow = Date.parse('2026-08-19T14:46:40+08:00')
|
||||||
|
|
||||||
async function clearScreenshotFocus(page: import('@playwright/test').Page): Promise<void> {
|
async function clearScreenshotFocus(page: import('@playwright/test').Page): Promise<void> {
|
||||||
@@ -200,6 +200,30 @@ test('API-00 Reader Skill page visual @visual', async () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('API-00 Reader Skill page dark visual @visual', async () => {
|
||||||
|
const fixture = await launchTestApp({ now: visualNow, appearanceTheme: 'dark' })
|
||||||
|
const pageErrors: Error[] = []
|
||||||
|
fixture.page.on('pageerror', (error) => pageErrors.push(error))
|
||||||
|
try {
|
||||||
|
await fixture.setWindowContentSize(visualViewport)
|
||||||
|
await fixture.page.getByRole('button', { name: 'API' }).click()
|
||||||
|
await expect(fixture.page.getByRole('heading', { name: 'TraceMemo Reader' })).toBeVisible()
|
||||||
|
await expect(fixture.page.getByText('API Token', { exact: true })).toBeVisible()
|
||||||
|
await expect(fixture.page.locator('html')).toHaveAttribute('data-theme', 'dark')
|
||||||
|
expect(
|
||||||
|
await fixture.page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)
|
||||||
|
).toBe(true)
|
||||||
|
expect(pageErrors).toEqual([])
|
||||||
|
await clearScreenshotFocus(fixture.page)
|
||||||
|
await expect(fixture.page).toHaveScreenshot('api-center-page-dark.png', {
|
||||||
|
animations: 'disabled',
|
||||||
|
caret: 'hide'
|
||||||
|
})
|
||||||
|
} finally {
|
||||||
|
await fixture.close()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
test('API-01 Reader Skill preview visual @visual', async () => {
|
test('API-01 Reader Skill preview visual @visual', async () => {
|
||||||
const fixture = await launchTestApp({ now: visualNow })
|
const fixture = await launchTestApp({ now: visualNow })
|
||||||
const pageErrors: Error[] = []
|
const pageErrors: Error[] = []
|
||||||
@@ -259,77 +283,99 @@ test('API-02 Agent target segmented control visual @visual', async () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
test('REPORT-00 report configuration controls visual @visual', async () => {
|
for (const appearanceTheme of ['light', 'dark'] as const) {
|
||||||
const fixture = await launchTestApp({ now: visualNow })
|
test(`REPORT-00 report configuration controls ${appearanceTheme} visual @visual`, async () => {
|
||||||
const pageErrors: Error[] = []
|
const fixture = await launchTestApp({ now: visualNow, appearanceTheme })
|
||||||
fixture.page.on('pageerror', (error) => pageErrors.push(error))
|
const pageErrors: Error[] = []
|
||||||
try {
|
fixture.page.on('pageerror', (error) => pageErrors.push(error))
|
||||||
await fixture.setWindowContentSize(visualViewport)
|
try {
|
||||||
await fixture.page.getByRole('button', { name: '日报' }).click()
|
await fixture.setWindowContentSize(visualViewport)
|
||||||
await fixture.page.getByRole('button', { name: '开始生成日报' }).click()
|
await fixture.page.getByRole('button', { name: '日报' }).click()
|
||||||
await fixture.page.locator('.report-source-item').filter({ hasText: '产品测试群' }).click()
|
await fixture.page.getByRole('button', { name: '开始生成日报' }).click()
|
||||||
await expect(fixture.page.getByRole('heading', { name: '生成群聊日报' })).toBeVisible()
|
await fixture.page.locator('.report-source-item').filter({ hasText: '产品测试群' }).click()
|
||||||
await expect(fixture.page.getByRole('radiogroup', { name: '总结范围' })).toBeVisible()
|
await expect(fixture.page.getByRole('heading', { name: '生成群聊日报' })).toBeVisible()
|
||||||
expect(
|
await expect(fixture.page.getByRole('radiogroup', { name: '总结范围' })).toBeVisible()
|
||||||
await fixture.page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)
|
expect(
|
||||||
).toBe(true)
|
await fixture.page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)
|
||||||
expect(pageErrors).toEqual([])
|
).toBe(true)
|
||||||
await clearScreenshotFocus(fixture.page)
|
expect(pageErrors).toEqual([])
|
||||||
await expect(fixture.page).toHaveScreenshot('report-config-page.png', {
|
await clearScreenshotFocus(fixture.page)
|
||||||
animations: 'disabled',
|
await expect(fixture.page).toHaveScreenshot(
|
||||||
caret: 'hide'
|
`${appearanceTheme === 'light' ? 'report-config-page' : 'report-config-page-dark'}.png`,
|
||||||
})
|
{
|
||||||
|
animations: 'disabled',
|
||||||
|
caret: 'hide'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const modelHeading = fixture.page.getByRole('heading', { name: '模型配置' })
|
const modelHeading = fixture.page.getByRole('heading', { name: '模型配置' })
|
||||||
await modelHeading.scrollIntoViewIfNeeded()
|
await modelHeading.scrollIntoViewIfNeeded()
|
||||||
await expect(modelHeading).toBeVisible()
|
await expect(modelHeading).toBeVisible()
|
||||||
await clearScreenshotFocus(fixture.page)
|
await clearScreenshotFocus(fixture.page)
|
||||||
await expect(fixture.page).toHaveScreenshot('report-model-controls.png', {
|
await expect(fixture.page).toHaveScreenshot(
|
||||||
animations: 'disabled',
|
`${appearanceTheme === 'light' ? 'report-model-controls' : 'report-model-controls-dark'}.png`,
|
||||||
caret: 'hide'
|
{
|
||||||
})
|
animations: 'disabled',
|
||||||
|
caret: 'hide'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const templateSection = fixture.page.getByRole('heading', { name: '日报模板' }).locator('..')
|
if (appearanceTheme === 'light') {
|
||||||
await templateSection.getByRole('button', { name: '查看版式' }).first().click()
|
const templateSection = fixture.page
|
||||||
const templateDialog = fixture.page.getByRole('dialog', { name: '经典日报' })
|
.getByRole('heading', { name: '日报模板' })
|
||||||
await expect(templateDialog).toBeVisible()
|
.locator('..')
|
||||||
await clearScreenshotFocus(fixture.page)
|
await templateSection.getByRole('button', { name: '查看版式' }).first().click()
|
||||||
await expect(fixture.page).toHaveScreenshot('report-template-dialog.png', {
|
const templateDialog = fixture.page.getByRole('dialog', { name: '经典日报' })
|
||||||
animations: 'disabled',
|
await expect(templateDialog).toBeVisible()
|
||||||
caret: 'hide'
|
await clearScreenshotFocus(fixture.page)
|
||||||
})
|
await expect(fixture.page).toHaveScreenshot('report-template-dialog.png', {
|
||||||
} finally {
|
animations: 'disabled',
|
||||||
await fixture.close()
|
caret: 'hide'
|
||||||
}
|
})
|
||||||
})
|
}
|
||||||
|
} finally {
|
||||||
|
await fixture.close()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
test('REPORT-01 report retry controls visual @visual', async () => {
|
for (const appearanceTheme of ['light', 'dark'] as const) {
|
||||||
const fixture = await launchTestApp({ now: visualNow, aiFailure: '401' })
|
test(`REPORT-01 report retry controls ${appearanceTheme} visual @visual`, async () => {
|
||||||
const pageErrors: Error[] = []
|
const fixture = await launchTestApp({
|
||||||
fixture.page.on('pageerror', (error) => pageErrors.push(error))
|
now: visualNow,
|
||||||
try {
|
aiFailure: '401',
|
||||||
await fixture.setWindowContentSize(visualViewport)
|
appearanceTheme,
|
||||||
await fixture.page.getByRole('button', { name: '日报' }).click()
|
stableUserData: '/tmp/tracememo-e2e-report-user-data'
|
||||||
await fixture.page.getByRole('button', { name: '开始生成日报' }).click()
|
|
||||||
await fixture.page.locator('.report-source-item').filter({ hasText: '产品测试群' }).click()
|
|
||||||
await fixture.page.getByRole('radio', { name: '近 7 天' }).click()
|
|
||||||
await fixture.page.getByRole('button', { name: '开始生成日报' }).click()
|
|
||||||
await expect(fixture.page.getByText(/本地假服务错误 401/).first()).toBeVisible()
|
|
||||||
await expect(fixture.page.getByRole('combobox', { name: '切换模型' })).toBeVisible()
|
|
||||||
await expect(fixture.page.getByRole('button', { name: '使用所选模型重新生成' })).toBeEnabled()
|
|
||||||
expect(
|
|
||||||
await fixture.page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)
|
|
||||||
).toBe(true)
|
|
||||||
expect(pageErrors).toEqual([])
|
|
||||||
await clearScreenshotFocus(fixture.page)
|
|
||||||
await expect(fixture.page).toHaveScreenshot('report-retry-controls.png', {
|
|
||||||
animations: 'disabled',
|
|
||||||
caret: 'hide'
|
|
||||||
})
|
})
|
||||||
} finally {
|
const pageErrors: Error[] = []
|
||||||
await fixture.close()
|
fixture.page.on('pageerror', (error) => pageErrors.push(error))
|
||||||
}
|
try {
|
||||||
})
|
await fixture.setWindowContentSize(visualViewport)
|
||||||
|
await fixture.page.getByRole('button', { name: '日报' }).click()
|
||||||
|
await fixture.page.getByRole('button', { name: '开始生成日报' }).click()
|
||||||
|
await fixture.page.locator('.report-source-item').filter({ hasText: '产品测试群' }).click()
|
||||||
|
await fixture.page.getByRole('radio', { name: '近 7 天' }).click()
|
||||||
|
await fixture.page.getByRole('button', { name: '开始生成日报' }).click()
|
||||||
|
await expect(fixture.page.getByText(/本地假服务错误 401/).first()).toBeVisible()
|
||||||
|
await expect(fixture.page.getByRole('combobox', { name: '切换模型' })).toBeVisible()
|
||||||
|
await expect(fixture.page.getByRole('button', { name: '使用所选模型重新生成' })).toBeEnabled()
|
||||||
|
expect(
|
||||||
|
await fixture.page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)
|
||||||
|
).toBe(true)
|
||||||
|
expect(pageErrors).toEqual([])
|
||||||
|
await clearScreenshotFocus(fixture.page)
|
||||||
|
await expect(fixture.page).toHaveScreenshot(
|
||||||
|
`${appearanceTheme === 'light' ? 'report-retry-controls' : 'report-retry-controls-dark'}.png`,
|
||||||
|
{
|
||||||
|
animations: 'disabled',
|
||||||
|
caret: 'hide'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} finally {
|
||||||
|
await fixture.close()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
for (const appearanceTheme of ['light', 'dark'] as const) {
|
for (const appearanceTheme of ['light', 'dark'] as const) {
|
||||||
test(`CHAT-02 personal WeChat send dialog ${appearanceTheme} visual @visual`, async () => {
|
test(`CHAT-02 personal WeChat send dialog ${appearanceTheme} visual @visual`, async () => {
|
||||||
@@ -568,6 +614,10 @@ for (const appearanceTheme of ['light', 'dark'] as const) {
|
|||||||
await expect(fixture.page.getByRole('heading', { name: '新增供应商' })).toBeVisible()
|
await expect(fixture.page.getByRole('heading', { name: '新增供应商' })).toBeVisible()
|
||||||
await fixture.page.getByLabel('供应商 ID').fill('fixture-new-provider')
|
await fixture.page.getByLabel('供应商 ID').fill('fixture-new-provider')
|
||||||
await expect(fixture.page.getByRole('combobox', { name: '快速模板' })).toBeVisible()
|
await expect(fixture.page.getByRole('combobox', { name: '快速模板' })).toBeVisible()
|
||||||
|
// Pin the screenshot after fill() auto-scroll to avoid half-pixel capture drift.
|
||||||
|
await fixture.page
|
||||||
|
.locator('.settings-page-scroll')
|
||||||
|
.evaluate((element) => (element.scrollTop = 396))
|
||||||
expect(
|
expect(
|
||||||
await fixture.page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)
|
await fixture.page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)
|
||||||
).toBe(true)
|
).toBe(true)
|
||||||
|
|||||||
Reference in New Issue
Block a user