mirror of
https://github.com/zyycn/codex-proxy-rs.git
synced 2026-11-06 16:06:08 +00:00
fix(web): center button loading indicators
Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
@@ -70,7 +70,7 @@ const loadingIconSize: Record<ButtonSize, number> = {
|
||||
}
|
||||
|
||||
const classes = computed(() => [
|
||||
'inline-flex items-center justify-center border-0 font-bold leading-[1.15] transition-[background-color,box-shadow,color,opacity,transform] duration-150 cursor-pointer outline-none motion-safe:active:translate-y-px motion-safe:active:scale-[0.985]',
|
||||
'relative inline-flex items-center justify-center border-0 font-bold leading-[1.15] transition-[background-color,box-shadow,color,opacity,transform] duration-150 cursor-pointer outline-none motion-safe:active:translate-y-px motion-safe:active:scale-[0.985]',
|
||||
props.iconOnly ? iconOnlySizeClasses[props.size] : sizeClasses[props.size],
|
||||
props.iconOnly ? '' : 'rounded-(--cp-button-radius-base)',
|
||||
'focus-visible:ring-2 focus-visible:ring-(--cp-info-border) focus-visible:ring-offset-2 focus-visible:ring-offset-(--cp-bg-surface)',
|
||||
@@ -110,23 +110,32 @@ const labelClasses = computed(() => [
|
||||
>
|
||||
<span
|
||||
v-if="loading"
|
||||
class="inline-flex shrink-0 items-center justify-center leading-none"
|
||||
class="pointer-events-none absolute inset-0 inline-flex items-center justify-center leading-none"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<LoaderCircle
|
||||
:size="loadingIconSize[size]"
|
||||
class="block animate-spin origin-center will-change-transform transform-fill"
|
||||
class="block animate-spin origin-center [transform-box:view-box] will-change-transform"
|
||||
/>
|
||||
</span>
|
||||
<span v-if="$slots.icon && !loading" class="inline-flex shrink-0">
|
||||
<span
|
||||
v-if="$slots.icon"
|
||||
class="inline-flex shrink-0 transition-opacity duration-150"
|
||||
:class="loading ? 'opacity-0' : undefined"
|
||||
>
|
||||
<slot name="icon" />
|
||||
</span>
|
||||
<span v-if="!iconOnly && $slots.default" :class="labelClasses">
|
||||
<span
|
||||
v-if="!iconOnly && $slots.default"
|
||||
class="transition-opacity duration-150"
|
||||
:class="[labelClasses, loading ? 'opacity-0' : undefined]"
|
||||
>
|
||||
<slot />
|
||||
</span>
|
||||
<span
|
||||
v-if="iconOnly && !$slots.icon && !loading"
|
||||
class="inline-flex items-center justify-center"
|
||||
v-if="iconOnly && !$slots.icon"
|
||||
class="inline-flex items-center justify-center transition-opacity duration-150"
|
||||
:class="loading ? 'opacity-0' : undefined"
|
||||
>
|
||||
<slot />
|
||||
</span>
|
||||
|
||||
@@ -45,10 +45,11 @@ const quotaWindows = computed(() => orderedPanelQuotaWindows(props.account.quota
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
title="刷新额度"
|
||||
:loading="refreshing"
|
||||
:disabled="refreshing"
|
||||
@click="emit('refreshQuota', account.id)"
|
||||
>
|
||||
<RefreshCw class="size-3.5" :class="refreshing ? 'animate-spin' : undefined" />
|
||||
<RefreshCw class="size-3.5" />
|
||||
</BaseButton>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { AccountRow } from '../constants'
|
||||
import { KeyRound, LoaderCircle, MoreHorizontal, Power, RefreshCw, Trash2, Wifi } from '@lucide/vue'
|
||||
import { KeyRound, MoreHorizontal, Power, RefreshCw, Trash2, Wifi } from '@lucide/vue'
|
||||
|
||||
import { computed } from 'vue'
|
||||
import BaseButton from '@/components/base/BaseButton.vue'
|
||||
@@ -52,51 +52,51 @@ const canReauthorize = computed(() => props.account.provider === 'openai')
|
||||
</template>
|
||||
|
||||
<template #default="{ close }">
|
||||
<button
|
||||
type="button"
|
||||
class="flex h-8.5 w-full items-center gap-2 rounded-(--cp-input-radius-small) border-0 bg-transparent px-3 text-left text-[13px] leading-none font-emphasis text-(--cp-text-primary) transition-colors hover:bg-(--cp-default-bg-hover) disabled:cursor-not-allowed disabled:text-(--cp-disabled-text)"
|
||||
<BaseButton
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="h-8.5! w-full justify-start! gap-2! rounded-(--cp-input-radius-small)! px-3! text-left text-[13px] leading-none! font-emphasis! text-(--cp-text-primary)!"
|
||||
:loading="testing"
|
||||
:disabled="testing"
|
||||
@click.stop="(close(), emit('test', account))"
|
||||
>
|
||||
<LoaderCircle v-if="testing" class="size-3.5 animate-spin text-(--cp-text-muted)" />
|
||||
<Wifi v-else class="size-3.5 text-(--cp-text-muted)" />
|
||||
<Wifi class="size-3.5 text-(--cp-text-muted)" />
|
||||
测试连接
|
||||
</button>
|
||||
<button
|
||||
</BaseButton>
|
||||
<BaseButton
|
||||
v-if="canRefreshToken"
|
||||
type="button"
|
||||
class="flex h-8.5 w-full items-center gap-2 rounded-(--cp-input-radius-small) border-0 bg-transparent px-3 text-left text-[13px] leading-none font-emphasis text-(--cp-text-primary) transition-colors hover:bg-(--cp-default-bg-hover) disabled:cursor-not-allowed disabled:text-(--cp-disabled-text)"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="h-8.5! w-full justify-start! gap-2! rounded-(--cp-input-radius-small)! px-3! text-left text-[13px] leading-none! font-emphasis! text-(--cp-text-primary)!"
|
||||
:loading="refreshing"
|
||||
:disabled="refreshing"
|
||||
@click.stop="(close(), emit('refresh', account.id))"
|
||||
>
|
||||
<RefreshCw
|
||||
class="size-3.5 text-(--cp-text-muted)"
|
||||
:class="refreshing ? 'animate-spin' : undefined"
|
||||
/>
|
||||
<RefreshCw class="size-3.5 text-(--cp-text-muted)" />
|
||||
刷新 token
|
||||
</button>
|
||||
<button
|
||||
</BaseButton>
|
||||
<BaseButton
|
||||
v-if="canReauthorize"
|
||||
type="button"
|
||||
class="flex h-8.5 w-full items-center gap-2 rounded-(--cp-input-radius-small) border-0 bg-transparent px-3 text-left text-[13px] leading-none font-emphasis text-(--cp-text-primary) transition-colors hover:bg-(--cp-default-bg-hover)"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="h-8.5! w-full justify-start! gap-2! rounded-(--cp-input-radius-small)! px-3! text-left text-[13px] leading-none! font-emphasis! text-(--cp-text-primary)!"
|
||||
@click.stop="(close(), emit('reauthorize', account))"
|
||||
>
|
||||
<KeyRound class="size-3.5 text-(--cp-text-muted)" />
|
||||
重新授权
|
||||
</button>
|
||||
<button
|
||||
</BaseButton>
|
||||
<BaseButton
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="h-8.5! w-full justify-start! gap-2! rounded-(--cp-input-radius-small)! px-3! text-left text-[13px] leading-none! font-emphasis! text-(--cp-text-primary)!"
|
||||
:loading="updatingStatus"
|
||||
type="button"
|
||||
class="flex h-8.5 w-full items-center gap-2 rounded-(--cp-input-radius-small) border-0 bg-transparent px-3 text-left text-[13px] leading-none font-emphasis text-(--cp-text-primary) transition-colors hover:bg-(--cp-default-bg-hover) disabled:cursor-not-allowed disabled:text-(--cp-disabled-text)"
|
||||
:disabled="updatingStatus"
|
||||
@click.stop="(close(), emit('toggleSchedule', account))"
|
||||
>
|
||||
<LoaderCircle
|
||||
v-if="updatingStatus"
|
||||
class="size-3.5 animate-spin text-(--cp-text-muted)"
|
||||
/>
|
||||
<Power v-else class="size-3.5 text-(--cp-text-muted)" />
|
||||
<Power class="size-3.5 text-(--cp-text-muted)" />
|
||||
{{ scheduleLabel }}
|
||||
</button>
|
||||
</BaseButton>
|
||||
</template>
|
||||
</BasePopover>
|
||||
</div>
|
||||
|
||||
@@ -46,10 +46,11 @@ const {
|
||||
class="text-(--cp-normal)"
|
||||
size="md"
|
||||
label="刷新概览"
|
||||
:loading="loading || refreshing"
|
||||
:disabled="loading || refreshing"
|
||||
@click="refresh"
|
||||
>
|
||||
<RefreshCw :size="19" :class="loading || refreshing ? 'animate-spin' : undefined" />
|
||||
<RefreshCw :size="19" />
|
||||
</BaseButton>
|
||||
</template>
|
||||
</BasePageHeader>
|
||||
|
||||
@@ -69,10 +69,11 @@ function showDetail(record: Awaited<ReturnType<typeof getOpsErrors>>['items'][nu
|
||||
variant="ghost"
|
||||
size="md"
|
||||
label="刷新错误明细"
|
||||
:loading="refreshing"
|
||||
:disabled="loading || refreshing"
|
||||
@click="refresh"
|
||||
>
|
||||
<RefreshCw class="size-4.5" :class="refreshing ? 'animate-spin' : undefined" />
|
||||
<RefreshCw class="size-4.5" />
|
||||
</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -32,10 +32,11 @@ const search = defineModel<string>('search', { required: true })
|
||||
variant="ghost"
|
||||
size="md"
|
||||
label="刷新使用记录"
|
||||
:loading="refreshing"
|
||||
:disabled="loading || refreshing"
|
||||
@click="emit('refresh')"
|
||||
>
|
||||
<RefreshCw class="size-4.5" :class="refreshing ? 'animate-spin' : undefined" />
|
||||
<RefreshCw class="size-4.5" />
|
||||
</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user