feat(service-catalog): 对齐基础服务目录交互逻辑
- 更新 6 张服务卡片数据(Wayne/MySQL/openresty/PgSQL/Redis/接入新服务) - 容器服务(Wayne)点击打开发布弹窗(业务线/命名空间/集群/规格/服务名) - MySQL 点击打开标准化交付弹窗(架构/规格/版本/实例名 + YAML 预览) - openresty 可点击但提示"功能对接中" - PgSQL/Redis 置灰不可点击,提示"功能规划中" - 接入新服务置灰(0.5)无响应 - 弹窗确认后 toast 提示并跳转任务中心
This commit is contained in:
@@ -3,59 +3,304 @@
|
|||||||
<div class="page-head">
|
<div class="page-head">
|
||||||
<div>
|
<div>
|
||||||
<h1>基础服务目录</h1>
|
<h1>基础服务目录</h1>
|
||||||
<p>点击卡片,通过封装好的 ansible-playbook 一键部署标准化基础服务</p>
|
<p>点击卡片,通过封装好的 ansible-playbook 一键标准化交付,完成后自动注册进对应子系统</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="svc-grid">
|
<div class="svc-grid">
|
||||||
<div v-for="service in services" :key="service.name" class="svc-card" @click="handleDeploy(service)">
|
<div
|
||||||
|
v-for="service in services"
|
||||||
|
:key="service.name"
|
||||||
|
class="svc-card"
|
||||||
|
:class="{ disabled: service.disabled }"
|
||||||
|
:style="service.disabled ? { opacity: service.opacity } : {}"
|
||||||
|
@click="handleCardClick(service)"
|
||||||
|
>
|
||||||
<div class="svc-top">
|
<div class="svc-top">
|
||||||
<div class="svc-ic" :style="{ background: service.bgColor, color: service.iconColor }">
|
<div class="svc-ic" :style="{ background: service.bgColor, color: service.iconColor }">
|
||||||
{{ service.icon }}
|
{{ service.icon }}
|
||||||
</div>
|
</div>
|
||||||
<h4>{{ service.name }}</h4>
|
<h4 :style="service.disabled && service.icon === '+' ? { color: 'var(--text-dim)' } : {}">{{ service.name }}</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="svc-desc">{{ service.description }}</div>
|
<div class="svc-desc">{{ service.description }}</div>
|
||||||
<div class="svc-foot">
|
<div class="svc-foot">
|
||||||
<span class="playbook">{{ service.playbook }}</span>
|
<span class="playbook">{{ service.playbook }}</span>
|
||||||
<span>{{ service.version }}</span>
|
<span :style="service.statusColor ? { color: service.statusColor } : {}">{{ service.version }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 弹窗:发布服务 · 跳 Wayne -->
|
||||||
|
<Teleport to="body">
|
||||||
|
<div v-if="showWayneModal" class="overlay" @click.self="showWayneModal = false">
|
||||||
|
<div class="modal">
|
||||||
|
<div class="modal-head">
|
||||||
|
<h3>发布服务 · 跳 Wayne</h3>
|
||||||
|
<button class="close" @click="showWayneModal = false">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="field-row">
|
||||||
|
<div class="field">
|
||||||
|
<label>业务线</label>
|
||||||
|
<select v-model="wayneForm.bl">
|
||||||
|
<option value="las">las(当前)</option>
|
||||||
|
<option value="kodo">kodo</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>命名空间</label>
|
||||||
|
<select v-model="wayneForm.namespace">
|
||||||
|
<option value="ns-las-prod">ns-las-prod</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field-row">
|
||||||
|
<div class="field">
|
||||||
|
<label>目标集群</label>
|
||||||
|
<select v-model="wayneForm.cluster">
|
||||||
|
<option value="rke2-sh-prod-01">rke2-sh-prod-01(华东)</option>
|
||||||
|
<option value="rke2-bj-prod-01">rke2-bj-prod-01(华北)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>规格</label>
|
||||||
|
<select v-model="wayneForm.spec">
|
||||||
|
<option value="2C4G">2C 4G × 3 副本</option>
|
||||||
|
<option value="4C8G">4C 8G × 3 副本</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>服务名称</label>
|
||||||
|
<input v-model="wayneForm.serviceName" placeholder="las-search-api" />
|
||||||
|
</div>
|
||||||
|
<div class="tooltip-note">
|
||||||
|
凭 SSO 身份免登进入 <b>Wayne</b>,在 ns-las-prod 下部署服务;权限随业务线 / 角色自动具备,仅可操作被授权 namespace。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-foot">
|
||||||
|
<button class="btn btn-ghost" @click="showWayneModal = false">取消</button>
|
||||||
|
<button class="btn btn-primary" @click="handleWayneSubmit">跳 Wayne 发布 ↗</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
|
|
||||||
|
<!-- 弹窗:数据库标准化交付 · MySQL -->
|
||||||
|
<Teleport to="body">
|
||||||
|
<div v-if="showMysqlModal" class="overlay" @click.self="showMysqlModal = false">
|
||||||
|
<div class="modal">
|
||||||
|
<div class="modal-head">
|
||||||
|
<h3>数据库标准化交付 · MySQL</h3>
|
||||||
|
<button class="close" @click="showMysqlModal = false">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="field-row">
|
||||||
|
<div class="field">
|
||||||
|
<label>业务线</label>
|
||||||
|
<select v-model="mysqlForm.bl">
|
||||||
|
<option value="las">las(当前)</option>
|
||||||
|
<option value="kodo">kodo</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>架构模式</label>
|
||||||
|
<select v-model="mysqlForm.topology">
|
||||||
|
<option value="1m2r">一主两从</option>
|
||||||
|
<option value="1m1r">一主一从</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field-row">
|
||||||
|
<div class="field">
|
||||||
|
<label>规格</label>
|
||||||
|
<select v-model="mysqlForm.spec">
|
||||||
|
<option value="8C32G">8C 32G · 500G SSD(Ceph RBD)</option>
|
||||||
|
<option value="16C64G">16C 64G · 1T SSD</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>版本</label>
|
||||||
|
<select v-model="mysqlForm.version">
|
||||||
|
<option value="8.0.36">MySQL 8.0.36</option>
|
||||||
|
<option value="5.7.44">MySQL 5.7.44</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>实例名称</label>
|
||||||
|
<input v-model="mysqlForm.instanceName" placeholder="mysql-las-billing-02" />
|
||||||
|
</div>
|
||||||
|
<div class="yaml-preview"><span class="c"># ansible-runner 调用预览</span>
|
||||||
|
<span class="k">playbook</span>: roles/mysql-deploy
|
||||||
|
<span class="k">tenant</span>: <span class="s">{{ mysqlForm.bl }}</span>
|
||||||
|
<span class="k">topology</span>: <span class="s">{{ mysqlForm.topology === '1m2r' ? '1-master-2-replica' : '1-master-1-replica' }}</span>
|
||||||
|
<span class="k">node_selector</span>: <span class="s">business-line={{ mysqlForm.bl }}</span>
|
||||||
|
<span class="k">storage_class</span>: <span class="s">ceph-rbd-ssd</span>
|
||||||
|
<span class="k">register_to</span>: <span class="s">clouddm</span> <span class="c"># 自动注册数据源,跳 CloudDM 上线</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-foot">
|
||||||
|
<button class="btn btn-ghost" @click="showMysqlModal = false">取消</button>
|
||||||
|
<button class="btn btn-primary" @click="handleMysqlSubmit">确认交付</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref, reactive } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
const services = ref([
|
const router = useRouter()
|
||||||
{ name: 'MySQL', icon: 'My', bgColor: 'var(--tag-blue-bg)', iconColor: 'var(--tag-blue-text)', description: '一主多从,自动注册进 open-cdm 数据源,支持 LDAP 账号统一审核 SQL 上线。', playbook: 'roles/mysql-deploy', version: 'v8.0.36' },
|
|
||||||
{ name: 'Redis', icon: 'Rd', bgColor: 'var(--logo-cc-bg)', iconColor: 'var(--err)', description: '支持 Standalone / Sentinel / Cluster,部署完成后自动注册进 CacheCloud。', playbook: 'roles/redis-deploy', version: 'v7.2' },
|
interface Service {
|
||||||
{ name: 'openresty', icon: 'Or', bgColor: 'var(--logo-dm-bg)', iconColor: 'var(--tag-green-text)', description: '容器化部署在 K8s 内,作为业务边缘网关,支持灰度路由配置。', playbook: 'roles/openresty-deploy', version: 'v1.25' },
|
name: string
|
||||||
{ name: 'dpvs', icon: 'Dp', bgColor: 'var(--logo-qp-bg)', iconColor: 'var(--tag-amber-text)', description: '四层负载均衡,直接管理宿主机网络命名空间,不纳入容器编排。', playbook: 'roles/dpvs-deploy', version: 'v1.9' },
|
icon: string
|
||||||
{ name: 'PgSQL', icon: 'Pg', bgColor: 'var(--tag-purple-bg)', iconColor: 'var(--tag-purple-text)', description: '流复制主从架构,规划中 · 第二期接入 open-cdm 统一审核体系。', playbook: 'roles/pgsql-deploy', version: '规划中' },
|
bgColor: string
|
||||||
|
iconColor: string
|
||||||
|
description: string
|
||||||
|
playbook: string
|
||||||
|
version: string
|
||||||
|
statusColor?: string
|
||||||
|
disabled?: boolean
|
||||||
|
opacity?: number
|
||||||
|
modal?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const services = ref<Service[]>([
|
||||||
|
{
|
||||||
|
name: '容器服务(Wayne)',
|
||||||
|
icon: 'Wy',
|
||||||
|
bgColor: '#1C2A3A',
|
||||||
|
iconColor: '#7FB8FF',
|
||||||
|
description: '在 RKE2 容器池标准发布业务服务,跳 Wayne 免登管理多集群与命名空间。',
|
||||||
|
playbook: 'wayne · ns-las-prod',
|
||||||
|
version: '',
|
||||||
|
modal: 'wayne',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'MySQL',
|
||||||
|
icon: 'My',
|
||||||
|
bgColor: '#1C2E4A',
|
||||||
|
iconColor: '#7FB8FF',
|
||||||
|
description: '一主多从标准化交付,完成后自动注册进 CloudDM / open-cdm 数据源,统一审核 SQL 上线。',
|
||||||
|
playbook: 'roles/mysql-deploy',
|
||||||
|
version: 'v8.0.36',
|
||||||
|
modal: 'mysql',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'openresty',
|
||||||
|
icon: 'Or',
|
||||||
|
bgColor: '#1C3A2E',
|
||||||
|
iconColor: '#7FFFC2',
|
||||||
|
description: '容器化部署在 K8s 内,作为业务边缘网关,支持灰度路由配置。',
|
||||||
|
playbook: 'roles/openresty-deploy',
|
||||||
|
version: 'v1.25',
|
||||||
|
modal: 'openresty',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'PgSQL',
|
||||||
|
icon: 'Pg',
|
||||||
|
bgColor: '#2E1C3A',
|
||||||
|
iconColor: '#C9A6FF',
|
||||||
|
description: '流复制主从架构,规划中 · 接入 CloudDM 统一审核体系。',
|
||||||
|
playbook: 'roles/pgsql-deploy',
|
||||||
|
version: '规划中',
|
||||||
|
statusColor: 'var(--text-dim)',
|
||||||
|
disabled: true,
|
||||||
|
opacity: 0.8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Redis',
|
||||||
|
icon: 'Rd',
|
||||||
|
bgColor: '#3A1C28',
|
||||||
|
iconColor: '#FF8E9C',
|
||||||
|
description: 'Redis 管理由 CacheCloud 承载,规划接入后开放标准化交付。',
|
||||||
|
playbook: 'CacheCloud',
|
||||||
|
version: '规划接入',
|
||||||
|
disabled: true,
|
||||||
|
opacity: 0.6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '接入新服务',
|
||||||
|
icon: '+',
|
||||||
|
bgColor: '#262C38',
|
||||||
|
iconColor: 'var(--text-dim)',
|
||||||
|
description: '封装新的 ansible-playbook,注册进基础服务目录',
|
||||||
|
playbook: '',
|
||||||
|
version: '',
|
||||||
|
disabled: true,
|
||||||
|
opacity: 0.5,
|
||||||
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
const handleDeploy = (service: any) => {
|
// 弹窗状态
|
||||||
ElMessage.success(`${service.name} 部署任务已提交`)
|
const showWayneModal = ref(false)
|
||||||
|
const showMysqlModal = ref(false)
|
||||||
|
|
||||||
|
const wayneForm = reactive({
|
||||||
|
bl: 'las',
|
||||||
|
namespace: 'ns-las-prod',
|
||||||
|
cluster: 'rke2-sh-prod-01',
|
||||||
|
spec: '2C4G',
|
||||||
|
serviceName: 'las-search-api',
|
||||||
|
})
|
||||||
|
|
||||||
|
const mysqlForm = reactive({
|
||||||
|
bl: 'las',
|
||||||
|
topology: '1m2r',
|
||||||
|
spec: '8C32G',
|
||||||
|
version: '8.0.36',
|
||||||
|
instanceName: 'mysql-las-billing-02',
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleCardClick = (service: Service) => {
|
||||||
|
if (service.disabled) {
|
||||||
|
if (service.name === '接入新服务') return
|
||||||
|
ElMessage.warning(`${service.name} 功能规划中,敬请期待`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (service.modal === 'wayne') {
|
||||||
|
showWayneModal.value = true
|
||||||
|
} else if (service.modal === 'mysql') {
|
||||||
|
showMysqlModal.value = true
|
||||||
|
} else if (service.modal === 'openresty') {
|
||||||
|
ElMessage.info('openresty 部署功能对接中,敬请期待')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleWayneSubmit = () => {
|
||||||
|
showWayneModal.value = false
|
||||||
|
ElMessage.success('已跳转 Wayne 并提交发布任务')
|
||||||
|
router.push({ name: 'Tasks' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMysqlSubmit = () => {
|
||||||
|
showMysqlModal.value = false
|
||||||
|
ElMessage.success('MySQL 标准化交付已提交,完成后自动注册 CloudDM')
|
||||||
|
router.push({ name: 'Tasks' })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
/* .page-head, .svc-grid 已在 global.css 中定义 */
|
|
||||||
|
|
||||||
.svc-card {
|
.svc-card {
|
||||||
background: var(--bg-panel);
|
background: var(--bg-panel);
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
border-radius: var(--radius-lg);
|
border-radius: 8px;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: border-color 0.15s;
|
transition: border-color 0.15s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.svc-card:hover {
|
.svc-card:hover:not(.disabled) {
|
||||||
border-color: var(--hover-border);
|
border-color: #3A4356;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svc-card.disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.svc-top {
|
.svc-top {
|
||||||
@@ -102,4 +347,183 @@ h4 {
|
|||||||
font-family: var(--mono);
|
font-family: var(--mono);
|
||||||
color: var(--text-mid);
|
color: var(--text-mid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ========== overlay / modal ========== */
|
||||||
|
.overlay {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(7, 9, 13, 0.72);
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 50;
|
||||||
|
padding-top: 6vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
width: 560px;
|
||||||
|
max-width: 92vw;
|
||||||
|
background: var(--bg-panel);
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 16px 18px;
|
||||||
|
border-bottom: 1px solid var(--line-soft, var(--line));
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-head h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 14.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-head .close {
|
||||||
|
margin-left: auto;
|
||||||
|
color: var(--text-dim);
|
||||||
|
font-size: 18px;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 4px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
padding: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-foot {
|
||||||
|
padding: 14px 18px;
|
||||||
|
border-top: 1px solid var(--line-soft, var(--line));
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== form fields ========== */
|
||||||
|
.field {
|
||||||
|
margin-bottom: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field label {
|
||||||
|
display: block;
|
||||||
|
font-size: 11.5px;
|
||||||
|
color: var(--text-dim);
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field select,
|
||||||
|
.field input {
|
||||||
|
width: 100%;
|
||||||
|
background: var(--bg-panel-2, var(--bg-panel));
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
color: var(--text-hi);
|
||||||
|
font-size: 12.5px;
|
||||||
|
font-family: var(--sans, inherit);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field select:focus,
|
||||||
|
.field input:focus {
|
||||||
|
border-color: var(--accent-dim, var(--accent));
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== yaml preview ========== */
|
||||||
|
.yaml-preview {
|
||||||
|
background: #0B0D12;
|
||||||
|
border: 1px solid var(--line-soft, var(--line));
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 11.5px;
|
||||||
|
color: #8EC8FF;
|
||||||
|
line-height: 1.7;
|
||||||
|
white-space: pre;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yaml-preview .k {
|
||||||
|
color: #7FB8FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yaml-preview .s {
|
||||||
|
color: #FFC97A;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yaml-preview .c {
|
||||||
|
color: var(--text-dim);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== tooltip note ========== */
|
||||||
|
.tooltip-note {
|
||||||
|
background: #0F261D;
|
||||||
|
border: 1px solid var(--accent-dim, var(--accent));
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-mid);
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-note b {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== buttons ========== */
|
||||||
|
.btn {
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
background: var(--bg-panel-2, var(--bg-panel));
|
||||||
|
color: var(--text-hi);
|
||||||
|
padding: 8px 14px;
|
||||||
|
font-size: 12.5px;
|
||||||
|
font-weight: 500;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover {
|
||||||
|
border-color: #3A4356;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background: var(--accent);
|
||||||
|
border-color: var(--accent);
|
||||||
|
color: #06150F;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
background: #55E8B3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-ghost {
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text-mid);
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-ghost:hover {
|
||||||
|
color: var(--text-hi);
|
||||||
|
background: var(--bg-panel-2, var(--bg-panel));
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user