Skip to content

Commit f9b534d

Browse files
committed
feat(spx-gui): add publish action in editor preview
1 parent 87d70c5 commit f9b534d

File tree

7 files changed

+157
-109
lines changed

7 files changed

+157
-109
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ function handleSpriteSelect(sprite: Sprite | null) {
5858
}
5959
.main {
6060
flex: 1;
61+
width: 0;
6162
min-width: 0;
6263
display: flex;
6364
justify-content: center;
@@ -70,7 +71,7 @@ function handleSpriteSelect(sprite: Sprite | null) {
7071
gap: var(--ui-gap-middle);
7172
7273
@include responsive(desktop-large) {
73-
flex-basis: 492px;
74+
flex-basis: 494px;
7475
}
7576
7677
.collapse-icon {

spx-gui/src/components/editor/navbar/EditorNavbar.vue

Lines changed: 103 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<!-- eslint-disable vue/no-v-html -->
22
<template>
3-
<NavbarWrapper disabled-lang>
3+
<NavbarWrapper disabled-lang disabled-tutorials>
44
<template #left>
55
<NavbarDropdown
66
:trigger-radar="{
@@ -58,22 +58,26 @@
5858
</UIMenu>
5959
</NavbarDropdown>
6060

61-
<UITooltip :disabled="undoAction == null">
62-
<template #trigger>
63-
<button class="history-button" :disabled="undoAction == null" @click="handleUndo.fn">
64-
<UIIcon class="icon" type="undo" />
65-
</button>
66-
</template>
67-
<span class="history-menu-text">{{ $t(undoText) }}</span>
68-
</UITooltip>
69-
<UITooltip :disabled="redoAction == null">
70-
<template #trigger>
71-
<button class="history-button" :disabled="redoAction == null" @click="handleRedo.fn">
72-
<UIIcon class="icon" type="redo" />
73-
</button>
74-
</template>
75-
<span class="history-menu-text">{{ $t(redoText) }}</span>
76-
</UITooltip>
61+
<NavbarTutorials v-if="showTutorialsEntry" />
62+
63+
<div class="history-button-wrapper">
64+
<UITooltip :disabled="undoAction == null">
65+
<template #trigger>
66+
<button class="history-button" :disabled="undoAction == null" @click="handleUndo.fn">
67+
<UIIcon class="icon" type="undo" />
68+
</button>
69+
</template>
70+
<span class="history-menu-text">{{ $t(undoText) }}</span>
71+
</UITooltip>
72+
<UITooltip :disabled="redoAction == null">
73+
<template #trigger>
74+
<button class="history-button" :disabled="redoAction == null" @click="handleRedo.fn">
75+
<UIIcon class="icon" type="redo" />
76+
</button>
77+
</template>
78+
<span class="history-menu-text">{{ $t(redoText) }}</span>
79+
</UITooltip>
80+
</div>
7781
</template>
7882
<template #center>
7983
<template v-if="project != null">
@@ -90,40 +94,30 @@
9094
</template>
9195
</template>
9296
<template #right>
93-
<NavbarDropdown
94-
:trigger-radar="{
95-
name: 'editor type menu',
96-
desc: 'Hover to see editor type options (preview, global)'
97-
}"
97+
<UIButtonGroup
98+
v-radar="{ name: 'editor type menu', desc: 'Hover to see editor type options (preview, global)' }"
99+
class="editor-mode-wrapper"
100+
type="text"
101+
:value="selectedEditMode"
102+
@update:value="(v) => state?.selectEditMode(v as EditMode)"
98103
>
99-
<template #trigger>
100-
<div class="editor-type-selected">
101-
<img :src="selectedEditModeItem.icon" />
102-
{{ $t(selectedEditModeItem.display) }}
103-
</div>
104-
</template>
105-
<UIMenu>
106-
<UIMenuItem
107-
v-for="(typeItem, index) in editModeItems"
108-
:key="index"
109-
class="editor-type-item"
110-
@click="state?.selectEditMode(typeItem.value)"
111-
>
112-
<template #icon><img :src="typeItem.icon" /></template>
113-
{{ $t(typeItem.display) }}
114-
</UIMenuItem>
115-
</UIMenu>
116-
</NavbarDropdown>
117-
<div v-show="canManageProject" class="publish">
118-
<UIButton
119-
v-radar="{ name: 'Publish button', desc: 'Click to publish the project' }"
120-
type="secondary"
121-
:disabled="!isOnline"
122-
@click="handlePublishProject"
123-
>
124-
{{ $t({ en: 'Publish', zh: '发布' }) }}
125-
</UIButton>
126-
</div>
104+
<UITooltip>
105+
<template #trigger>
106+
<UIButtonGroupItem :value="EditMode.Preview">
107+
<div class="icon" v-html="gamePreviewSvg"></div>
108+
</UIButtonGroupItem>
109+
</template>
110+
{{ $t({ en: 'Preview', zh: '预览' }) }}
111+
</UITooltip>
112+
<UITooltip>
113+
<template #trigger>
114+
<UIButtonGroupItem :value="EditMode.Global">
115+
<div class="icon" v-html="globalSettingsSvg"></div>
116+
</UIButtonGroupItem>
117+
</template>
118+
{{ $t({ en: 'Global Settings', zh: '全局设置' }) }}
119+
</UITooltip>
120+
</UIButtonGroup>
127121
</template>
128122
</NavbarWrapper>
129123
</template>
@@ -132,7 +126,16 @@
132126
import { computed } from 'vue'
133127
import { useRouter } from 'vue-router'
134128
import saveAs from 'file-saver'
135-
import { UIMenu, UIMenuGroup, UIMenuItem, UIIcon, UITooltip, useConfirmDialog, UIButton } from '@/components/ui'
129+
import {
130+
UIMenu,
131+
UIMenuGroup,
132+
UIMenuItem,
133+
UIIcon,
134+
UITooltip,
135+
useConfirmDialog,
136+
UIButtonGroup,
137+
UIButtonGroupItem
138+
} from '@/components/ui'
136139
import { useMessageHandle } from '@/utils/exception'
137140
import { useI18n, type LocaleMessage } from '@/utils/i18n'
138141
import { useNetwork } from '@/utils/network'
@@ -141,12 +144,14 @@ import { type Project } from '@/models/project'
141144
import { getSignedInUsername, useUser } from '@/stores/user'
142145
import { Visibility } from '@/apis/common'
143146
import { getProjectPageRoute } from '@/router'
147+
import { showTutorialsEntry } from '@/utils/env'
144148
import { usePublishProject, useRemoveProject, useUnpublishProject } from '@/components/project'
145149
import { useLoadFromScratchModal } from '@/components/asset'
146150
import NavbarWrapper from '@/components/navbar/NavbarWrapper.vue'
147151
import NavbarDropdown from '@/components/navbar/NavbarDropdown.vue'
148152
import NavbarNewProjectItem from '@/components/navbar/NavbarNewProjectItem.vue'
149153
import NavbarOpenProjectItem from '@/components/navbar/NavbarOpenProjectItem.vue'
154+
import NavbarTutorials from '@/components/navbar/NavbarTutorials.vue'
150155
import { SavingState, EditingMode } from '../editing'
151156
import { EditMode, type EditorState } from '../editor-state'
152157
import importProjectSvg from './icons/import-project.svg'
@@ -156,12 +161,12 @@ import importScratchSvg from './icons/import-scratch.svg'
156161
import publishSvg from './icons/publish.svg'
157162
import unpublishSvg from './icons/unpublish.svg'
158163
import projectPageSvg from './icons/project-page.svg'
159-
import gamePreview from './icons/game-preview.svg'
160-
import globalSettings from './icons/global-settings.svg'
161164
import offlineSvg from './icons/offline.svg?raw'
162165
import savingSvg from './icons/saving.svg?raw'
163166
import failedToSaveSvg from './icons/failed-to-save.svg?raw'
164167
import cloudCheckSvg from './icons/cloud-check.svg?raw'
168+
import gamePreviewSvg from './icons/game-preview.svg?raw'
169+
import globalSettingsSvg from './icons/global-settings.svg?raw'
165170
166171
const props = defineProps<{
167172
project: Project | null
@@ -182,20 +187,8 @@ const canManageProject = computed(() => {
182187
183188
const projectOwnerRet = useUser(() => props.project?.owner ?? null)
184189
185-
const editModeItems = [
186-
{
187-
display: { en: 'Game Preview', zh: '游戏预览' },
188-
value: EditMode.Preview,
189-
icon: gamePreview
190-
},
191-
{
192-
display: { en: 'Global Settings', zh: '全局设置' },
193-
value: EditMode.Global,
194-
icon: globalSettings
195-
}
196-
]
197-
const selectedEditModeItem = computed(
198-
() => editModeItems.find((item) => item.value === props.state?.selectedEditMode) ?? editModeItems[0]
190+
const selectedEditMode = computed(() =>
191+
props.state?.selectedEditMode != null ? props.state!.selectedEditMode : EditMode.Preview
199192
)
200193
201194
const ownerInfoToDisplay = computed(() => {
@@ -360,30 +353,35 @@ const autoSaveStateIcon = computed<AutoSaveStateIcon | null>(() => {
360353
margin: 0 4px;
361354
}
362355
363-
.history-button {
356+
.history-button-wrapper {
364357
display: flex;
365-
justify-content: center;
366-
align-items: center;
367-
width: 40px;
368-
height: 100%;
369-
background: none;
370-
outline: none;
371-
border: none;
372-
padding: 0;
373-
color: white;
374-
375-
.icon {
376-
width: 18px;
377-
}
358+
margin-left: 16px;
359+
360+
.history-button {
361+
display: flex;
362+
justify-content: center;
363+
align-items: center;
364+
width: 40px;
365+
height: 100%;
366+
background: none;
367+
outline: none;
368+
border: none;
369+
padding: 0;
370+
color: white;
371+
372+
.icon {
373+
width: 18px;
374+
}
378375
379-
&[disabled] {
380-
color: #9de6ec;
381-
cursor: not-allowed;
382-
}
376+
&[disabled] {
377+
color: #9de6ec;
378+
cursor: not-allowed;
379+
}
383380
384-
&:hover:not([disabled]) {
385-
background-color: var(--ui-color-primary-600);
386-
cursor: pointer;
381+
&:hover:not([disabled]) {
382+
background-color: var(--ui-color-primary-600);
383+
cursor: pointer;
384+
}
387385
}
388386
}
389387
@@ -417,6 +415,23 @@ const autoSaveStateIcon = computed<AutoSaveStateIcon | null>(() => {
417415
}
418416
}
419417
418+
.editor-mode-wrapper {
419+
align-items: center;
420+
421+
& .ui-button-group-item {
422+
background-color: #47d8e4;
423+
color: var(--ui-color-grey-200);
424+
&.active {
425+
background-color: var(--ui-color-grey-200);
426+
color: #47d8e4;
427+
}
428+
}
429+
430+
.icon {
431+
display: flex;
432+
}
433+
}
434+
420435
.publish {
421436
margin-right: 2px;
422437
height: 100%;
Lines changed: 6 additions & 3 deletions
Loading
Lines changed: 6 additions & 3 deletions
Loading

spx-gui/src/components/editor/preview/EditorPreview.vue

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,28 @@
77
<div class="header">
88
{{ $t(headerTitle) }}
99
</div>
10-
<UIButton
11-
v-if="runnerState === 'initial'"
12-
v-radar="{ name: 'Run button', desc: 'Click to run the project in debug mode' }"
13-
class="button"
14-
type="primary"
15-
icon="playHollow"
16-
:loading="handleRun.isLoading.value"
17-
@click="handleRun.fn"
18-
>
19-
{{ $t({ en: 'Run', zh: '运行' }) }}
20-
</UIButton>
10+
<template v-if="runnerState === 'initial'">
11+
<UIButton
12+
v-radar="{ name: 'Run button', desc: 'Click to run the project in debug mode' }"
13+
class="button"
14+
type="primary"
15+
icon="playHollow"
16+
:loading="handleRun.isLoading.value"
17+
@click="handleRun.fn"
18+
>
19+
{{ $t({ en: 'Run', zh: '运行' }) }}
20+
</UIButton>
21+
22+
<UIButton
23+
v-radar="{ name: 'Publish button', desc: 'Click to publish the project' }"
24+
type="secondary"
25+
:disabled="!isOnline"
26+
@click="handlePublishProject"
27+
>
28+
<img :src="publishSvg" />
29+
{{ $t({ en: 'Publish', zh: '发布' }) }}
30+
</UIButton>
31+
</template>
2132
<template v-else>
2233
<UIButton
2334
v-radar="{ name: 'Rerun button', desc: 'Click to rerun the project' }"
@@ -134,9 +145,13 @@ import MapEditorModal from '@/components/editor/map-editor/MapEditorModal.vue'
134145
import { RuntimeOutputKind, type RuntimeOutput } from '@/components/editor/runtime'
135146
import { DiagnosticSeverity, textDocumentId2CodeFileName } from '../code-editor/common'
136147
import StageViewer from './stage-viewer/StageViewer.vue'
148+
import { useNetwork } from '@/utils/network'
149+
import { usePublishProject } from '@/components/project'
150+
import publishSvg from './publish.svg'
137151
138152
const editorCtx = useEditorCtx()
139153
const codeEditorCtx = useCodeEditorCtx()
154+
const { isOnline } = useNetwork()
140155
141156
const runtime = computed(() => editorCtx.state.runtime)
142157
const runnerState = ref<'initial' | 'loading' | 'running'>('initial')
@@ -310,6 +325,12 @@ async function executeRun(action: 'run' | 'rerun') {
310325
}
311326
}
312327
328+
const publishProject = usePublishProject()
329+
const handlePublishProject = useMessageHandle(() => publishProject(editorCtx.project), {
330+
en: 'Failed to publish project',
331+
zh: '发布项目失败'
332+
}).fn
333+
313334
const handleRun = useMessageHandle(
314335
async () => {
315336
await checkAndNotifyError()
@@ -415,7 +436,7 @@ function getStageInlineAnchor() {
415436
}
416437
417438
.button {
418-
margin-left: 8px;
439+
margin: 0 8px;
419440
}
420441
421442
.main {
Lines changed: 3 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)