mirror of
https://github.com/Tencent/WeKnora.git
synced 2026-06-04 13:30:32 +08:00
feat(settings): redesign parser/storage engine cards
Bring the engine selectors in line with the rest of the redesigned settings cards (Model / WebSearch / Mcp). Same skeleton: leading 36x36 monogram badge tinted per engine, clean title row, dot+label status pill, two-line description, brand-color outline when the config drawer is open for that card. Parser engines: - Replace the bespoke .engine-card markup with a button-based card carrying a badge derived from the localized display name. - Keep available/unavailable as a status pill (green dot / red dot) instead of t-tags, retaining the unavailable-reason tooltip via a dedicated --help variant. Storage engines: - Collapse the eight hand-written cards into a single v-for over a STORAGE_PROVIDERS array; titles, monograms, and statuses funnel through providerTitle/providerInitial/providerStatus helpers so adding a future engine only needs an array entry plus translations. - Status pill mirrors Parser/Mcp idioms: green for available / configurable, gray for "needs config" (currently MinIO-only). Drops the now-unused .engine-card-header/.engine-card-desc/ .tag-with-tooltip rules.
This commit is contained in:
@@ -25,40 +25,70 @@
|
||||
<p class="empty-text">{{ $t('settings.parser.noEngineDetected') }}</p>
|
||||
</div>
|
||||
|
||||
<!-- 与其它 settings 列表同形:左侧 monogram 徽章 + 标题 + 状态徽 + 两行描述。
|
||||
整张卡片可点击,打开抽屉配置;当前抽屉对应的卡片获得品牌色描边。 -->
|
||||
<div v-else class="engine-cards">
|
||||
<!-- 当后端未返回 builtin 引擎项时,仍展示 DocReader 状态卡片 -->
|
||||
<div
|
||||
<button
|
||||
v-if="!hasBuiltinEngine"
|
||||
:class="['engine-card', { active: drawerVisible && currentEngine?.Name === 'builtin' }]"
|
||||
type="button"
|
||||
class="engine-card engine-card--builtin"
|
||||
:class="{ 'engine-card--active': drawerVisible && currentEngine?.Name === 'builtin' }"
|
||||
@click="openDrawer({ Name: 'builtin' } as any)"
|
||||
>
|
||||
<div class="engine-card-header">
|
||||
<h3>builtin</h3>
|
||||
<t-tag
|
||||
:theme="connected ? 'success' : 'danger'"
|
||||
variant="light"
|
||||
size="small"
|
||||
>{{ connected ? $t('settings.parser.connected') : $t('settings.parser.disconnected') }}</t-tag>
|
||||
<div class="engine-card__badge">{{ engineInitial('builtin') }}</div>
|
||||
<div class="engine-card__body">
|
||||
<div class="engine-card__header">
|
||||
<h3 class="engine-card__title">{{ getEngineDisplayName('builtin') }}</h3>
|
||||
<span
|
||||
class="engine-card__status"
|
||||
:class="connected ? 'engine-card__status--on' : 'engine-card__status--err'"
|
||||
>
|
||||
<span class="engine-card__status-dot" />
|
||||
{{ connected ? $t('settings.parser.connected') : $t('settings.parser.disconnected') }}
|
||||
</span>
|
||||
</div>
|
||||
<p class="engine-card__desc">{{ $t('settings.parser.builtinDesc') }}</p>
|
||||
</div>
|
||||
<p class="engine-card-desc">{{ $t('settings.parser.builtinDesc') }}</p>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<div
|
||||
<button
|
||||
v-for="engine in sortedEngines"
|
||||
:key="engine.Name"
|
||||
:class="['engine-card', { active: drawerVisible && currentEngine?.Name === engine.Name }]"
|
||||
type="button"
|
||||
class="engine-card"
|
||||
:class="[
|
||||
`engine-card--${engine.Name}`,
|
||||
{ 'engine-card--active': drawerVisible && currentEngine?.Name === engine.Name }
|
||||
]"
|
||||
@click="openDrawer(engine)"
|
||||
>
|
||||
<div class="engine-card-header">
|
||||
<h3>{{ getEngineDisplayName(engine.Name) }}</h3>
|
||||
<t-tag v-if="engine.Available" theme="success" variant="light" size="small">{{ $t('settings.parser.available') }}</t-tag>
|
||||
<t-tooltip v-else-if="engine.UnavailableReason" :content="engine.UnavailableReason" placement="top">
|
||||
<t-tag theme="danger" variant="light" size="small" class="tag-with-tooltip">{{ $t('settings.parser.unavailable') }}</t-tag>
|
||||
</t-tooltip>
|
||||
<t-tag v-else theme="danger" variant="light" size="small">{{ $t('settings.parser.unavailable') }}</t-tag>
|
||||
<div class="engine-card__badge">{{ engineInitial(engine.Name) }}</div>
|
||||
<div class="engine-card__body">
|
||||
<div class="engine-card__header">
|
||||
<h3 class="engine-card__title">{{ getEngineDisplayName(engine.Name) }}</h3>
|
||||
<span v-if="engine.Available" class="engine-card__status engine-card__status--on">
|
||||
<span class="engine-card__status-dot" />
|
||||
{{ $t('settings.parser.available') }}
|
||||
</span>
|
||||
<t-tooltip
|
||||
v-else-if="engine.UnavailableReason"
|
||||
:content="engine.UnavailableReason"
|
||||
placement="top"
|
||||
>
|
||||
<span class="engine-card__status engine-card__status--err engine-card__status--help">
|
||||
<span class="engine-card__status-dot" />
|
||||
{{ $t('settings.parser.unavailable') }}
|
||||
</span>
|
||||
</t-tooltip>
|
||||
<span v-else class="engine-card__status engine-card__status--err">
|
||||
<span class="engine-card__status-dot" />
|
||||
{{ $t('settings.parser.unavailable') }}
|
||||
</span>
|
||||
</div>
|
||||
<p class="engine-card__desc">{{ getEngineDisplayDesc(engine.Name, engine.Description) }}</p>
|
||||
</div>
|
||||
<p class="engine-card-desc">{{ getEngineDisplayDesc(engine.Name, engine.Description) }}</p>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -336,6 +366,13 @@ function engineDocLabel(_name: string): string {
|
||||
return t('settings.parser.docs')
|
||||
}
|
||||
|
||||
// 卡片徽章首字母。优先用本地化名称的首字符(覆盖如「内置/简易」等中文场景),
|
||||
// 兜底回到 engine name;保证英文/中文都能显示一个稳定的可读 monogram。
|
||||
function engineInitial(engineName: string): string {
|
||||
const display = getEngineDisplayName(engineName)
|
||||
return (display.trim().charAt(0) || engineName.charAt(0) || '?').toUpperCase()
|
||||
}
|
||||
|
||||
function getEngineDisplayName(engineName: string): string {
|
||||
const key = `kbSettings.parser.engines.${engineName}.name`
|
||||
const translated = t(key)
|
||||
@@ -574,53 +611,141 @@ onMounted(loadAll)
|
||||
// ---- 引擎卡片布局 ----
|
||||
.engine-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
||||
gap: 16px;
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
gap: 12px;
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
// 与 ModelSettings / WebSearchSettings / McpSettings 同形的提供者卡片。
|
||||
// 这里整张卡是一个 button —— 单击即打开配置抽屉;active 状态用品牌色描边。
|
||||
.engine-card {
|
||||
border: 1px solid var(--td-component-stroke);
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
background: var(--td-bg-color-container);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
padding: 14px 14px 14px 12px;
|
||||
border: 1px solid var(--td-component-stroke);
|
||||
border-radius: 10px;
|
||||
background: var(--td-bg-color-container);
|
||||
text-align: left;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.18s ease, box-shadow 0.18s ease, background-color 0.18s ease;
|
||||
min-width: 0;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--td-brand-color);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
border-color: var(--td-brand-color-3, var(--td-brand-color));
|
||||
box-shadow: 0 4px 14px rgba(15, 23, 42, 0.06);
|
||||
}
|
||||
|
||||
&.active {
|
||||
&--active {
|
||||
border-color: var(--td-brand-color);
|
||||
background: rgba(var(--td-brand-color-5-rgba), 0.05);
|
||||
background: var(--td-brand-color-1, rgba(7, 192, 95, 0.06));
|
||||
}
|
||||
}
|
||||
|
||||
.engine-card-header {
|
||||
.engine-card__badge {
|
||||
flex-shrink: 0;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 9px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
justify-content: center;
|
||||
margin-top: 1px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
background: rgba(0, 82, 217, 0.1);
|
||||
color: #0052D9;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: var(--td-text-color-primary);
|
||||
margin: 0;
|
||||
font-family: var(--app-font-family-mono);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
// 解析引擎徽章配色 —— 内置/官方系绿,外部工具按性质各取一色。
|
||||
.engine-card--builtin .engine-card__badge,
|
||||
.engine-card--weknoracloud .engine-card__badge {
|
||||
background: rgba(7, 192, 95, 0.12);
|
||||
color: #07C05F;
|
||||
}
|
||||
.engine-card--simple .engine-card__badge {
|
||||
background: rgba(70, 70, 70, 0.1);
|
||||
color: #464646;
|
||||
}
|
||||
.engine-card--markitdown .engine-card__badge {
|
||||
background: rgba(0, 137, 255, 0.12);
|
||||
color: #0089FF;
|
||||
}
|
||||
.engine-card--mineru .engine-card__badge,
|
||||
.engine-card--mineru_cloud .engine-card__badge {
|
||||
background: rgba(98, 53, 187, 0.12);
|
||||
color: #6235BB;
|
||||
}
|
||||
|
||||
.engine-card__body {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.engine-card__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.engine-card__title {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
color: var(--td-text-color-primary);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
// 与 McpSettings 一致的 dot+文字状态徽章。on=绿、err=红、help 用 cursor:help 提示。
|
||||
.engine-card__status {
|
||||
flex-shrink: 0;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 1px 8px 1px 6px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
line-height: 16px;
|
||||
border-radius: 10px;
|
||||
background: var(--td-bg-color-secondarycontainer);
|
||||
|
||||
&--on {
|
||||
color: var(--td-success-color-7, #118053);
|
||||
|
||||
.engine-card__status-dot { background: var(--td-success-color, #118053); }
|
||||
}
|
||||
|
||||
&--err {
|
||||
color: var(--td-error-color-7, #C93E3E);
|
||||
|
||||
.engine-card__status-dot { background: var(--td-error-color, #C93E3E); }
|
||||
}
|
||||
|
||||
&--help {
|
||||
cursor: help;
|
||||
}
|
||||
}
|
||||
|
||||
.engine-card-desc {
|
||||
font-size: 13px;
|
||||
.engine-card__status-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.engine-card__desc {
|
||||
font-size: 12px;
|
||||
color: var(--td-text-color-secondary);
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
@@ -756,10 +881,6 @@ onMounted(loadAll)
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.tag-with-tooltip {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
// ---- WeKnoraCloud 凭证状态 ----
|
||||
.wkc-status {
|
||||
display: flex;
|
||||
|
||||
@@ -50,103 +50,38 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 与其它 settings 列表同形:左侧 monogram 徽章 + 标题 + 状态徽 + 描述。
|
||||
整张卡是一个 button,单击打开配置抽屉;当前抽屉对应的卡获得品牌色描边。
|
||||
原本 8 张手写卡片由统一的 STORAGE_PROVIDERS 数组驱动,把状态判定收敛到
|
||||
providerStatus(),新增 provider 时只需在数组里加一项 + 翻译键即可。 -->
|
||||
<div class="engine-cards">
|
||||
<div
|
||||
v-if="isProviderAllowed('local')"
|
||||
:class="['engine-card', { active: drawerVisible && currentEngine === 'local' }]"
|
||||
@click="openDrawer('local')"
|
||||
<button
|
||||
v-for="provider in STORAGE_PROVIDERS"
|
||||
v-show="isProviderAllowed(provider.id)"
|
||||
:key="provider.id"
|
||||
type="button"
|
||||
class="engine-card"
|
||||
:class="[
|
||||
`engine-card--${provider.id}`,
|
||||
{ 'engine-card--active': drawerVisible && currentEngine === provider.id }
|
||||
]"
|
||||
@click="openDrawer(provider.id)"
|
||||
>
|
||||
<div class="engine-card-header">
|
||||
<h3>{{ $t('settings.storage.localTitle') }}</h3>
|
||||
<t-tag theme="success" variant="light" size="small">{{ $t('settings.storage.available') }}</t-tag>
|
||||
<div class="engine-card__badge">{{ providerInitial(provider.id) }}</div>
|
||||
<div class="engine-card__body">
|
||||
<div class="engine-card__header">
|
||||
<h3 class="engine-card__title">{{ providerTitle(provider.id) }}</h3>
|
||||
<span
|
||||
class="engine-card__status"
|
||||
:class="`engine-card__status--${providerStatus(provider.id).kind}`"
|
||||
>
|
||||
<span class="engine-card__status-dot" />
|
||||
{{ providerStatus(provider.id).label }}
|
||||
</span>
|
||||
</div>
|
||||
<p class="engine-card__desc">{{ $t(`settings.storage.${provider.id}Desc`) }}</p>
|
||||
</div>
|
||||
<p class="engine-card-desc">{{ $t('settings.storage.localDesc') }}</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="isProviderAllowed('minio')"
|
||||
:class="['engine-card', { active: drawerVisible && currentEngine === 'minio' }]"
|
||||
@click="openDrawer('minio')"
|
||||
>
|
||||
<div class="engine-card-header">
|
||||
<h3>MinIO</h3>
|
||||
<t-tag v-if="minioAvailable" theme="success" variant="light" size="small">{{ $t('settings.storage.available') }}</t-tag>
|
||||
<t-tag v-else theme="default" variant="light" size="small">{{ $t('settings.storage.needsConfig') }}</t-tag>
|
||||
</div>
|
||||
<p class="engine-card-desc">{{ $t('settings.storage.minioDesc') }}</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="isProviderAllowed('cos')"
|
||||
:class="['engine-card', { active: drawerVisible && currentEngine === 'cos' }]"
|
||||
@click="openDrawer('cos')"
|
||||
>
|
||||
<div class="engine-card-header">
|
||||
<h3>{{ $t('settings.storage.cosTitle') }}</h3>
|
||||
<t-tag theme="success" variant="light" size="small">{{ $t('settings.storage.configurable') }}</t-tag>
|
||||
</div>
|
||||
<p class="engine-card-desc">{{ $t('settings.storage.cosDesc') }}</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="isProviderAllowed('tos')"
|
||||
:class="['engine-card', { active: drawerVisible && currentEngine === 'tos' }]"
|
||||
@click="openDrawer('tos')"
|
||||
>
|
||||
<div class="engine-card-header">
|
||||
<h3>{{ $t('settings.storage.tosTitle') }}</h3>
|
||||
<t-tag theme="success" variant="light" size="small">{{ $t('settings.storage.configurable') }}</t-tag>
|
||||
</div>
|
||||
<p class="engine-card-desc">{{ $t('settings.storage.tosDesc') }}</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="isProviderAllowed('s3')"
|
||||
:class="['engine-card', { active: drawerVisible && currentEngine === 's3' }]"
|
||||
@click="openDrawer('s3')"
|
||||
>
|
||||
<div class="engine-card-header">
|
||||
<h3>{{ $t('settings.storage.s3Title') }}</h3>
|
||||
<t-tag theme="success" variant="light" size="small">{{ $t('settings.storage.configurable') }}</t-tag>
|
||||
</div>
|
||||
<p class="engine-card-desc">{{ $t('settings.storage.s3Desc') }}</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="isProviderAllowed('oss')"
|
||||
:class="['engine-card', { active: drawerVisible && currentEngine === 'oss' }]"
|
||||
@click="openDrawer('oss')"
|
||||
>
|
||||
<div class="engine-card-header">
|
||||
<h3>{{ $t('settings.storage.ossTitle') }}</h3>
|
||||
<t-tag theme="success" variant="light" size="small">{{ $t('settings.storage.configurable') }}</t-tag>
|
||||
</div>
|
||||
<p class="engine-card-desc">{{ $t('settings.storage.ossDesc') }}</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="isProviderAllowed('ks3')"
|
||||
:class="['engine-card', { active: drawerVisible && currentEngine === 'ks3' }]"
|
||||
@click="openDrawer('ks3')"
|
||||
>
|
||||
<div class="engine-card-header">
|
||||
<h3>{{ $t('settings.storage.ks3Title') }}</h3>
|
||||
<t-tag theme="success" variant="light" size="small">{{ $t('settings.storage.configurable') }}</t-tag>
|
||||
</div>
|
||||
<p class="engine-card-desc">{{ $t('settings.storage.ks3Desc') }}</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="isProviderAllowed('obs')"
|
||||
:class="['engine-card', { active: drawerVisible && currentEngine === 'obs' }]"
|
||||
@click="openDrawer('obs')"
|
||||
>
|
||||
<div class="engine-card-header">
|
||||
<h3>{{ $t('settings.storage.obsTitle') }}</h3>
|
||||
<t-tag theme="success" variant="light" size="small">{{ $t('settings.storage.configurable') }}</t-tag>
|
||||
</div>
|
||||
<p class="engine-card-desc">{{ $t('settings.storage.obsDesc') }}</p>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -680,6 +615,40 @@ const minioAvailable = computed(() => {
|
||||
return minioEnvAvailable.value
|
||||
})
|
||||
|
||||
// Single source-of-truth for the cards列 + 状态/标题查询。新增 provider 时
|
||||
// 在数组里加一项 + 翻译键即可,模板 v-for 自动跟进。
|
||||
type StorageProviderId = 'local' | 'minio' | 'cos' | 'tos' | 's3' | 'oss' | 'ks3' | 'obs'
|
||||
const STORAGE_PROVIDERS: { id: StorageProviderId }[] = [
|
||||
{ id: 'local' },
|
||||
{ id: 'minio' },
|
||||
{ id: 'cos' },
|
||||
{ id: 'tos' },
|
||||
{ id: 's3' },
|
||||
{ id: 'oss' },
|
||||
{ id: 'ks3' },
|
||||
{ id: 'obs' },
|
||||
]
|
||||
|
||||
const providerTitle = (id: StorageProviderId): string => {
|
||||
if (id === 'minio') return 'MinIO'
|
||||
if (id === 's3') return 'AWS S3'
|
||||
return t(`settings.storage.${id}Title`)
|
||||
}
|
||||
|
||||
const providerInitial = (id: StorageProviderId): string => {
|
||||
return providerTitle(id).trim().charAt(0).toUpperCase() || '?'
|
||||
}
|
||||
|
||||
const providerStatus = (id: StorageProviderId): { kind: 'on' | 'off'; label: string } => {
|
||||
if (id === 'minio' && !minioAvailable.value) {
|
||||
return { kind: 'off', label: t('settings.storage.needsConfig') }
|
||||
}
|
||||
if (id === 'local' || id === 'minio') {
|
||||
return { kind: 'on', label: t('settings.storage.available') }
|
||||
}
|
||||
return { kind: 'on', label: t('settings.storage.configurable') }
|
||||
}
|
||||
|
||||
function isProviderAllowed(provider: string) {
|
||||
if (allowedProviders.value === null) return true
|
||||
return allowedProviders.value.includes(provider)
|
||||
@@ -1106,53 +1075,150 @@ onMounted(loadAll)
|
||||
|
||||
.engine-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
||||
gap: 16px;
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
gap: 12px;
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
// 与 Parser / Model / WebSearch / Mcp 一致的卡片样式 —— 整张是 button,
|
||||
// 单击打开抽屉;active 是「当前正在编辑」的语义而不是「默认引擎」。
|
||||
.engine-card {
|
||||
border: 1px solid var(--td-component-stroke);
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
background: var(--td-bg-color-container);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
padding: 14px 14px 14px 12px;
|
||||
border: 1px solid var(--td-component-stroke);
|
||||
border-radius: 10px;
|
||||
background: var(--td-bg-color-container);
|
||||
text-align: left;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.18s ease, box-shadow 0.18s ease, background-color 0.18s ease;
|
||||
min-width: 0;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--td-brand-color);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
border-color: var(--td-brand-color-3, var(--td-brand-color));
|
||||
box-shadow: 0 4px 14px rgba(15, 23, 42, 0.06);
|
||||
}
|
||||
|
||||
&.active {
|
||||
&--active {
|
||||
border-color: var(--td-brand-color);
|
||||
background: rgba(var(--td-brand-color-5-rgba), 0.05);
|
||||
background: var(--td-brand-color-1, rgba(7, 192, 95, 0.06));
|
||||
}
|
||||
}
|
||||
|
||||
.engine-card-header {
|
||||
.engine-card__badge {
|
||||
flex-shrink: 0;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 9px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
justify-content: center;
|
||||
margin-top: 1px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
background: rgba(0, 82, 217, 0.1);
|
||||
color: #0052D9;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: var(--td-text-color-primary);
|
||||
margin: 0;
|
||||
font-family: var(--app-font-family-mono);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
// 各对象存储徽章配色 —— 和 LOGO 主色对齐,但走低饱和版以维持 settings 整体调性。
|
||||
.engine-card--local .engine-card__badge {
|
||||
background: rgba(70, 70, 70, 0.1);
|
||||
color: #464646;
|
||||
}
|
||||
.engine-card--minio .engine-card__badge {
|
||||
background: rgba(225, 38, 38, 0.12);
|
||||
color: #C0382B;
|
||||
}
|
||||
.engine-card--cos .engine-card__badge {
|
||||
background: rgba(0, 82, 217, 0.1);
|
||||
color: #0052D9;
|
||||
}
|
||||
.engine-card--tos .engine-card__badge {
|
||||
background: rgba(0, 137, 255, 0.12);
|
||||
color: #0089FF;
|
||||
}
|
||||
.engine-card--s3 .engine-card__badge {
|
||||
background: rgba(255, 153, 0, 0.12);
|
||||
color: #D97706;
|
||||
}
|
||||
.engine-card--oss .engine-card__badge {
|
||||
background: rgba(255, 90, 0, 0.12);
|
||||
color: #E55A00;
|
||||
}
|
||||
.engine-card--ks3 .engine-card__badge {
|
||||
background: rgba(7, 192, 95, 0.12);
|
||||
color: #07A050;
|
||||
}
|
||||
.engine-card--obs .engine-card__badge {
|
||||
background: rgba(206, 17, 38, 0.1);
|
||||
color: #CE1126;
|
||||
}
|
||||
|
||||
.engine-card__body {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.engine-card__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.engine-card__title {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
color: var(--td-text-color-primary);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.engine-card__status {
|
||||
flex-shrink: 0;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 1px 8px 1px 6px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
line-height: 16px;
|
||||
border-radius: 10px;
|
||||
background: var(--td-bg-color-secondarycontainer);
|
||||
|
||||
&--on {
|
||||
color: var(--td-success-color-7, #118053);
|
||||
|
||||
.engine-card__status-dot { background: var(--td-success-color, #118053); }
|
||||
}
|
||||
|
||||
&--off {
|
||||
color: var(--td-text-color-placeholder);
|
||||
|
||||
.engine-card__status-dot { background: var(--td-gray-color-5); }
|
||||
}
|
||||
}
|
||||
|
||||
.engine-card-desc {
|
||||
font-size: 13px;
|
||||
.engine-card__status-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.engine-card__desc {
|
||||
font-size: 12px;
|
||||
color: var(--td-text-color-secondary);
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
|
||||
Reference in New Issue
Block a user