Skip to content

Commit a47ce9f

Browse files
committed
✨ (viewer) Replay controls in local mode
1 parent 27df611 commit a47ce9f

File tree

1 file changed

+54
-18
lines changed

1 file changed

+54
-18
lines changed

viewer/src/components/Wrapper.vue

+54-18
Original file line numberDiff line numberDiff line change
@@ -4,42 +4,78 @@
44
<b-modal v-model="modalShow" size="lg" @ok="handleOK" title="Load from JSON">
55
<b-textarea v-model="text" rows="6" />
66
</b-modal>
7-
<b-avatar
8-
button
9-
style="position: fixed; left: 20px; bottom: 20px; z-index: 100"
10-
size="50"
11-
@click="modalShow = true"
12-
>
13-
LOAD
14-
</b-avatar>
15-
<b-avatar button style="position: fixed; left: 80px; bottom: 20px; z-index: 100" size="50" @click="openExport">
16-
EXPORT
17-
</b-avatar>
7+
<div class="d-flex">
8+
<b-button-group>
9+
<b-button @click="modalShow = true">Load</b-button>
10+
<b-button @click="openExport">Export</b-button>
11+
</b-button-group>
12+
<div class="mt-75">
13+
<b-btn variant="info" size="sm" @click="startReplay" v-if="!replayData">Replay</b-btn>
14+
<div v-else class="d-flex align-items-center">
15+
<b-btn size="sm" class="mr-1" @click="replayTo(replayData.start)">⏮️</b-btn>
16+
<b-btn size="sm" class="mx-1" @click="replayTo(Math.max(replayData.start, replayData.current - 1))">
17+
18+
</b-btn>
19+
<span
20+
class="mx-1 text-center"
21+
style="text-overflow: ellipsis; overflow: hidden; white-space: nowrap; flex-grow: 1"
22+
>
23+
{{ replayData.current }} / {{ replayData.end }}
24+
</span>
25+
<b-btn size="sm" class="mx-1" @click="replayTo(Math.min(replayData.end, replayData.current + 1))"> ⏩ </b-btn>
26+
<b-btn size="sm" class="mx-1" @click="replayTo(replayData.end)">⏭️</b-btn>
27+
<b-btn size="sm" class="ml-1" @click="endReplay">⏹️</b-btn>
28+
</div>
29+
</div>
30+
</div>
1831
</div>
1932
</template>
2033
<script lang="ts">
21-
import { Vue, Prop, Watch, Component } from "vue-property-decorator";
34+
import { Vue, Component } from "vue-property-decorator";
2235
import Game from "./Game.vue";
2336
2437
@Component({
25-
components: { Game }
38+
components: { Game },
2639
})
2740
export default class Wrapper extends Vue {
2841
modalShow = false;
2942
text = "";
43+
replayData: { stard: number; end: number; current: number } | null = null;
3044
31-
handleOK () {
45+
handleOK() {
3246
this.$store.dispatch("gaiaViewer/loadFromJSON", JSON.parse(this.text));
3347
}
3448
35-
openExport () {
49+
openExport() {
3650
this.text = JSON.stringify(this.$store.state.gaiaViewer.data);
3751
this.modalShow = true;
3852
}
53+
54+
startReplay() {
55+
this.$store.dispatch("gaiaViewer/replayStart");
56+
}
57+
58+
replayTo(dest: number) {
59+
this.$store.dispatch("gaiaViewer/replayTo", dest);
60+
}
61+
62+
endReplay() {
63+
this.$store.dispatch("gaiaViewer/replayEnd");
64+
this.replayData = null;
65+
}
66+
67+
mounted() {
68+
const unsub = this.$store.subscribeAction(({ type, payload }) => {
69+
if (type === "gaiaViewer/replayInfo") {
70+
this.replayData = payload;
71+
}
72+
});
73+
this.$on("hook:beforeDestroy", unsub);
74+
}
3975
}
4076
</script>
41-
<style lang="scss">
42-
.b-avatar-custom {
43-
display: contents !important;
77+
<style lang="scss" scoped>
78+
.btn-group {
79+
margin: 0.3rem;
4480
}
4581
</style>

0 commit comments

Comments
 (0)