Skip to content

Commit 7246e4f

Browse files
committed
feat(spx-gui): refactor the global/sprite config and optimize the expand/collapse
1 parent f9b534d commit 7246e4f

File tree

12 files changed

+228
-162
lines changed

12 files changed

+228
-162
lines changed

spx-gui/src/components/editor/ProjectEditor.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
<EditorPreview />
2626
<EditorPanels />
2727
</div>
28-
<GlobalSettings v-if="!isPreviewMode" />
28+
<GlobalConfig v-if="!isPreviewMode" />
2929
</template>
3030

3131
<script setup lang="ts">
@@ -53,7 +53,7 @@ import { genSpriteFromCanvas, genBackdropFromCanvas } from '@/models/common/asse
5353
import { computed, watchEffect } from 'vue'
5454
import type { z } from 'zod'
5555
import { Monitor } from '@/models/widget/monitor'
56-
import GlobalSettings from '@/components/editor/map-editor/GlobalSettings.vue'
56+
import GlobalConfig from '@/components/editor/map-editor/GlobalConfig.vue'
5757
import { EditMode } from './editor-state'
5858
5959
const editorCtx = useEditorCtx()
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<script setup lang="ts">
2+
import { UIIcon, UITooltip } from '@/components/ui'
3+
import { useMessageHandle } from '@/utils/exception'
4+
import { type Sprite } from '@/models/sprite'
5+
import { type Project } from '@/models/project'
6+
import { useRenameSprite } from '@/components/asset'
7+
import AssetName from '@/components/asset/AssetName.vue'
8+
9+
const props = defineProps<{
10+
sprite: Sprite
11+
project: Project
12+
}>()
13+
14+
const emit = defineEmits<{
15+
collapse: []
16+
}>()
17+
18+
const renameSprite = useRenameSprite()
19+
const handleNameEdit = useMessageHandle(() => renameSprite(props.sprite), {
20+
en: 'Failed to rename sprite',
21+
zh: '重命名精灵失败'
22+
}).fn
23+
</script>
24+
25+
<template>
26+
<div class="header">
27+
<AssetName>{{ sprite.name }}</AssetName>
28+
<UIIcon
29+
v-radar="{ name: 'Rename button', desc: 'Button to rename the sprite' }"
30+
class="icon"
31+
:title="$t({ en: 'Rename', zh: '重命名' })"
32+
type="edit"
33+
@click="handleNameEdit"
34+
/>
35+
<div class="spacer" />
36+
<UITooltip>
37+
<template #trigger>
38+
<UIIcon
39+
v-radar="{ name: 'Collapse button', desc: 'Button to collapse the sprite basic configuration panel' }"
40+
class="icon"
41+
type="doubleArrowDown"
42+
@click="emit('collapse')"
43+
/>
44+
</template>
45+
{{
46+
$t({
47+
en: 'Collapse',
48+
zh: '收起'
49+
})
50+
}}
51+
</UITooltip>
52+
</div>
53+
<slot />
54+
</template>
55+
56+
<style scoped lang="scss">
57+
.header {
58+
height: 28px;
59+
color: var(--ui-color-title);
60+
display: flex;
61+
align-items: center;
62+
}
63+
64+
.icon {
65+
cursor: pointer;
66+
color: var(--ui-color-grey-900);
67+
&:hover {
68+
color: var(--ui-color-grey-800);
69+
}
70+
&:active {
71+
color: var(--ui-color-grey-1000);
72+
}
73+
}
74+
75+
.spacer {
76+
flex: 1;
77+
}
78+
</style>

