refactor(web): 重构英雄管理页面布局与交互

1. 将原侧边栏选择改为卡片列表首页视图,新增顶部计数和新建按钮
2. 重新设计英雄列表项,展示基础信息、属性、技能和触发效果
3. 重构编辑弹窗布局,适配移动端并优化交互流程
4. 新增多项数据展示辅助函数,优化页面信息展示
This commit is contained in:
pan
2026-09-04 11:01:18 +08:00
parent bf154a5bfd
commit 4e0ef5bccc
3 changed files with 330 additions and 140 deletions

View File

@@ -1,4 +1,4 @@
import { v3 } from "cc" import { v3 } from "cc"
import { BoxSet, FacSet, FightSet } from "./GameSet" import { BoxSet, FacSet, FightSet } from "./GameSet"
import { SkillOverrides, TGroup, SkillSet, FieldSkillSet, SkillConfig, SkillKind, FieldSkillConfig, FieldSkillType, mergeSkillParams } from "./SkillSet" import { SkillOverrides, TGroup, SkillSet, FieldSkillSet, SkillConfig, SkillKind, FieldSkillConfig, FieldSkillType, mergeSkillParams } from "./SkillSet"
import { BuffList, BuffConfig, ModOp } from "./BuffSet" import { BuffList, BuffConfig, ModOp } from "./BuffSet"

View File

