Sharkey/src/client/app/common/views/components/games/reversi/reversi.vue

333 lines
7 KiB
Vue
Raw Normal View History

2018-03-06 18:54:56 +02:00
<template>
2018-08-03 09:59:24 +03:00
<div class="vchtoekanapleubgzioubdtmlkribzfd">
2018-03-07 04:40:40 +02:00
<div v-if="game">
2018-03-08 10:57:57 +02:00
<x-gameroom :game="game"/>
2018-03-07 04:40:40 +02:00
</div>
2018-03-07 10:48:32 +02:00
<div class="matching" v-else-if="matching">
2018-08-02 03:52:47 +03:00
<h1>{{ '%i18n:@matching.waiting-for%'.split('{}')[0] }}<b>{{ matching | userName }}</b>{{ '%i18n:@matching.waiting-for%'.split('{}')[1] }}<mk-ellipsis/></h1>
2018-03-07 10:48:32 +02:00
<div class="cancel">
2018-08-02 18:36:29 +03:00
<form-button round @click="cancel">%i18n:@matching.cancel%</form-button>
2018-03-07 10:48:32 +02:00
</div>
2018-03-06 18:54:56 +02:00
</div>
2018-03-07 10:48:32 +02:00
<div class="index" v-else>
2018-08-02 01:36:25 +03:00
<h1>%i18n:@title%</h1>
<p>%i18n:@sub-title%</p>
2018-03-07 10:48:32 +02:00
<div class="play">
2018-08-02 01:36:25 +03:00
<!--<el-button round>フリーマッチ(準備中)</el-button>-->
2018-08-02 16:54:52 +03:00
<form-button primary round @click="match">%i18n:@invite%</form-button>
2018-03-07 10:48:32 +02:00
<details>
2018-08-02 01:36:25 +03:00
<summary>%i18n:@rule%</summary>
2018-03-07 10:48:32 +02:00
<div>
2018-08-02 01:36:25 +03:00
<p>%i18n:@rule-desc%</p>
2018-03-07 10:48:32 +02:00
<dl>
2018-08-02 01:36:25 +03:00
<dt><b>%i18n:@mode-invite%</b></dt>
<dd>%i18n:@mode-invite-desc%</dd>
2018-03-07 10:48:32 +02:00
</dl>
</div>
</details>
</div>
<section v-if="invitations.length > 0">
2018-08-02 01:36:25 +03:00
<h2>%i18n:@invitations%</h2>
2018-03-07 10:48:32 +02:00
<div class="invitation" v-for="i in invitations" tabindex="-1" @click="accept(i)">
2018-05-04 10:27:03 +03:00
<mk-avatar class="avatar" :user="i.parent"/>
2018-08-02 03:52:47 +03:00
<span class="name"><b>{{ i.parent | userName }}</b></span>
2018-03-07 10:48:32 +02:00
<span class="username">@{{ i.parent.username }}</span>
2018-03-29 08:48:47 +03:00
<mk-time :time="i.createdAt"/>
2018-03-07 10:48:32 +02:00
</div>
</section>
<section v-if="myGames.length > 0">
2018-08-02 01:36:25 +03:00
<h2>%i18n:@my-games%</h2>
2018-06-17 02:10:54 +03:00
<a class="game" v-for="g in myGames" tabindex="-1" @click.prevent="go(g)" :href="`/reversi/${g.id}`">
2018-05-04 10:56:23 +03:00
<mk-avatar class="avatar" :user="g.user1"/>
<mk-avatar class="avatar" :user="g.user2"/>
2018-08-02 03:52:47 +03:00
<span><b>{{ g.user1 | userName }}</b> vs <b>{{ g.user2 | userName }}</b></span>
2018-08-02 01:36:25 +03:00
<span class="state">{{ g.isEnded ? '%i18n:@game-state.ended%' : '%i18n:@game-state.playing%' }}</span>
2018-03-10 06:22:20 +02:00
</a>
2018-03-07 04:40:40 +02:00
</section>
2018-03-07 11:45:16 +02:00
<section v-if="games.length > 0">
2018-08-02 01:36:25 +03:00
<h2>%i18n:@all-games%</h2>
2018-06-17 02:10:54 +03:00
<a class="game" v-for="g in games" tabindex="-1" @click.prevent="go(g)" :href="`/reversi/${g.id}`">
2018-05-04 10:56:23 +03:00
<mk-avatar class="avatar" :user="g.user1"/>
<mk-avatar class="avatar" :user="g.user2"/>
2018-08-02 03:52:47 +03:00
<span><b>{{ g.user1 | userName }}</b> vs <b>{{ g.user2 | userName }}</b></span>
2018-08-02 01:36:25 +03:00
<span class="state">{{ g.isEnded ? '%i18n:@game-state.ended%' : '%i18n:@game-state.playing%' }}</span>
2018-03-10 06:22:20 +02:00
</a>
2018-03-06 18:54:56 +02:00
</section>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
2018-06-17 02:10:54 +03:00
import XGameroom from './reversi.gameroom.vue';
2018-03-07 04:40:40 +02:00
2018-03-06 18:54:56 +02:00
export default Vue.extend({
2018-03-07 04:40:40 +02:00
components: {
2018-03-08 10:57:57 +02:00
XGameroom
2018-03-07 04:40:40 +02:00
},
2018-03-09 18:48:16 +02:00
props: ['initGame'],
2018-03-07 04:40:40 +02:00
data() {
return {
game: null,
games: [],
gamesFetching: true,
gamesMoreFetching: false,
2018-03-07 10:48:32 +02:00
myGames: [],
matching: null,
2018-03-07 04:40:40 +02:00
invitations: [],
connection: null,
2018-03-11 11:08:26 +02:00
connectionId: null,
pingClock: null
2018-03-07 04:40:40 +02:00
};
},
2018-03-09 18:48:16 +02:00
watch: {
game(g) {
this.$emit('gamed', g);
}
},
2018-03-09 18:48:16 +02:00
created() {
if (this.initGame) {
this.game = this.initGame;
}
},
2018-03-07 04:40:40 +02:00
mounted() {
if (this.$store.getters.isSignedIn) {
this.connection = (this as any).os.streams.reversiStream.getConnection();
this.connectionId = (this as any).os.streams.reversiStream.use();
2018-03-07 04:40:40 +02:00
this.connection.on('matched', this.onMatched);
this.connection.on('invited', this.onInvited);
2018-03-06 18:54:56 +02:00
(this as any).api('games/reversi/games', {
my: true
}).then(games => {
this.myGames = games;
});
(this as any).api('games/reversi/invitations').then(invitations => {
this.invitations = this.invitations.concat(invitations);
});
this.pingClock = setInterval(() => {
if (this.matching) {
this.connection.send({
type: 'ping',
id: this.matching.id
});
}
}, 3000);
}
2018-03-07 10:48:32 +02:00
2018-07-07 13:01:33 +03:00
(this as any).api('games/reversi/games').then(games => {
2018-03-07 04:40:40 +02:00
this.games = games;
this.gamesFetching = false;
});
},
2018-03-07 04:40:40 +02:00
beforeDestroy() {
if (this.connection) {
this.connection.off('matched', this.onMatched);
this.connection.off('invited', this.onInvited);
(this as any).os.streams.reversiStream.dispose(this.connectionId);
2018-03-11 11:08:26 +02:00
clearInterval(this.pingClock);
}
2018-03-07 04:40:40 +02:00
},
2018-03-07 04:40:40 +02:00
methods: {
2018-03-09 11:29:27 +02:00
go(game) {
2018-07-07 13:01:33 +03:00
(this as any).api('games/reversi/games/show', {
2018-03-29 08:48:47 +03:00
gameId: game.id
2018-03-09 11:29:27 +02:00
}).then(game => {
2018-03-11 11:08:26 +02:00
this.matching = null;
2018-03-09 11:29:27 +02:00
this.game = game;
});
},
2018-03-07 04:40:40 +02:00
match() {
(this as any).apis.input({
2018-08-02 01:36:25 +03:00
title: '%i18n:@enter-username%'
2018-03-07 04:40:40 +02:00
}).then(username => {
(this as any).api('users/show', {
username
}).then(user => {
2018-07-07 13:01:33 +03:00
(this as any).api('games/reversi/match', {
2018-03-29 08:48:47 +03:00
userId: user.id
2018-03-07 04:40:40 +02:00
}).then(res => {
if (res == null) {
this.matching = user;
} else {
this.game = res;
}
});
});
});
},
2018-03-07 10:48:32 +02:00
cancel() {
this.matching = null;
2018-07-07 13:01:33 +03:00
(this as any).api('games/reversi/match/cancel');
2018-03-07 10:48:32 +02:00
},
2018-03-07 10:48:32 +02:00
accept(invitation) {
2018-07-07 13:01:33 +03:00
(this as any).api('games/reversi/match', {
2018-03-29 08:48:47 +03:00
userId: invitation.parent.id
2018-03-07 10:48:32 +02:00
}).then(game => {
if (game) {
2018-03-11 11:08:26 +02:00
this.matching = null;
2018-03-07 10:48:32 +02:00
this.game = game;
}
});
},
2018-03-07 04:40:40 +02:00
onMatched(game) {
2018-03-11 11:08:26 +02:00
this.matching = null;
2018-03-07 04:40:40 +02:00
this.game = game;
},
2018-03-07 04:40:40 +02:00
onInvited(invite) {
this.invitations.unshift(invite);
2018-03-06 18:54:56 +02:00
}
}
});
</script>
2018-03-07 10:48:32 +02:00
<style lang="stylus" scoped>
@import '~const.styl'
2018-08-03 09:59:24 +03:00
root(isDark)
color isDark ? #fff : #677f84
background isDark ? #191b22 : #fff
2018-03-07 10:48:32 +02:00
> .matching
> h1
margin 0
padding 24px
font-size 20px
text-align center
font-weight normal
> .cancel
margin 0 auto
padding 24px 0 0 0
max-width 200px
text-align center
border-top dashed 1px #c4cdd4
> .index
> h1
margin 0
padding 24px
font-size 24px
text-align center
font-weight normal
color #fff
2018-08-03 09:59:24 +03:00
background linear-gradient(to bottom, isDark ? #45730e : #8bca3e, isDark ? #464300 : #d6cf31)
2018-03-07 10:48:32 +02:00
& + p
margin 0
padding 12px
margin-bottom 12px
text-align center
font-size 14px
2018-08-03 09:59:24 +03:00
border-bottom solid 1px isDark ? #535f65 : #d3d9dc
2018-03-07 10:48:32 +02:00
> .play
margin 0 auto
padding 0 16px
max-width 500px
text-align center
> details
margin 8px 0
> div
padding 16px
font-size 14px
text-align left
2018-08-03 09:59:24 +03:00
background isDark ? #282c37 : #f5f5f5
2018-03-07 10:48:32 +02:00
border-radius 8px
> section
margin 0 auto
padding 0 16px 16px 16px
max-width 500px
2018-08-03 09:59:24 +03:00
border-top solid 1px isDark ? #535f65 : #d3d9dc
2018-03-07 10:48:32 +02:00
> h2
margin 0
padding 16px 0 8px 0
font-size 16px
font-weight bold
.invitation
margin 8px 0
padding 8px
border solid 1px #e1e5e8
border-radius 6px
cursor pointer
*
pointer-events none
user-select none
&:focus
border-color $theme-color
&:hover
background #f5f5f5
&:active
background #eee
2018-05-04 10:27:03 +03:00
> .avatar
2018-05-04 11:08:41 +03:00
width 32px
height 32px
2018-03-07 10:48:32 +02:00
border-radius 100%
> span
margin 0 8px
line-height 32px
.game
2018-03-10 06:22:20 +02:00
display block
2018-03-07 10:48:32 +02:00
margin 8px 0
padding 8px
2018-08-03 09:59:24 +03:00
color isDark ? #fff : #677f84
background isDark ? #282c37 : #fff
box-shadow 0 2px 16px rgba(#000, isDark ? 0.7 : 0.15)
2018-03-07 10:48:32 +02:00
border-radius 6px
cursor pointer
*
pointer-events none
user-select none
&:hover
2018-08-03 09:59:24 +03:00
background isDark ? #313543 : #f5f5f5
2018-03-07 10:48:32 +02:00
&:active
2018-08-03 09:59:24 +03:00
background isDark ? #1e222b : #eee
2018-03-07 10:48:32 +02:00
2018-05-04 10:27:03 +03:00
> .avatar
2018-05-04 11:08:41 +03:00
width 32px
height 32px
2018-03-07 10:48:32 +02:00
border-radius 100%
> span
margin 0 8px
line-height 32px
2018-08-03 09:59:24 +03:00
.vchtoekanapleubgzioubdtmlkribzfd[data-darkmode]
root(true)
.vchtoekanapleubgzioubdtmlkribzfd:not([data-darkmode])
root(false)
2018-03-07 10:48:32 +02:00
</style>