设为基准
清空基准
@@ -54,6 +57,13 @@ const configStore = useConfigStore()
const infoStore = useInfoStore()
const type = ref<'equ' | 'oath'>('equ')
+withDefaults(
+ defineProps<{
+ showOverview?: boolean
+ }>(),
+ { showOverview: true },
+)
+
const setStandard = () => {
if (!configStore?.result?.state?.uuid) return
infoStore.setStandard(configStore.result.state, configStore.skillCountConfig)
@@ -68,20 +78,22 @@ const clearStandard = () => {
.result-shell {
position: relative;
display: grid;
- width: calc(
- var(--ui-character-result-info-inline-size) + var(--ui-character-result-summary-inline-size) +
- var(--ui-character-result-toggle-inline-size)
- );
+ width: 100%;
min-width: 0;
height: 100%;
min-height: 0;
grid-template-columns:
var(--ui-character-result-info-inline-size)
- var(--ui-character-result-summary-inline-size);
+ minmax(0, 1fr);
gap: var(--ui-character-result-toggle-inline-size);
overflow: visible;
}
+.result-shell--without-overview {
+ grid-template-columns: minmax(0, 1fr);
+ gap: 0;
+}
+
.result-overview {
display: grid;
min-width: 0;
@@ -109,15 +121,18 @@ const clearStandard = () => {
min-height: 0;
}
-@media (min-width: 1600px) {
+@media (min-width: 1180px) {
.result-shell {
- width: calc(
- var(--ui-character-result-info-inline-size) + var(--ui-character-result-full-inline-size) +
- var(--ui-character-workspace-gap)
- );
- grid-template-columns:
- var(--ui-character-result-info-inline-size)
- var(--ui-character-result-full-inline-size);
+ gap: var(--ui-character-workspace-gap);
+ }
+}
+
+@media (max-width: 900px) {
+ .result-shell {
+ height: 100%;
+ min-height: 100%;
+ grid-template-columns: minmax(0, 1fr);
+ grid-template-rows: repeat(2, minmax(560px, 1fr));
gap: var(--ui-character-workspace-gap);
}
}
diff --git a/frontend-ui/src/pages/Character/Result/components/Skill.vue b/frontend-ui/src/pages/Character/Result/components/Skill.vue
index c3ed7a10..efa61893 100644
--- a/frontend-ui/src/pages/Character/Result/components/Skill.vue
+++ b/frontend-ui/src/pages/Character/Result/components/Skill.vue
@@ -118,7 +118,7 @@
@@ -126,166 +126,166 @@
@@ -293,6 +293,7 @@ function sortValue(key: SortKey) {
diff --git a/frontend-ui/src/pages/Character/Skill/components/SkillDetail/index.tsx b/frontend-ui/src/pages/Character/Skill/components/SkillDetail/index.tsx
index 447b621d..b5b7bb78 100644
--- a/frontend-ui/src/pages/Character/Skill/components/SkillDetail/index.tsx
+++ b/frontend-ui/src/pages/Character/Skill/components/SkillDetail/index.tsx
@@ -1,6 +1,7 @@
import { asyncComputed } from '@vueuse/core'
import api from '@/api'
import './style.scss'
+import { UiDataSection } from '@/components/ui/data-section'
import { TabsRoot, UiTabsList, UiTabsTrigger } from '@/components/ui/tabs'
export default defineComponent({
@@ -86,32 +87,48 @@ export default defineComponent({
const renderSkillDetail = () => (
<>
-
-
- {desc.value?.map((item) => (
- // item.startsWith('[') || item.startsWith('-') || item.startsWith('<') ? (
- //
{item}
- // ) :
-
{item}
- ))}
+
+
+ {basic.value.map(
+ (item) =>
+ !!item.value && (
+
+ {item.label}
+ {item.value}
+
+ ),
+ )}
-
+
+
+
+
+ {desc.value?.map((item) => (
+
{item}
+ ))}
+
+
+
{detail.value.length > 0 && (
- <>
-
技能属性
+
- >
+
)}
>
)
@@ -132,10 +149,17 @@ export default defineComponent({
<>
{item.name}
-
技能描述
-
+
+
+
>
))}
diff --git a/frontend-ui/src/pages/Character/Skill/components/SkillDetail/style.scss b/frontend-ui/src/pages/Character/Skill/components/SkillDetail/style.scss
index 5cc48bd9..843ea369 100644
--- a/frontend-ui/src/pages/Character/Skill/components/SkillDetail/style.scss
+++ b/frontend-ui/src/pages/Character/Skill/components/SkillDetail/style.scss
@@ -46,6 +46,29 @@
overflow-y: auto;
}
+.skill-detail__section {
+ flex: 0 0 auto;
+ border-color: #3e4040;
+}
+
+.skill-detail__section--grow {
+ min-height: 0;
+ flex: 1;
+}
+
+.skill-detail__section .ui-data-section__content {
+ min-height: 0;
+ padding: 0;
+}
+
+.skill-detail__section--grow .ui-data-section__content {
+ display: flex;
+ min-height: 0;
+ flex: 1;
+ flex-direction: column;
+ overflow: hidden;
+}
+
.skill-detail__evolution {
height: auto;
}
@@ -136,16 +159,6 @@
}
}
-.skill_title {
- border: 1px solid #3e4040;
- color: #c1a238;
- background: linear-gradient(180deg, #2b292b 0%, #0b0b0b 100%);
- height: 20px;
- display: flex;
- align-items: center;
- padding: 0px 5px;
-}
-
.item {
background-color: #171616;
padding: 0px 5px;
diff --git a/frontend-ui/src/pages/Character/Skill/components/SkillTree/img/extra_awake_85.png b/frontend-ui/src/pages/Character/Skill/components/SkillTree/img/extra_awake_85.png
new file mode 100644
index 00000000..8aafcaf6
Binary files /dev/null and b/frontend-ui/src/pages/Character/Skill/components/SkillTree/img/extra_awake_85.png differ
diff --git a/frontend-ui/src/pages/Character/Skill/components/SkillTree/index.tsx b/frontend-ui/src/pages/Character/Skill/components/SkillTree/index.tsx
index e4f00ba2..dc149119 100644
--- a/frontend-ui/src/pages/Character/Skill/components/SkillTree/index.tsx
+++ b/frontend-ui/src/pages/Character/Skill/components/SkillTree/index.tsx
@@ -1,13 +1,17 @@
-import { getImageURL } from '@/utils/images'
import type { ISkill } from '@/api/info/type'
-import { useVModel } from '@vueuse/core'
import { UiButton } from '@/components/ui/button'
+import { getImageURL } from '@/utils/images'
+import { useVModel } from '@vueuse/core'
import addIcon from './img/add.svg'
import maxIcon from './img/max.svg'
import minIcon from './img/min.svg'
import subIcon from './img/sub.svg'
import './style.scss'
+const rowPrefixes = ['通用', 1, '', 10, '', 20, '', 30, '', 40, 50, 60, 70, 80, 90, 100]
+const defaultColumnCount = 11
+const altersWithoutRowPrefix = new Set(['creator', 'dark_knight'])
+
export default defineComponent({
name: 'SkillTree',
props: {
@@ -21,269 +25,259 @@ export default defineComponent({
},
bindAwake: {
type: Number,
- default: () => 50,
+ default: 50,
+ },
+ alter: {
+ type: String,
+ default: '',
},
},
- emits: ['chooseSkill'],
+ emits: ['chooseSkill', 'update:lvInfo', 'update:bindAwake'],
setup(props, { emit }) {
- const skills = computed(() => props.skills)
const lvInfo = useVModel(props, 'lvInfo')
const bindAwake = useVModel(props, 'bindAwake')
- // const emit = defineEmits(['chooseSkill'])
+ const activeSkill = ref(-1)
- const getSkill = (lvStart: number, lvEnd: number, position: number) => {
- if (position >= 0)
- return skills.value.find(
- (item) =>
- item.line > lvStart - 5 &&
- item.line <= Math.max(lvEnd - 5, 1) &&
- item.position == position,
- )
- else
- return skills.value.filter(
- (item) => item.line > lvStart - 5 && item.line <= Math.max(lvEnd - 5, 1),
- )
+ const skillGrid = computed(() => {
+ const grid = new Map
()
+ const occupiedRows = new Set()
+ let maxColumn = defaultColumnCount - 1
+
+ props.skills.forEach((skill) => {
+ const [column, row] = skill.cellPosition ?? []
+ if (!Number.isInteger(column) || !Number.isInteger(row) || column < 0 || row < 0) return
+ grid.set(`${row}:${column}`, skill)
+ occupiedRows.add(row)
+ maxColumn = Math.max(maxColumn, column)
+ })
+
+ return {
+ grid,
+ columns: Array.from({ length: maxColumn + 1 }, (_, index) => index),
+ rows: Array.from(occupiedRows).sort((left, right) => left - right),
+ }
+ })
+
+ const showRowPrefix = computed(() => !altersWithoutRowPrefix.has(props.alter))
+ const isExtraAlter = computed(() => altersWithoutRowPrefix.has(props.alter))
+
+ const getRowPrefix = (row: number) => {
+ const lastRow = skillGrid.value.rows.at(-1) ?? -1
+ if (lastRow >= rowPrefixes.length && row >= rowPrefixes.length - 1) {
+ return row === lastRow ? rowPrefixes.at(-1) : ''
+ }
+ return rowPrefixes[row]
}
- const lvList = [15, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100]
+ const getLastPositionedSkill = (learnLv: number) =>
+ props.skills
+ .filter((skill) => skill.learnLv === learnLv && skill.type === 'active' && skill.bind)
+ .sort((left, right) => {
+ const [leftColumn = -1, leftRow = -1] = left.cellPosition ?? []
+ const [rightColumn = -1, rightRow = -1] = right.cellPosition ?? []
+ return leftRow - rightRow || leftColumn - rightColumn
+ })
+ .at(-1)
- const columns = Array.from({ length: 11 }, (_, index) => index)
+ const awakeSkill1 = computed(() =>
+ props.skills.find((skill) => skill.learnLv === 50 && skill.type === 'active' && skill.bind),
+ )
+ const awakeSkill2 = computed(() =>
+ props.skills.find((skill) => skill.learnLv === 85 && skill.type === 'active' && skill.bind),
+ )
+ const extraAwakeSkill2 = computed(() =>
+ props.alter === 'creator'
+ ? props.skills.find((skill) => skill.learnLv === 85 && skill.name === '生命之树')
+ : getLastPositionedSkill(85),
+ )
+ const extraAwakeSkill3 = computed(() => getLastPositionedSkill(100))
- const activeSkill = ref(-1)
+ watchEffect(() => {
+ if (isExtraAlter.value && bindAwake.value !== 85) bindAwake.value = 85
+ })
- const chooseSkill = (skill?: ISkill, operation: string = 'add') => {
+ const actionSkillLevel = (skill: ISkill, operation: string) => {
+ const key = skill.id.toString()
+ const current = lvInfo.value[key] ?? { lv: 0, vp: 0, up: 0 }
+ if (!lvInfo.value[key]) lvInfo.value[key] = current
+
+ if (operation === 'add') current.lv = Math.min(current.lv + 1, skill.maxLv)
+ if (operation === 'addMax') current.lv = skill.maxLearnLv
+ if (operation === 'sub') current.lv = Math.max(current.lv - 1, 0)
+ if (operation === 'subMax') lvInfo.value[key] = { lv: 0, vp: 0, up: 0 }
+ }
+
+ const chooseSkill = (skill?: ISkill, operation = 'add') => {
if (!skill) {
activeSkill.value = -1
return
}
- if (activeSkill.value == skill.id) actionSkillLv(skill, operation)
+ if (activeSkill.value === skill.id) actionSkillLevel(skill, operation)
else activeSkill.value = skill.id
emit('chooseSkill', skill.id)
}
- const awakeSkill_1 = computed(() =>
- skills.value.find((item) => item.learnLv == 50 && item.type == 'active' && item.bind),
- )
- const awakeSkill_2 = computed(() =>
- skills.value.find((item) => item.learnLv == 85 && item.type == 'active' && item.bind),
- )
+ const hasAwakeBinding = (skill: ISkill) =>
+ isExtraAlter.value
+ ? skill.id === extraAwakeSkill3.value?.id
+ : skill.learnLv === 100 && skill.bind
- const actionSkillLv = (skill: ISkill, operation: string) => {
- if (operation == 'add') {
- lvInfo.value[skill.id.toString()].lv = Math.min(
- lvInfo.value[skill.id.toString()]?.lv + 1,
- skill.maxLv,
- )
- return
+ const renderSkillAction = (skill: ISkill) => {
+ const level = lvInfo.value[skill.id.toString()]?.lv ?? 0
+ const action = (event: Event, operation: string) => {
+ event.stopPropagation()
+ actionSkillLevel(skill, operation)
}
- if (operation == 'addMax') {
- lvInfo.value[skill.id.toString()].lv = skill.maxLearnLv
- return
- }
- if (operation == 'sub') {
- lvInfo.value[skill.id.toString()].lv = Math.max(
- lvInfo.value[skill.id.toString()]?.lv - 1,
- 0,
- )
- return
- }
- if (operation == 'subMax') {
- lvInfo.value[skill.id.toString()] = { lv: 0, vp: 0, up: 0 }
- return
- }
- emit('chooseSkill', skill.id)
- }
- const chooseBindAwake = (lv: number) => {
- bindAwake.value = lv
- }
-
- const renderSkill = (skill: ISkill, index: number) => {
- const info = lvInfo.value?.[skill.id.toString()]
- let color = 'white'
- if (info?.lv < skill.maxLearnLv) color = '#32E432'
- if (info?.lv > skill.maxLearnLv) color = '#58E0FC'
return (
- <>
-
-
- {info?.vp > 0 &&
}
- {info?.up > 0 &&
}
-
- {activeSkill.value == skill.id && renderSkillAction(skill)}
-
{
- e.stopPropagation()
- chooseSkill(skill)
- }}
- onContextmenu={(e) => {
- e.stopPropagation()
- e.preventDefault()
- chooseSkill(skill, 'sub')
- }}
- key={index}
+
+
+
action(event, 'subMax')}
>
-
-
- {info?.lv ?? 0}
-
-
- {skill.learnLv == 100 && skill.bind && (
- <>
-
-
chooseBindAwake(50)}>
-

-
1次
-
-
chooseBindAwake(85)}>
-

-
2次
-
-
- >
- )}
+

+
+
action(event, 'sub')}
+ >
+
+
+
action(event, 'add')}
+ >
+
+
+
= skill.maxLearnLv}
+ onClick={(event: Event) => action(event, 'addMax')}
+ >
+
+
- >
+
)
}
- const renderSkillAction = (skill: ISkill) => (
- <>
- <>
-
-
-
{
- e.stopPropagation()
- actionSkillLv(skill, 'subMax')
- }}
- >
-
-
-
{
- e.stopPropagation()
- actionSkillLv(skill, 'sub')
- }}
- >
-
-
-
{
- e.stopPropagation()
- actionSkillLv(skill, 'add')
- }}
- >
-
-
-
= skill.maxLearnLv}
- onClick={(e: Event) => {
- e.stopPropagation()
- actionSkillLv(skill, 'addMax')
- }}
- >
-
-
- {/*

{
- e.stopPropagation()
- actionSkillLv(skill, 'subMax')
- }}
- >
-

{
- e.stopPropagation()
- actionSkillLv(skill, 'sub')
- }}
- >
-

{
- e.stopPropagation()
- actionSkillLv(skill, 'add')
- }}
- >
-

{
- e.stopPropagation()
- actionSkillLv(skill, 'addMax')
- }}
- > */}
-
-
- >
- >
+ const renderNormalAwakeBinding = () => (
+
+
+
+
)
- return () => (
- <>
-
(activeSkill.value = -1)}>
- {((getSkill(0, 15, -1) ?? []) as ISkill[]).length > 0 && (
- <>
-
-
- 其
余
-
- {((getSkill(0, 15, -1) ?? []) as ISkill[])?.map((skill, index) =>
- renderSkill(skill, index),
- )}
-
- >
- )}
-
- {lvList.map((lv, index) =>
- ((getSkill(lv, lvList[index + 1] ?? 150, -1) as ISkill[])?.length ?? 0) > 0 ? (
-
- {lv == 1 || lv % 10 == 0 ? (
-
{lv}
- ) : (
-
- )}
- {columns.map((column) => {
- const skill = getSkill(lv, lvList[index + 1] ?? 150, column) as ISkill
- return skill ? (
- renderSkill(skill, index)
- ) : (
-
- )
- })}
-
(activeSkill.value = -1)}>
-
- ) : (
- <>>
- ),
- )}
+ const renderExtraAwakeBinding = () => (
+
+ )
+
+ const renderSkill = (skill: ISkill) => {
+ const info = lvInfo.value[skill.id.toString()]
+ const color =
+ (info?.lv ?? 0) < skill.maxLearnLv
+ ? '#32e432'
+ : (info?.lv ?? 0) > skill.maxLearnLv
+ ? '#58e0fc'
+ : 'white'
+
+ return (
+
+
+ {(info?.vp ?? 0) > 0 && }
+ {(info?.up ?? 0) > 0 && }
+
+ {activeSkill.value === skill.id && renderSkillAction(skill)}
+
+ {hasAwakeBinding(skill) &&
+ (isExtraAlter.value ? renderExtraAwakeBinding() : renderNormalAwakeBinding())}
+
+ )
+ }
+
+ return () => (
+
(activeSkill.value = -1)}>
+ {skillGrid.value.rows.map((row) => (
+
+
{showRowPrefix.value ? getRowPrefix(row) : ''}
+ {skillGrid.value.columns.map((column) => {
+ const skill = skillGrid.value.grid.get(`${row}:${column}`)
+ return skill ? (
+ renderSkill(skill)
+ ) : (
+
+ )
+ })}
+
+
+ ))}
+
)
},
})
diff --git a/frontend-ui/src/pages/Character/Skill/components/SkillTree/style.scss b/frontend-ui/src/pages/Character/Skill/components/SkillTree/style.scss
index 6caf1bce..825ea865 100644
--- a/frontend-ui/src/pages/Character/Skill/components/SkillTree/style.scss
+++ b/frontend-ui/src/pages/Character/Skill/components/SkillTree/style.scss
@@ -1,6 +1,7 @@
.skill-tree {
- /* Preserve the original 11-column tree rhythm while allowing its host to scroll on narrow screens. */
- min-width: 550px;
+ /* Fill the standard tree viewport; expanded special-job grids keep their intrinsic width and scroll. */
+ width: max-content;
+ min-width: 100%;
}
.skill-tree-line {
@@ -48,6 +49,10 @@
align-items: center;
flex-direction: column;
cursor: pointer;
+ border: 0;
+ background-color: transparent;
+ color: inherit;
+ font: inherit;
}
.skill-tree__icon {
@@ -89,6 +94,38 @@
align-items: center;
flex-direction: column;
cursor: pointer;
+ border: 0;
+ background: transparent;
+ color: inherit;
+ font: inherit;
+}
+
+.skill-tree__extra-awake {
+ position: absolute;
+ top: -3px;
+ left: 0;
+ width: 117px;
+ height: 54px;
+ background: url('./img/extra_awake_85.png') 0 0 / 100% 100% no-repeat;
+}
+
+.skill-tree__extra-awake-option {
+ position: absolute;
+ z-index: 2;
+ top: 3px;
+ left: 78px;
+ display: flex;
+ width: 36px;
+ height: 48px;
+ box-sizing: border-box;
+ padding-block: 3px;
+ align-items: center;
+ flex-direction: column;
+ color: #ffc701;
+
+ span {
+ margin-top: 1px;
+ }
}
.skill-tree__awake-icon {
diff --git a/frontend-ui/src/pages/Character/Skill/components/img/shortcut.png b/frontend-ui/src/pages/Character/Skill/components/img/shortcut.png
new file mode 100644
index 00000000..282a4d2b
Binary files /dev/null and b/frontend-ui/src/pages/Character/Skill/components/img/shortcut.png differ
diff --git a/frontend-ui/src/pages/Character/Skill/index.vue b/frontend-ui/src/pages/Character/Skill/index.vue
index c5cffe1d..5a427028 100644
--- a/frontend-ui/src/pages/Character/Skill/index.vue
+++ b/frontend-ui/src/pages/Character/Skill/index.vue
@@ -1,168 +1,145 @@
-
-
-
+
+
+
+
+ 技能加点
+ 技能定制
+
+
+
-
+
+ :alter="infoStore.infos?.alter"
+ v-model:lv-info="configStore.config.skills"
+ v-model:bind-awake="configStore.config.bindAwake"
+ @choose-skill="setCurrentSkill"
+ />
-
-
-
-
-
-
-
-

- 技能详情
-
+
-
-
-
-
-
+
+
+
+
-
-
diff --git a/frontend-ui/src/pages/ComponentCatalog/Index.vue b/frontend-ui/src/pages/ComponentCatalog/Index.vue
index 3582d773..f525ed02 100644
--- a/frontend-ui/src/pages/ComponentCatalog/Index.vue
+++ b/frontend-ui/src/pages/ComponentCatalog/Index.vue
@@ -538,8 +538,8 @@ function removeFavorite(item: UiFavoriteDrawerItem) {
装备消耗品材料任务制作材料任务物品
展示武器、防具与首饰词条。
展示药剂、宝珠与特殊消耗品。
@@ -990,7 +990,7 @@ footer {
background: #101111;
color: var(--ui-muted-foreground);
font:
- 9px/1.4 Consolas,
+ 11px/1.4 Consolas,
monospace;
}
.catalog-content {
@@ -1197,7 +1197,7 @@ label > span,
color: var(--dcalc-success);
}
.status-danger {
- color: var(--dcalc-danger);
+ color: var(--ui-danger-foreground);
}
.table-icon {
display: block;
@@ -1319,9 +1319,9 @@ footer {
display: flex;
justify-content: space-between;
margin-top: 14px;
- color: #81755f;
+ color: var(--ui-muted-foreground);
font:
- 9px/1 Consolas,
+ 11px/1 Consolas,
monospace;
letter-spacing: 1.2px;
}
diff --git a/frontend-ui/src/stores/config.ts b/frontend-ui/src/stores/config.ts
index 0f3ad005..61f9ac39 100644
--- a/frontend-ui/src/stores/config.ts
+++ b/frontend-ui/src/stores/config.ts
@@ -1,7 +1,7 @@
import { defineStore } from 'pinia'
import { useInfoStore } from './info'
import api from '@/api'
-import type { IEquipment } from '@/api/info/type'
+import type { IEquipment, ISkill } from '@/api/info/type'
import type { IResultSkillCount } from '@/api/calc/type'
// | '上衣'
// | '头肩'
@@ -42,6 +42,11 @@ export interface IConfigEmblem {
items: string[]
}
+export interface ISkillShortcuts {
+ shortcuts: string[]
+ combos: string[][]
+}
+
export interface IConfig {
skills: Record
equips: Record
@@ -73,6 +78,7 @@ export interface IConfig {
options: Record
avatarLink: string
emblems: Record
+ skillShortcuts: ISkillShortcuts
}
const defaultEqusConfig = {
@@ -113,6 +119,39 @@ const createDefaultEmblemConfig = (): IConfigEmblem => ({
const defaultEmblemConfig = createDefaultEmblemConfig()
+const createDefaultSkillShortcuts = (): ISkillShortcuts => ({
+ shortcuts: Array.from({ length: 6 }, () => ''),
+ combos: Array.from({ length: 6 }, () => Array.from({ length: 5 }, () => '')),
+})
+
+const normalizeSkillShortcuts = (
+ arrangement?: Partial,
+ skills: ISkill[] = [],
+): ISkillShortcuts => {
+ const validSkillIds = new Set(skills.map((skill) => skill.id.toString()))
+ const skillIdByUuid = new Map(skills.map((skill) => [skill.uuid, skill.id.toString()]))
+ const normalizeSkillId = (value: unknown) => {
+ const key =
+ typeof value === 'number' ? value.toString() : typeof value === 'string' ? value : ''
+ if (!key) return ''
+ return validSkillIds.has(key) ? key : (skillIdByUuid.get(key) ?? '')
+ }
+
+ return {
+ shortcuts: Array.from({ length: 6 }, (_, index) =>
+ normalizeSkillId(arrangement?.shortcuts?.[index]),
+ ),
+ combos: Array.from({ length: 6 }, (_, column) => {
+ const combo = Array.from({ length: 5 }, (_, stage) =>
+ normalizeSkillId(arrangement?.combos?.[column]?.[stage]),
+ )
+ const firstEmptyStage = combo.findIndex((skillId) => !skillId)
+ if (firstEmptyStage >= 0) combo.fill('', firstEmptyStage)
+ return combo
+ }),
+ }
+}
+
export const useConfigStore = defineStore('configStore', () => {
const config = ref({
skills: {},
@@ -128,6 +167,7 @@ export const useConfigStore = defineStore('configStore', () => {
options: {},
avatarLink: '',
emblems: {},
+ skillShortcuts: createDefaultSkillShortcuts(),
})
const skillCountConfig = ref([])
@@ -161,6 +201,7 @@ export const useConfigStore = defineStore('configStore', () => {
options: {},
avatarLink: '',
emblems: {},
+ skillShortcuts: createDefaultSkillShortcuts(),
}
}
if (!config.value?.equips) config.value.equips = {}
@@ -172,6 +213,10 @@ export const useConfigStore = defineStore('configStore', () => {
if (!config.value?.options) config.value.options = {}
if (!config.value?.oaths) config.value.oaths = {}
if (!config.value?.emblems) config.value.emblems = {}
+ config.value.skillShortcuts = normalizeSkillShortcuts(
+ config.value.skillShortcuts,
+ infoStore.skills,
+ )
const part = [...infoStore.parts, '宠物', '副武器'].filter(
(a) => !config.value?.equips.hasOwnProperty(a),
@@ -291,5 +336,6 @@ export const useConfigStore = defineStore('configStore', () => {
createDefaultOathConfig,
defaultEmblemConfig,
createDefaultEmblemConfig,
+ createDefaultSkillShortcuts,
}
})
diff --git a/frontend-ui/src/style/themes/dcalc.css b/frontend-ui/src/style/themes/dcalc.css
index 0c16650f..3cfd69f3 100644
--- a/frontend-ui/src/style/themes/dcalc.css
+++ b/frontend-ui/src/style/themes/dcalc.css
@@ -19,6 +19,8 @@
--ui-accent-foreground: #fee97d;
--ui-destructive: var(--dcalc-danger);
--ui-destructive-foreground: #fff4f4;
+ --ui-danger-foreground: #ef8883;
+ --ui-unavailable-foreground: #8f8b83;
--ui-border: var(--dcalc-brass-dark);
--ui-input: #5b472a;
--ui-ring: var(--dcalc-focus);
diff --git a/frontend-ui/src/style/themes/midnight.css b/frontend-ui/src/style/themes/midnight.css
index 663279a2..08aec8f1 100644
--- a/frontend-ui/src/style/themes/midnight.css
+++ b/frontend-ui/src/style/themes/midnight.css
@@ -19,6 +19,8 @@
--ui-accent-foreground: #ffffff;
--ui-destructive: #a73f45;
--ui-destructive-foreground: #fff4f4;
+ --ui-danger-foreground: #f08b94;
+ --ui-unavailable-foreground: #8da0bc;
--ui-border: #40577a;
--ui-input: #354b6e;
--ui-ring: #6fb5e6;
diff --git a/frontend-ui/src/style/tokens/primitives.css b/frontend-ui/src/style/tokens/primitives.css
index b4952553..48f1fa32 100644
--- a/frontend-ui/src/style/tokens/primitives.css
+++ b/frontend-ui/src/style/tokens/primitives.css
@@ -62,8 +62,8 @@
--ui-popup-z-index: 80;
--ui-field-padding-inline: 9px;
--ui-option-height: 27px;
- --ui-tabs-height: 40px;
- --ui-tab-height: 30px;
+ --ui-tabs-height: 32px;
+ --ui-tab-height: 24px;
/*
* Component geometry defaults. Every value is consumed through var(), so a component instance
@@ -132,10 +132,10 @@
100dvh - 16px - var(--ui-dialog-header-block-size) - var(--ui-dialog-footer-min-block-size)
);
--ui-dialog-body-padding: 12px;
- --ui-tab-marker-inline-size: 39px;
- --ui-tab-marker-block-size: 5px;
- --ui-tab-marker-arrow-inline-size: 9px;
- --ui-tab-marker-arrow-block-size: 4px;
+ --ui-tab-marker-inline-size: 33px;
+ --ui-tab-marker-block-size: 4px;
+ --ui-tab-marker-arrow-inline-size: 7px;
+ --ui-tab-marker-arrow-block-size: 3px;
--ui-number-fast-inline-size: 26px;
--ui-number-fast-block-size: 28px;
--ui-number-fast-step-block-size: 14px;
@@ -300,3 +300,14 @@
--ui-shop-action-block-size: 24px;
--ui-shop-action-icon-size: 16px;
}
+
+@media (max-width: 520px) {
+ :root {
+ /* Preserve pixel artwork while giving standalone touch controls a 24px minimum hit box. */
+ --ui-slider-control-size: 24px;
+ --ui-select-icon-inline-size: 24px;
+ --ui-select-icon-block-size: 24px;
+ --ui-number-fast-block-size: 48px;
+ --ui-number-fast-step-block-size: 24px;
+ }
+}