spx-gui/src/components/editor/map-editor/MapEditor.vue

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script setup lang="ts">
22
import { computed, ref } from 'vue'
3-
import { UICard, UICardHeader } from '@/components/ui'
3+
import { UICard, UICardHeader, UIIcon, UITooltip } from '@/components/ui'
44
import type { Project } from '@/models/project'
55
import MapViewer from './map-viewer/MapViewer.vue'
66
import SpriteList from './SpriteList.vue'
@@ -13,10 +13,13 @@ const props = defineProps<{
1313
}>()
1414
1515
const selectedSpriteId = ref(props.selectedSpriteId)
16+
const collapsed = ref(props.selectedSpriteId != null && props.project.stage.physics.enabled)
17+
1618
const selectedSprite = computed(() => props.project.sprites.find((s) => s.id === selectedSpriteId.value) ?? null)
1719
1820
function handleSpriteSelect(sprite: Sprite | null) {
1921
selectedSpriteId.value = sprite?.id ?? null
22+
collapsed.value = true
2023
}
2124
</script>
2225

@@ -26,16 +29,31 @@ function handleSpriteSelect(sprite: Sprite | null) {
2629
<MapViewer :project="project" :selected-sprite="selectedSprite" @update:selected-sprite="handleSpriteSelect" />
2730
</div>
2831
<div class="sider">
29-
<UICard class="collapse-card">
32+
<UICard>
3033
<UICardHeader>
31-
{{
32-
$t({
33-
en: 'Global Configuration',
34-
zh: '全局配置'
35-
})
36-
}}
34+
<div class="collapse-header">
35+
{{
36+
$t({
37+
en: 'Global Config',
38+
zh: '全局配置'
39+
})
40+
}}
41+
<UITooltip>
42+
<template #trigger>
43+
<UIIcon
44+
class="collapse-icon"
45+
:class="{ collapsed }"
46+
type="doubleArrowDown"
47+
@click="collapsed = !collapsed"
48+
/>
49+
</template>
50+
{{ $t({ en: collapsed ? 'Expand' : 'Collapse', zh: collapsed ? '展开' : '收起' }) }}
51+
</UITooltip>
52+
</div>
3753
</UICardHeader>
38-
<MapBasicConfig class="map-config" :project="project" />
54+
<Transition>
55+
<MapBasicConfig v-if="!collapsed" class="map-config" :project="project" />
56+
</Transition>
3957
</UICard>
4058
<SpriteList
4159
class="sprite-list"
@@ -74,6 +92,13 @@ function handleSpriteSelect(sprite: Sprite | null) {
7492
flex-basis: 494px;
7593
}
7694
95+
.collapse-header {
96+
width: 100%;
97+
display: flex;
98+
align-items: center;
99+
justify-content: space-between;
100+
}
101+
77102
.collapse-icon {
78103
transition: transform 0.3s;
79104
margin-left: 8px;

spx-gui/src/components/editor/map-editor/SpriteBasicConfig.vue

Lines changed: 23 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,15 @@ import { computed } from 'vue'
33
44
import type { Project } from '@/models/project'
55
import { PhysicsMode, type Sprite } from '@/models/sprite'
6-
import { useRenameSprite } from '@/components/asset'
76
import { useMessageHandle } from '@/utils/exception'
87
98
import SpritePositionSize from '@/components/editor/common/config/sprite/SpritePositionSize.vue'
109
import SpriteDirection from '@/components/editor/common/config/sprite/SpriteDirection.vue'
1110
import SpriteVisible from '@/components/editor/common/config/sprite/SpriteVisible.vue'
1211
import SpritePhysics from '@/components/editor/common/config/sprite/SpritePhysics.vue'
13-
import AssetName from '@/components/asset/AssetName.vue'
1412
import { UIIcon, useModal } from '@/components/ui'
1513
import SpriteCollisionEditorModal from '../sprite/SpriteCollisionEditorModal.vue'
14+
import SpriteConfigPanel from '../common/config/sprite/SpriteConfigPanel.vue'
1615
1716
const props = defineProps<{
1817
sprite: Sprite
@@ -25,12 +24,6 @@ const isCollisionSettingsEnabled = computed(() => {
2524
return true
2625
})
2726
28-
const renameSprite = useRenameSprite()
29-
const handleNameEdit = useMessageHandle(() => renameSprite(props.sprite), {
30-
en: 'Failed to rename sprite',
31-
zh: '重命名精灵失败'
32-
}).fn
33-
3427
const editSpriteCollision = useModal(SpriteCollisionEditorModal)
3528
const handleEditCollision = useMessageHandle(
3629
() => editSpriteCollision({ sprite: props.sprite, project: props.project }),
@@ -42,63 +35,32 @@ const handleEditCollision = useMessageHandle(
4235
</script>
4336

4437
<template>
45-
<div class="header">
46-
<AssetName>{{ sprite.name }}</AssetName>
47-
<UIIcon
48-
v-radar="{ name: 'Rename button', desc: 'Button to rename the sprite' }"
49-
class="icon"
50-
:title="$t({ en: 'Rename', zh: '重命名' })"
51-
type="edit"
52-
@click="handleNameEdit"
53-
/>
54-
<div class="spacer" />
55-
</div>
56-
<div class="config-wrapper">
57-
<SpritePositionSize :sprite="sprite" :project="project" />
58-
<div class="config-item">
59-
<div class="label">{{ $t({ en: 'Rotation', zh: '旋转' }) }}</div>
60-
<SpriteDirection :sprite="sprite" :project="project" />
61-
</div>
62-
<div class="config-item">
63-
<div class="label">{{ $t({ en: 'Show', zh: '显示' }) }}</div>
64-
<SpriteVisible :sprite="sprite" :project="project" />
65-
</div>
66-
<div v-if="project.stage.physics.enabled" class="config-item">
67-
<div class="label">{{ $t({ en: 'Physics', zh: '物理特性' }) }}</div>
68-
<SpritePhysics :sprite="sprite" :project="project" />
69-
</div>
70-
<div v-if="isCollisionSettingsEnabled" class="config-item">
71-
<div class="label">{{ $t({ en: 'Collision settings', zh: '碰撞设置' }) }}</div>
72-
<button class="edit-collision-button" @click="handleEditCollision">
73-
<UIIcon type="setting" />
74-
</button>
38+
<SpriteConfigPanel :project="project" :sprite="sprite">
39+
<div class="config-wrapper">
40+
<SpritePositionSize :sprite="sprite" :project="project" />
41+
<div class="config-item">
42+
<div class="label">{{ $t({ en: 'Rotation', zh: '旋转' }) }}</div>
43+
<SpriteDirection :sprite="sprite" :project="project" />
44+
</div>
45+
<div class="config-item">
46+
<div class="label">{{ $t({ en: 'Show', zh: '显示' }) }}</div>
47+
<SpriteVisible :sprite="sprite" :project="project" />
48+
</div>
49+
<div v-if="project.stage.physics.enabled" class="config-item">
50+
<div class="label">{{ $t({ en: 'Physics', zh: '物理特性' }) }}</div>
51+
<SpritePhysics :sprite="sprite" :project="project" />
52+
</div>
53+
<div v-if="isCollisionSettingsEnabled" class="config-item">
54+
<div class="label">{{ $t({ en: 'Collision settings', zh: '碰撞设置' }) }}</div>
55+
<button class="edit-collision-button" @click="handleEditCollision">
56+
<UIIcon type="setting" />
57+
</button>
58+
</div>
7559
</div>
76-
</div>
60+
</SpriteConfigPanel>
7761
</template>
7862

7963
<style lang="scss" scoped>
80-
.header {
81-
height: 28px;
82-
color: var(--ui-color-title);
83-
display: flex;
84-
align-items: center;
85-
}
86-
87-
.icon {
88-
cursor: pointer;
89-
color: var(--ui-color-grey-900);
90-
&:hover {
91-
color: var(--ui-color-grey-800);
92-
}
93-
&:active {
94-
color: var(--ui-color-grey-1000);
95-
}
96-
}
97-
98-
.spacer {
99-
flex: 1;
100-
}
101-
10264
.config-wrapper {
10365
display: flex;
10466
flex-direction: column;

spx-gui/src/components/editor/map-editor/SpriteList.vue

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ SpriteList
55
-->
66

77
<script setup lang="ts">
8-
import { computed } from 'vue'
8+
import { computed, ref, watch } from 'vue'
99
1010
import type { Project } from '@/models/project'
1111
import type { Sprite } from '@/models/sprite'
1212
import { useMessageHandle } from '@/utils/exception'
1313
14-
import { getCssVars, UICard, UIMenu, UIMenuItem, useUIVariables } from '@/components/ui'
14+
import { getCssVars, UICard, UIIcon, UIMenu, UIMenuItem, UITooltip, useUIVariables } from '@/components/ui'
1515
import SpriteItem from '@/components/editor/sprite/SpriteItem.vue'
1616
import PanelList from '../panels/common/PanelList.vue'
1717
import PanelHeader from '../panels/common/PanelHeader.vue'
@@ -31,6 +31,12 @@ const emit = defineEmits<{
3131
3232
const sprites = computed(() => props.project.sprites)
3333
34+
const footerExpanded = ref(props.selectedSprite != null)
35+
watch(
36+
() => props.selectedSprite,
37+
(newSprite) => (footerExpanded.value = newSprite != null)
38+
)
39+
3440
// TODO: CSS variables may not work when the component implementation changes
3541
const uiVariables = useUIVariables()
3642
const cssVars = computed(() => getCssVars('--panel-color-', uiVariables.color.sprite))
@@ -85,7 +91,7 @@ const handleAddFromAssetLibrary = useMessageHandle(
8591
class="sprite-list-card"
8692
:style="cssVars"
8793
>
88-
<PanelHeader active>
94+
<PanelHeader :active="selectedSprite != null">
8995
{{ $t({ en: 'Sprites', zh: '精灵' }) }}
9096
<template #add-options>
9197
<UIMenu>
@@ -116,20 +122,37 @@ const handleAddFromAssetLibrary = useMessageHandle(
116122
</PanelList>
117123

118124
<PanelFooter
119-
v-if="selectedSprite != null"
125+
v-if="footerExpanded && selectedSprite != null"
120126
v-radar="{
121127
name: `Basic configuration for selected sprite`,
122128
desc: 'Panel for configuring sprite basic settings'
123129
}"
124130
class="footer"
125131
>
126-
<SpriteBasicConfig :sprite="selectedSprite" :project="project" />
132+
<SpriteBasicConfig :sprite="selectedSprite" :project="project" @collapse="footerExpanded = false" />
127133
</PanelFooter>
134+
135+
<UITooltip v-if="!footerExpanded && selectedSprite != null">
136+
<template #trigger>
137+
<div
138+
v-radar="{
139+
name: 'Expand button',
140+
desc: 'Button to expand the basic configuration panel for selected sprite'
141+
}"
142+
class="footer-expand-button"
143+
@click="footerExpanded = true"
144+
>
145+
<UIIcon class="footer-expand-icon" type="doubleArrowDown" />
146+
</div>
147+
</template>
148+
{{ $t({ en: 'Expand', zh: '展开' }) }}
149+
</UITooltip>
128150
</UICard>
129151
</template>
130152

131153
<style lang="scss" scoped>
132154
.sprite-list-card {
155+
position: relative;
133156
display: flex;
134157
flex-direction: column;
135158
@@ -141,4 +164,22 @@ const handleAddFromAssetLibrary = useMessageHandle(
141164
.footer {
142165
padding: 16px;
143166
}
167+
168+
.footer-expand-button {
169+
position: absolute;
170+
width: 24px;
171+
height: 24px;
172+
right: 12px;
173+
bottom: 0;
174+
display: flex;
175+
align-items: center;
176+
justify-content: center;
177+
box-shadow: 0px -2px 8px 0px rgba(51, 51, 51, 0.08);
178+
background-color: var(--ui-color-grey-300);
179+
cursor: pointer;
180+
}
181+
182+
.footer-expand-icon {
183+
transform: rotate(180deg);
184+
}
144185
</style>

0 commit comments

Comments
 (0)