mirror of
https://github.com/Kvan7/Exiled-Exchange-2.git
synced 2026-09-28 15:45:58 +00:00
feat: map profiles, closes #868
This commit is contained in:
@@ -504,6 +504,17 @@ function upgradeConfig (_config: Config): Config {
|
||||
const itemSearch = config.widgets.find(w => w.wmType === 'item-search') as widget.ItemSearchWidget
|
||||
itemSearch.ocrGemsKey = null
|
||||
|
||||
const itemCheck = config.widgets.find(w => w.wmType === 'item-check') as widget.ItemCheckWidget
|
||||
itemCheck.maps.profile = 1
|
||||
for (const stat of itemCheck.maps.selectedStats) {
|
||||
const p1decision =
|
||||
(stat.decision === 'danger') ? 'd'
|
||||
: (stat.decision === 'warning') ? 'w'
|
||||
: (stat.decision === 'desirable') ? 'g' : 's'
|
||||
|
||||
stat.decision = `${p1decision}--`
|
||||
}
|
||||
|
||||
config.configVersion = 15
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
<template>
|
||||
<div class="bg-gray-800 text-gray-200 border-gray-900 border-4"
|
||||
style="min-width: 20rem; max-width: min(100vw - var(--game-panel), 30rem);">
|
||||
<div class="bg-gray-900 py-1 px-4 text-center">{{ mapName }}</div>
|
||||
<div class="bg-gray-900 py-1 px-8 flex items-baseline gap-2">
|
||||
<div class="flex-1 text-center">{{ mapName }}</div>
|
||||
<div class="ml-8 text-gray-400">{{ t('Profile') }}</div>
|
||||
<div class="flex gap-0.5">
|
||||
<button
|
||||
v-for="profile in profiles" :key="profile.text"
|
||||
@click="profile.select"
|
||||
:class="{ 'border border-gray-600': profile.active }"
|
||||
class="w-6 bg-gray-800"
|
||||
>{{ profile.text }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<fullscreen-image v-if="image" :src="image" />
|
||||
<div v-if="!mapStats.length" class="px-8 py-2">
|
||||
{{ t('Item has no modifiers.') }}
|
||||
@@ -41,12 +52,14 @@ export default defineComponent({
|
||||
setup (props) {
|
||||
const { t } = useI18n()
|
||||
|
||||
const config = computed(() => AppConfig<ItemCheckWidget>('item-check')!)
|
||||
const config = computed(() => AppConfig<ItemCheckWidget>('item-check')!.maps)
|
||||
|
||||
const hasOutdatedTranslation = computed<boolean>(() => {
|
||||
return config.value.maps.selectedStats
|
||||
const idx = config.value.profile - 1
|
||||
return config.value.selectedStats
|
||||
.some(entry =>
|
||||
entry.decision !== 'seen' &&
|
||||
entry.decision[idx] !== '-' &&
|
||||
entry.decision[idx] !== 's' &&
|
||||
STAT_BY_MATCH_STR(entry.matcher) == null)
|
||||
})
|
||||
|
||||
@@ -59,7 +72,15 @@ export default defineComponent({
|
||||
: props.item.info.map?.screenshot
|
||||
),
|
||||
mapStats: computed(() => prepareMapStats(props.item)),
|
||||
hasOutdatedTranslation
|
||||
hasOutdatedTranslation,
|
||||
profiles: computed(() => {
|
||||
const ROMAN_NUMERALS = ['I', 'II', 'III']
|
||||
return ROMAN_NUMERALS.map((text, i) => ({
|
||||
text,
|
||||
active: (config.value.profile === i + 1),
|
||||
select: () => { config.value.profile = i + 1 }
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -72,7 +93,8 @@ export default defineComponent({
|
||||
},
|
||||
"ru": {
|
||||
"Item has no modifiers.": "На предмете нету модов.",
|
||||
"has_outdated": "Перевод некоторых свойств был изменен. Проверьте и обновите опасные моды карт в настройках. (Это сообщение будет скрыто, как только вы удалите все устаревшие переводы)"
|
||||
"has_outdated": "Перевод некоторых свойств был изменен. Проверьте и обновите опасные моды карт в настройках. (Это сообщение будет скрыто, как только вы удалите все устаревшие переводы)",
|
||||
"Profile": "Профиль"
|
||||
},
|
||||
"cmn-Hant" :{
|
||||
"has_outdataed" :"部份詞綴描述已變更,請檢查並更新地圖的危險詞綴。(當你刪除將所有舊版詞綴,此訊息會隱藏)"
|
||||
|
||||
@@ -1,21 +1,12 @@
|
||||
<template>
|
||||
<div class="flex">
|
||||
<button @click="handleClick"
|
||||
class="px-2 leading-none py-2 m-0 text-left flex-1 flex items-center overflow-hidden"
|
||||
:class="decision === 'danger' ? 'bg-red-700'
|
||||
: decision === 'warning' ? 'bg-orange-600'
|
||||
: decision === 'desirable' ? 'bg-green-700'
|
||||
: 'hover:bg-gray-700'">
|
||||
<template v-if="true">
|
||||
<i v-if="!decision || decision === 'seen'"
|
||||
class="inline-block mr-2" style="min-width: 1rem;">{{ '\u2009' }}</i>
|
||||
<i v-else
|
||||
class="fas mr-2 text-center" style="min-width: 1rem;"
|
||||
:class="decision === 'danger' ? 'fa-skull-crossbones'
|
||||
: decision === 'warning' ? 'fa-exclamation-triangle'
|
||||
: 'fa-check'"></i>
|
||||
</template>
|
||||
<item-modifier-text :text="stat.matcher" :roll="stat.roll" class="truncate" />
|
||||
class="p-2 gap-x-2 leading-none text-left flex-1 flex items-center overflow-hidden"
|
||||
:class="btnStyle?.bg ?? 'hover:bg-gray-700'">
|
||||
<i class="fas text-center w-4 shrink-0"
|
||||
:class="btnStyle?.icon" />
|
||||
<item-modifier-text class="truncate"
|
||||
:text="stat.matcher" :roll="stat.roll" />
|
||||
</button>
|
||||
<button @click="toggleSeenStatus" class="flex leading-none items-center text-gray-600 w-8 text-center justify-center">
|
||||
<i v-if="showNewStatIcon" class="fas fa-eye-slash"></i>
|
||||
@@ -30,6 +21,12 @@ import { AppConfig } from '@/web/Config'
|
||||
import { PreparedStat } from './prepare-map-stats'
|
||||
import { ItemCheckWidget } from '../overlay/interfaces'
|
||||
|
||||
const BTN_STYLES = new Map([
|
||||
['d', { bg: 'bg-red-700', icon: 'fa-skull-crossbones' }],
|
||||
['w', { bg: 'bg-orange-600', icon: 'fa-exclamation-triangle' }],
|
||||
['g', { bg: 'bg-green-700', icon: 'fa-check' }]
|
||||
])
|
||||
|
||||
export default defineComponent({
|
||||
components: { ItemModifierText },
|
||||
props: {
|
||||
@@ -39,48 +36,51 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
const config = computed(() => AppConfig<ItemCheckWidget>('item-check')!)
|
||||
const entry = computed(() => {
|
||||
return config.value.maps.selectedStats.find(_ => _.matcher === props.stat.matcher)
|
||||
const config = computed(() => AppConfig<ItemCheckWidget>('item-check')!.maps)
|
||||
const entry = computed(() => config.value.selectedStats
|
||||
.find(({ matcher }) => matcher === props.stat.matcher))
|
||||
|
||||
const decision = computed<string>({
|
||||
get () {
|
||||
if (!entry.value) return '-'
|
||||
return entry.value.decision[config.value.profile - 1]
|
||||
},
|
||||
set (value) {
|
||||
if (!entry.value) {
|
||||
const decision = ['-', '-', '-']
|
||||
decision[config.value.profile - 1] = value
|
||||
config.value.selectedStats.push({
|
||||
matcher: props.stat.matcher,
|
||||
decision: decision.join('')
|
||||
})
|
||||
} else {
|
||||
const decision = entry.value.decision.split('')
|
||||
decision[config.value.profile - 1] = value
|
||||
entry.value.decision = decision.join('')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const showNewStatIcon = computed(() => {
|
||||
return config.value.maps.showNewStats && !entry.value
|
||||
})
|
||||
const showNewStatIcon = computed(() =>
|
||||
config.value.showNewStats && decision.value === '-')
|
||||
|
||||
function toggleSeenStatus () {
|
||||
if (!config.value.maps.showNewStats) return
|
||||
|
||||
if (!entry.value) {
|
||||
config.value.maps.selectedStats.push({
|
||||
matcher: props.stat.matcher,
|
||||
decision: 'seen'
|
||||
})
|
||||
} else if (entry.value.decision === 'seen') {
|
||||
config.value.maps.selectedStats = config.value.maps.selectedStats.filter(selected => selected !== entry.value)
|
||||
if (config.value.showNewStats) {
|
||||
decision.value = (decision.value === '-') ? 's' : '-'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
decision: computed(() => entry.value?.decision),
|
||||
btnStyle: computed(() => BTN_STYLES.get(decision.value)),
|
||||
showNewStatIcon,
|
||||
toggleSeenStatus,
|
||||
handleClick () {
|
||||
if (!entry.value) {
|
||||
config.value.maps.selectedStats.push({
|
||||
matcher: props.stat.matcher,
|
||||
decision: 'danger'
|
||||
})
|
||||
} else {
|
||||
if (entry.value.decision === 'danger') {
|
||||
entry.value.decision = 'warning'
|
||||
} else if (entry.value.decision === 'warning') {
|
||||
entry.value.decision = 'desirable'
|
||||
} else if (entry.value.decision === 'desirable') {
|
||||
entry.value.decision = 'seen'
|
||||
} else if (entry.value.decision === 'seen') {
|
||||
entry.value.decision = 'danger'
|
||||
}
|
||||
switch (decision.value) {
|
||||
case '-': decision.value = 'd'; break
|
||||
case 's': decision.value = 'd'; break
|
||||
case 'd': decision.value = 'w'; break
|
||||
case 'w': decision.value = 'g'; break
|
||||
case 'g': decision.value = 's'; break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ export interface ItemCheckWidget extends Widget {
|
||||
craftOfExileKey: string | null
|
||||
stashSearchKey: string | null
|
||||
maps: {
|
||||
profile: number
|
||||
showNewStats: boolean
|
||||
selectedStats: Array<{
|
||||
matcher: string
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
<span class="truncate">{{ matcher.str }}</span>
|
||||
</div>
|
||||
<div class="flex items-baseline gap-x-4" :class="{ [$style['controls-auto-hide']]: !removable }">
|
||||
<ui-radio v-model="decision" value="warning" class="p-1" />
|
||||
<ui-radio v-model="decision" value="danger" class="p-1" />
|
||||
<ui-radio v-model="decision" value="desirable" class="p-1" />
|
||||
<ui-radio v-model="decision" value="w" class="p-1" />
|
||||
<ui-radio v-model="decision" value="d" class="p-1" />
|
||||
<ui-radio v-model="decision" value="g" class="p-1" />
|
||||
<button v-if="removable" @click="remove"
|
||||
class="flex items-center mx-1 py-1" :class="{ 'text-red-400': matcher.outdated }">
|
||||
<i class="w-4" :class="matcher.outdated ? 'fas fa-trash-alt' : 'fas fa-times'"></i>
|
||||
@@ -34,39 +34,47 @@ export default defineComponent({
|
||||
selectedStats: {
|
||||
type: Array as PropType<ItemCheckWidget['maps']['selectedStats']>,
|
||||
required: true
|
||||
},
|
||||
profile: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
const { t } = useI18n()
|
||||
|
||||
const entry = computed(() => {
|
||||
return props.selectedStats.find(entry => entry.matcher === props.matcher.str)
|
||||
})
|
||||
const entry = computed(() => props.selectedStats
|
||||
.find(({ matcher }) => matcher === props.matcher.str))
|
||||
|
||||
const decision = computed<undefined | string>({
|
||||
const decision = computed<string>({
|
||||
get () {
|
||||
return entry.value?.decision
|
||||
if (!entry.value) return '-'
|
||||
return entry.value.decision[props.profile - 1]
|
||||
},
|
||||
set (value) {
|
||||
if (entry.value) {
|
||||
entry.value.decision = value!
|
||||
} else {
|
||||
if (!entry.value) {
|
||||
const decision = ['-', '-', '-']
|
||||
decision[props.profile - 1] = value
|
||||
props.selectedStats.push({
|
||||
matcher: props.matcher.str,
|
||||
decision: value!
|
||||
decision: decision.join('')
|
||||
})
|
||||
} else {
|
||||
const decision = entry.value.decision.split('')
|
||||
decision[props.profile - 1] = value
|
||||
entry.value.decision = decision.join('')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function remove () {
|
||||
if (entry.value) {
|
||||
decision.value = 'seen'
|
||||
decision.value = '---'
|
||||
}
|
||||
}
|
||||
|
||||
const removable = computed(() => {
|
||||
return entry.value && decision.value !== 'seen'
|
||||
return decision.value !== 's' && decision.value !== '-'
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
<maps-stat-entry
|
||||
:style="{ position: 'absolute', top: `${props.top}px` }"
|
||||
:matcher="props.item"
|
||||
:selected-stats="selectedStats" />
|
||||
:selected-stats="selectedStats"
|
||||
:profile="profile" />
|
||||
</virtual-scroll>
|
||||
</div>
|
||||
</template>
|
||||
@@ -79,9 +80,10 @@ export default defineComponent({
|
||||
})
|
||||
|
||||
const selectedMatchers = computed(() => {
|
||||
const idx = widget.value.maps.profile - 1
|
||||
return new Set(
|
||||
widget.value.maps.selectedStats
|
||||
.filter(entry => entry.decision !== 'seen')
|
||||
.filter(({ decision }) => decision[idx] !== '-' && decision[idx] !== 's')
|
||||
.map(entry => entry.matcher))
|
||||
})
|
||||
|
||||
@@ -91,10 +93,12 @@ export default defineComponent({
|
||||
})
|
||||
|
||||
const hasOutdatedTranslation = computed<MapStatMatcher[]>(() => {
|
||||
const idx = widget.value.maps.profile - 1
|
||||
return widget.value.maps
|
||||
.selectedStats
|
||||
.filter(entry =>
|
||||
entry.decision !== 'seen' &&
|
||||
entry.decision[idx] !== '-' &&
|
||||
entry.decision[idx] !== 's' &&
|
||||
STAT_BY_MATCH_STR(entry.matcher) == null)
|
||||
.map(entry => ({ str: entry.matcher, heist: undefined, outdated: true }))
|
||||
})
|
||||
@@ -124,6 +128,7 @@ export default defineComponent({
|
||||
]
|
||||
}),
|
||||
selectedStats: computed(() => widget.value.maps.selectedStats),
|
||||
profile: computed(() => widget.value.maps.profile),
|
||||
fontSize: computed(() => props.config.fontSize)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user