@@ -10,138 +10,177 @@
</div> </div>
</header> </header>
<div class="hero-main"> <div class="hero-main">
<!-- 英雄选择工具栏:下拉选择,适配手机竖屏 --> <!-- 首页:英雄卡片列表 -->
<div class="hero-toolbar"> <div class="home-toolbar">
<el-select <span class="muted">共 {{ heroes.length }} 个英雄</span>
v-model="activeIdx" <el-button size="small" type="primary" @click="addHero">+ 新建英雄</el-button>
class="hero-select"
:placeholder="`选择英雄(共 ${heroes.length} 个)`"
filterable
:disabled="!heroes.length"
>
<el-option v-for="(h, i) in heroes" :key="i" :label="`${h.uuid} ${h.name || '(未命名)'}`" :value="i">
<span>{{ h.uuid }} {{ h.name || '(未命名)' }}</span>
<span class="hero-option-meta">{{ roleLabel(h.roleKey) }} · {{ typeLabel(h.typeKey) }} · ★{{ h.rarity }}</span>
</el-option>
</el-select>
<el-button type="primary" @click="addHero">+ 新增</el-button>
<el-button type="danger" plain :disabled="activeIdx < 0" @click="removeHero(activeIdx)">删当前</el-button>
</div> </div>
<section class="hero-editor" v-if="current"> <section class="hero-rows">
<!-- 基础属性 --> <div v-if="!heroes.length" class="empty">暂无英雄,点击右上角「新建英雄」开始配置</div>
<div class="panel"> <div v-for="(h, i) in heroes" :key="h.uuid" class="hero-row" @click="openEdit(i)">
<h3>基础属性</h3> <div class="row-main">
<div class="form-grid"> <span class="row-uuid">{{ h.uuid }}</span>
<el-form-item label="uuid"> <span class="row-name">{{ h.name || '(未命名)' }}</span>
<el-input-number v-model="current.uuid" :min="5001" :controls="false" style="width: 100%" /> <span class="card-rarity">{{ '★'.repeat(h.rarity) }}</span>
</el-form-item> </div>
<el-form-item label="名称"> <div class="row-meta">
<el-input v-model="current.name" /> <template v-if="heroStats(h)">
</el-form-item> <span class="stat">HP {{ heroStats(h).hp }}</span>
<el-form-item label="资源路径 path"> <span class="stat">AP {{ heroStats(h).ap }}</span>
<el-input v-model="current.path" placeholder="hm1 / hk2 ..." /> <span class="stat">DEF {{ heroStats(h).def }}</span>
</el-form-item> </template>
<el-form-item label="品质 rarity"> </div>
<el-select v-model="current.rarity"> <div class="row-skills">
<el-option v-for="n in 5" :key="n" :label="`${n} 星`" :value="n" /> <div class="row-skill">
</el-select> <span class="tag">普攻</span>{{ skillLabel(h.skills?.[0]) }}
</el-form-item> <span class="skill-detail">{{ skillDetail(h.skills?.[0]) }}</span>
<el-form-item label="职业 role"> </div>
<el-select v-model="current.roleKey"> <div class="row-skill">
<el-option v-for="r in HERO_ROLES" :key="r.key" :label="r.label" :value="r.key" /> <span class="tag">大招</span>{{ skillLabel(h.skills?.[1]) }}
</el-select> <span class="skill-detail">{{ skillDetail(h.skills?.[1]) }}</span>
</el-form-item> </div>
<el-form-item label="成长 grow_type"> </div>
<el-select v-model="current.growKey"> <div class="row-triggers" v-if="hasTriggers(h) || fieldSummary(h).length">
<el-option v-for="g in GROW_TYPES" :key="g.key" :label="g.label" :value="g.key" /> <span v-if="fieldSummary(h).length" class="trigger-chip aura">光环: {{ fieldSummary(h).join(';') }}</span>
</el-select> <span v-for="line in triggerSummary(h)" :key="line" class="trigger-chip">{{ line }}</span>
</el-form-item> <span v-if="bonusCount(h)" class="trigger-chip">加成: ×{{ bonusCount(h) }}</span>
<el-form-item label="形态 type"> </div>
<el-select v-model="current.typeKey"> <div class="row-comment" v-if="h.comment || h.info">{{ h.comment || h.info }}</div>
<el-option v-for="t in H_TYPES" :key="t.key" :label="t.label" :value="t.key" /> <div class="row-actions" @click.stop>
</el-select> <el-button size="small" type="primary" @click="openEdit(i)">修改</el-button>
</el-form-item> <el-button size="small" type="danger" plain @click="removeHero(i)">删除</el-button>
<el-form-item label="攻击距离 dis(可选)">
<el-input-number v-model="current.dis" :min="0" :controls="false" style="width: 100%" placeholder="默认按形态" />
</el-form-item>
<el-form-item label="hp 偏移">
<el-input-number v-model="current.statBase.hp" :controls="false" style="width: 100%" />
</el-form-item>
<el-form-item label="ap 偏移">
<el-input-number v-model="current.statBase.ap" :controls="false" style="width: 100%" />
</el-form-item>
<el-form-item label="def 偏移">
<el-input-number v-model="current.statBase.def" :controls="false" style="width: 100%" />
</el-form-item>
<el-form-item label="注释">
<el-input v-model="current.comment" placeholder="导出文件中显示在条目上方" />
</el-form-item>
</div> </div>
<div class="muted">基础值 = HERO_ROLE_BASE[{{ current.roleKey }}] → hp {{ roleBase?.hp }} / ap {{ roleBase?.ap }} / def {{ roleBase?.def }}</div>
</div>
<!-- 普攻 -->
<div class="panel">
<h3>普攻 skills[0]</h3>
<SkillEditor v-if="basicSkill" :skill="basicSkill" :options="basicSkillOptions" />
<el-button v-else size="small" type="primary" @click="addBasicSkill">+ 添加普攻</el-button>
</div>
<!-- 大招 -->
<div class="panel">
<h3>大招 skills[1]</h3>
<SkillEditor v-if="ultSkill" :skill="ultSkill" :options="ultSkillOptions" :is-ult="true" />
<el-button v-else size="small" type="primary" @click="addUltSkill">+ 添加大招</el-button>
</div>
<!-- 触发技能 -->
<div class="panel">
<h3>触发技能(lv4 激活)</h3>
<el-tabs>
<el-tab-pane label="atking 攻击后"><TriggerGroupEditor :model="current.atking" :skill-options="allSkills" :skill-map="skillMap" /></el-tab-pane>
<el-tab-pane label="atked 受击后"><TriggerGroupEditor :model="current.atked" :skill-options="allSkills" :skill-map="skillMap" /></el-tab-pane>
<el-tab-pane label="fstart 战斗开始"><TriggerGroupEditor :model="current.fstart" :skill-options="allSkills" :skill-map="skillMap" /></el-tab-pane>
<el-tab-pane label="dead 死亡后"><TriggerGroupEditor :model="current.dead" :skill-options="allSkills" :skill-map="skillMap" /></el-tab-pane>
</el-tabs>
</div>
<!-- 光环 -->
<div class="panel">
<h3>驻场光环 field</h3>
<FieldEditor :model="current.field" :field-options="fieldOptions" />
</div>
<!-- 复活已纳入 dead 触发组,通过 dead 编辑器的 overrides 配置 revive_hp / revive_count -->
<div class="panel">
<h3>复活配置(dead 触发组内)</h3>
<el-alert type="info" :closable="false" show-icon style="margin-bottom: 10px">
复活已纳入 dead 触发组:在 dead 中添加技能(如 6501),并在 overrides 中配置 revive_hp(回血比例%)和 revive_count(次数上限)。
</el-alert>
</div>
<!-- 额外加成 -->
<div class="panel">
<h3>额外属性加成</h3>
<el-tabs>
<el-tab-pane label="ap_bonus"><BonusEditor :model="current.ap_bonus" /></el-tab-pane>
<el-tab-pane label="hp_bonus"><BonusEditor :model="current.hp_bonus" /></el-tab-pane>
<el-tab-pane label="def_bonus"><BonusEditor :model="current.def_bonus" /></el-tab-pane>
</el-tabs>
</div>
<!-- 描述 -->
<div class="panel">
<h3>英雄描述 info</h3>
<el-input v-model="current.info" type="textarea" :rows="3" />
</div> </div>
</section> </section>
<section v-else class="hero-editor"><div class="empty">请先选择或新增英雄</div></section>
<!-- 编辑弹窗 -->
<el-dialog
v-model="editVisible"
:title="`编辑英雄 ${current?.uuid || ''} ${current?.name || ''}`"
width="94%"
top="3vh"
class="editor-dialog"
:close-on-click-modal="false"
>
<section class="hero-editor" v-if="current">
<!-- 基础属性 -->
<div class="panel">
<h3>基础属性</h3>
<div class="form-grid">
<el-form-item label="uuid">
<el-input-number v-model="current.uuid" :min="5001" :controls="false" style="width: 100%" />
</el-form-item>
<el-form-item label="名称">
<el-input v-model="current.name" />
</el-form-item>
<el-form-item label="资源路径 path">
<el-input v-model="current.path" placeholder="hm1 / hk2 ..." />
</el-form-item>
<el-form-item label="品质 rarity">
<el-select v-model="current.rarity">
<el-option v-for="n in 5" :key="n" :label="`${n} 星`" :value="n" />
</el-select>
</el-form-item>
<el-form-item label="职业 role">
<el-select v-model="current.roleKey">
<el-option v-for="r in HERO_ROLES" :key="r.key" :label="r.label" :value="r.key" />
</el-select>
</el-form-item>
<el-form-item label="成长 grow_type">
<el-select v-model="current.growKey">
<el-option v-for="g in GROW_TYPES" :key="g.key" :label="g.label" :value="g.key" />
</el-select>
</el-form-item>
<el-form-item label="形态 type">
<el-select v-model="current.typeKey">
<el-option v-for="t in H_TYPES" :key="t.key" :label="t.label" :value="t.key" />
</el-select>
</el-form-item>
<el-form-item label="攻击距离 dis(可选)">
<el-input-number v-model="current.dis" :min="0" :controls="false" style="width: 100%" placeholder="默认按形态" />
</el-form-item>
<el-form-item label="hp 偏移">
<el-input-number v-model="current.statBase.hp" :controls="false" style="width: 100%" />
</el-form-item>
<el-form-item label="ap 偏移">
<el-input-number v-model="current.statBase.ap" :controls="false" style="width: 100%" />
</el-form-item>
<el-form-item label="def 偏移">
<el-input-number v-model="current.statBase.def" :controls="false" style="width: 100%" />
</el-form-item>
<el-form-item label="注释">
<el-input v-model="current.comment" placeholder="导出文件中显示在条目上方" />
</el-form-item>
</div>
<div class="muted">基础值 = HERO_ROLE_BASE[{{ current.roleKey }}] → hp {{ roleBase?.hp }} / ap {{ roleBase?.ap }} / def {{ roleBase?.def }}</div>
</div>
<!-- 普攻 -->
<div class="panel">
<h3>普攻 skills[0]</h3>
<SkillEditor v-if="basicSkill" :skill="basicSkill" :options="basicSkillOptions" />
<el-button v-else size="small" type="primary" @click="addBasicSkill">+ 添加普攻</el-button>
</div>
<!-- 大招 -->
<div class="panel">
<h3>大招 skills[1]</h3>
<SkillEditor v-if="ultSkill" :skill="ultSkill" :options="ultSkillOptions" :is-ult="true" />
<el-button v-else size="small" type="primary" @click="addUltSkill">+ 添加大招</el-button>
</div>
<!-- 触发技能 -->
<div class="panel">
<h3>触发技能(lv4 激活)</h3>
<el-tabs>
<el-tab-pane label="atking 攻击后"><TriggerGroupEditor :model="current.atking" :skill-options="allSkills" :skill-map="skillMap" /></el-tab-pane>
<el-tab-pane label="atked 受击后"><TriggerGroupEditor :model="current.atked" :skill-options="allSkills" :skill-map="skillMap" /></el-tab-pane>
<el-tab-pane label="fstart 战斗开始"><TriggerGroupEditor :model="current.fstart" :skill-options="allSkills" :skill-map="skillMap" /></el-tab-pane>
<el-tab-pane label="dead 死亡后"><TriggerGroupEditor :model="current.dead" :skill-options="allSkills" :skill-map="skillMap" /></el-tab-pane>
</el-tabs>
</div>
<!-- 光环 -->
<div class="panel">
<h3>驻场光环 field</h3>
<FieldEditor :model="current.field" :field-options="fieldOptions" />
</div>
<!-- 复活已纳入 dead 触发组,通过 dead 编辑器的 overrides 配置 revive_hp / revive_count -->
<div class="panel">
<h3>复活配置(dead 触发组内)</h3>
<el-alert type="info" :closable="false" show-icon style="margin-bottom: 10px">
复活已纳入 dead 触发组:在 dead 中添加技能(如 6501),并在 overrides 中配置 revive_hp(回血比例%)和 revive_count(次数上限)。
</el-alert>
</div>
<!-- 额外加成 -->
<div class="panel">
<h3>额外属性加成</h3>
<el-tabs>
<el-tab-pane label="ap_bonus"><BonusEditor :model="current.ap_bonus" /></el-tab-pane>
<el-tab-pane label="hp_bonus"><BonusEditor :model="current.hp_bonus" /></el-tab-pane>
<el-tab-pane label="def_bonus"><BonusEditor :model="current.def_bonus" /></el-tab-pane>
</el-tabs>
</div>
<!-- 描述 -->
<div class="panel">
<h3>英雄描述 info</h3>
<el-input v-model="current.info" type="textarea" :rows="3" />
</div>
</section>
<template #footer>
<el-button size="small" type="danger" plain :disabled="activeIdx < 0" @click="removeHero(activeIdx)">删除当前英雄</el-button>
<el-button size="small" @click="editVisible = false">关闭</el-button>
</template>
</el-dialog>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, computed, onMounted, h } from 'vue' import { ref, computed, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { api } from './api' import { api } from './api'
import { import {
@@ -158,6 +197,8 @@ const heroes = ref([])
const activeIdx = ref(-1) const activeIdx = ref(-1)
const meta = ref(null) const meta = ref(null)
const loadingMeta = ref(false) const loadingMeta = ref(false)
// 编辑弹窗可见性:首页卡片点「修改/新建」打开,关闭仅收起不丢数据
const editVisible = ref(false)
const current = computed(() => heroes.value[activeIdx.value]) const current = computed(() => heroes.value[activeIdx.value])
@@ -191,6 +232,65 @@ const ultSkillOptions = computed(() => {
function roleLabel(key) { return HERO_ROLES.find((r) => r.key === key)?.label || key } function roleLabel(key) { return HERO_ROLES.find((r) => r.key === key)?.label || key }
function typeLabel(key) { return H_TYPES.find((t) => t.key === key)?.label || key } function typeLabel(key) { return H_TYPES.find((t) => t.key === key)?.label || key }
// 卡片技能摘要:优先引用处命名,其次回退 SkillSet 底座名
function skillLabel(sk) {
if (!sk) return '-'
return `${sk.uuid} ${sk.name || skillMap.value[sk.uuid]?.name || ''}`.trim()
}
// 技能数值摘要:关键 overrides 与成长档位上限(如 ap150 →lv16)
function skillDetail(sk) {
if (!sk) return ''
const parts = []
if (sk.overrides?.ap != null) parts.push(`ap${sk.overrides.ap}`)
if (sk.overrides?.timed_buff_id != null) parts.push(`buff${sk.overrides.timed_buff_id}`)
if (sk.overrides?.frz != null) parts.push(`frz${sk.overrides.frz}`)
if (sk.overrides?.stun != null) parts.push(`stun${sk.overrides.stun}`)
if (sk.overrides?.summon_count != null) parts.push(`数${sk.overrides.summon_count}`)
if (sk.lv_entries?.length) parts.push(`→lv${Math.max(...sk.lv_entries.map((e) => e.lv))}`)
return parts.join(' ')
}
// lv1 基础三维:HERO_ROLE_BASE + 编辑器偏移(meta 未加载时返回 null 不展示)
function heroStats(h) {
const roleEnum = HERO_ROLES.find((r) => r.key === h.roleKey)?.value
const base = meta.value?.HERO_ROLE_BASE?.[roleEnum]
if (!base) return null
return {
hp: base.hp + (h.statBase?.hp || 0),
ap: base.ap + (h.statBase?.ap || 0),
def: base.def + (h.statBase?.def || 0),
}
}
// 触发明细行:atking: 6004 奋力一击 lv4 格式,仅输出已启用的组
function triggerSummary(h) {
const lines = []
for (const tk of ['atking', 'atked', 'fstart', 'dead']) {
const grp = h[tk]
if (!grp) continue
for (const [sid, entries] of Object.entries(grp)) {
const minLv = Math.min(...entries.map((e) => e.lv))
const name = entries[0]?.name || skillMap.value[sid]?.name || ''
lines.push(`${tk}: ${sid} ${name} lv${minLv}`)
}
}
return lines
}
function hasTriggers(h) {
return ['atking', 'atked', 'fstart', 'dead'].some((k) => h[k] && Object.keys(h[k]).length)
}
// 光环明细行:lv4 · 大圣神威 0.25
function fieldSummary(h) {
if (!h.field?.length) return []
const fieldMap = meta.value?.FieldSkillSet || {}
return h.field.map((f) => {
const auras = f.uuids.map((u) => `${u.name || fieldMap[u.uuid]?.name || u.uuid} ${u.value}`).join('、')
return `lv${f.lv} · ${auras}`
})
}
// 额外加成条目总数(ap/hp/def_bonus 之和)
function bonusCount(h) {
return (h.ap_bonus?.length || 0) + (h.hp_bonus?.length || 0) + (h.def_bonus?.length || 0)
}
async function loadMeta() { async function loadMeta() {
loadingMeta.value = true loadingMeta.value = true
try { try {
@@ -211,6 +311,10 @@ async function refreshMeta() {
} }
} }
function openEdit(i) {
activeIdx.value = i
editVisible.value = true
}
function addHero() { function addHero() {
const nh = defaultHero() const nh = defaultHero()
const used = new Set(heroes.value.map((h) => h.uuid)) const used = new Set(heroes.value.map((h) => h.uuid))
@@ -218,11 +322,13 @@ function addHero() {
while (used.has(uuid)) uuid++ while (used.has(uuid)) uuid++
nh.uuid = uuid nh.uuid = uuid
heroes.value.push(nh) heroes.value.push(nh)
activeIdx.value = heroes.value.length - 1 openEdit(heroes.value.length - 1)
} }
function removeHero(i) { function removeHero(i) {
heroes.value.splice(i, 1) heroes.value.splice(i, 1)
if (activeIdx.value >= heroes.value.length) activeIdx.value = heroes.value.length - 1 if (activeIdx.value >= heroes.value.length) activeIdx.value = heroes.value.length - 1
// 删除后关闭弹窗回到首页
editVisible.value = false
} }
function addBasicSkill() { function addBasicSkill() {
@@ -257,7 +363,6 @@ async function loadHeroes() {
const r = await api.fetchHeroes() const r = await api.fetchHeroes()
if (Array.isArray(r.heroes) && r.heroes.length) { if (Array.isArray(r.heroes) && r.heroes.length) {
heroes.value = r.heroes heroes.value = r.heroes
activeIdx.value = 0
} }
} catch (e) { } catch (e) {
ElMessage.error('加载英雄数据失败: ' + (e?.response?.data?.error || e.message)) ElMessage.error('加载英雄数据失败: ' + (e?.response?.data?.error || e.message))

View File

@@ -60,27 +60,105 @@ body {
overflow: hidden; overflow: hidden;
} }
/* 英雄选择工具栏:下拉选择替代侧边栏列表,适配手机竖屏 */ /* 首页工具栏:计数 + 新建入口 */
.hero-toolbar { .home-toolbar {
display: flex; display: flex;
gap: 8px; gap: 8px;
align-items: center; align-items: center;
justify-content: space-between;
padding: 10px 14px; padding: 10px 14px;
background: var(--panel); background: var(--panel);
border-bottom: 1px solid var(--border); border-bottom: 1px solid var(--border);
flex-shrink: 0; flex-shrink: 0;
} }
.hero-toolbar .hero-select { flex: 1; min-width: 0; }
.hero-option-meta {
float: right;
font-size: 11px;
color: var(--text-light);
}
.hero-editor { /* 首页:一行一个英雄的列表布局 */
.hero-rows {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
padding: 16px 20px 40px; padding: 12px 16px 40px;
display: flex;
flex-direction: column;
gap: 8px;
}
.hero-row {
background: var(--panel);
border: 1px solid var(--border);
border-radius: 8px;
padding: 8px 12px;
cursor: pointer;
transition: box-shadow 0.15s;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 6px 14px;
font-size: 12px;
}
.hero-row:hover { box-shadow: 0 3px 12px rgba(46, 91, 160, 0.15); }
/* 行首:uuid + 名称 + 星级 */
.row-main { display: flex; align-items: center; gap: 8px; min-width: 130px; }
.row-uuid { font-family: Menlo, Consolas, monospace; color: var(--text-light); }
.row-name { font-size: 13px; font-weight: 600; }
.card-rarity { color: #f5a623; font-size: 11px; }
/* 三维徽章 */
.row-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 10px; }
.stat {
background: #f0f7ef;
color: #4a7c3f;
border-radius: 4px;
padding: 0 6px;
font-size: 11px;
line-height: 18px;
}
/* 技能段:普攻/大招两行 */
.row-skills { display: flex; flex-direction: column; gap: 2px; min-width: 200px; }
.skill-detail { color: var(--text-light); font-size: 11px; margin-left: 4px; }
/* 触发/光环/加成:chip 流式排布 */
.row-triggers { display: flex; flex-wrap: wrap; gap: 4px 6px; flex: 1; min-width: 160px; }
.trigger-chip {
background: #eef4fc;
color: var(--brand);
border-radius: 4px;
padding: 0 6px;
font-size: 11px;
line-height: 18px;
}
.trigger-chip.aura { background: #f4f0fa; color: #7c5cbf; }
.row-comment {
width: 100%;
color: var(--text-light);
font-size: 11px;
border-top: 1px dashed var(--border);
padding-top: 4px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.tag {
display: inline-block;
background: #eef4fc;
color: var(--brand);
border-radius: 4px;
padding: 0 5px;
margin-right: 6px;
font-size: 11px;
line-height: 18px;
}
/* 行尾操作按钮 */
.row-actions { display: flex; gap: 6px; margin-left: auto; }
/* 编辑弹窗:内容区内部滚动 */
.editor-dialog .el-dialog__body { max-height: 78vh; overflow-y: auto; padding: 8px 16px; }
.hero-editor {
padding: 4px 0 16px;
} }
.panel { .panel {
@@ -134,7 +212,7 @@ body {
padding: 60px 0; padding: 60px 0;
} }
/* 手机竖屏适配:头部按钮换行、表单单列、编辑区全宽滚动 */ /* 手机竖屏适配:头部按钮换行、行内信息自动折行、弹窗全宽 */
@media (max-width: 600px) { @media (max-width: 600px) {
.hero-header { .hero-header {
flex-wrap: wrap; flex-wrap: wrap;
@@ -142,9 +220,16 @@ body {
padding: 10px 12px; padding: 10px 12px;
} }
.hero-header .actions { flex-wrap: wrap; } .hero-header .actions { flex-wrap: wrap; }
.hero-editor { padding: 12px 12px 40px; } .hero-editor { padding: 4px 0 16px; }
.hero-toolbar { padding: 8px 10px; } .home-toolbar { padding: 8px 10px; }
.hero-toolbar .el-button { margin-left: 0; } .home-toolbar .el-button { margin-left: 0; }
.hero-rows { padding: 8px 10px 40px; }
.hero-row { gap: 4px 10px; }
.row-main { min-width: 0; }
.row-skills { min-width: 100%; }
.row-actions { margin-left: 0; }
.editor-dialog { width: 98% !important; }
.editor-dialog .el-dialog__body { max-height: 76vh; padding: 6px 10px; }
.form-grid { grid-template-columns: 1fr; } .form-grid { grid-template-columns: 1fr; }
.override-grid { grid-template-columns: 1fr; } .override-grid { grid-template-columns: 1fr; }
} }