First commit
This commit is contained in:
64
components/common/Checkbox.vue
Normal file
64
components/common/Checkbox.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div
|
||||
@click="changeValue()"
|
||||
class="select-none flex flex-row flex-nowrap items-center"
|
||||
:class="getClasses"
|
||||
>
|
||||
<!-- Box -->
|
||||
<fa-icon v-if="value === true" :icon="on" :class="iconSize"></fa-icon>
|
||||
<fa-icon v-else :icon="off" :class="iconSize"></fa-icon>
|
||||
<!-- Label -->
|
||||
<span class="ml-1 my-1 text-primary">
|
||||
<slot></slot>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
on: {
|
||||
type: Array,
|
||||
default: () => ['fa', 'toggle-on']
|
||||
},
|
||||
off: {
|
||||
type: Array,
|
||||
default: () => ['fa', 'toggle-off']
|
||||
},
|
||||
iconSize: {
|
||||
type: String,
|
||||
default: 'text-4xl'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeValue() {
|
||||
if ( ! this.disabled) {
|
||||
this.$emit("input", ! this.value);
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getClasses() {
|
||||
let classes = this.value ? 'text-blue-300 ' : 'text-rose-400 ';
|
||||
if (this.disabled) {
|
||||
classes += ' cursor-not-allowed grayscale-70 opacity-70 ';
|
||||
}
|
||||
else {
|
||||
classes += 'cursor-pointer hover:underline hover:decoration-2 ';
|
||||
classes += this.value ?
|
||||
'hover:text-blue-400 hover:decoration-blue-400 ' :
|
||||
'hover:text-rose-600 hover:decoration-rose-600 ';
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
69
components/common/ContentCategories.vue
Normal file
69
components/common/ContentCategories.vue
Normal file
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<!-- <dropdown :value="value" :index="index" @change="changeValue" ref="select"> -->
|
||||
<dropdown :value="value" @change="changeValue" class="w-52" :disabled="disabled">
|
||||
<option v-if="all" :value="-1">--- All Content ---</option>
|
||||
<optgroup
|
||||
v-for="(step, index) in content"
|
||||
:key="index"
|
||||
:label="step.name"
|
||||
>
|
||||
<option v-for="raid in filterContent(step.content)" :key="raid.id" :value="raid.id">
|
||||
{{ raid.name }}
|
||||
</option>
|
||||
</optgroup>
|
||||
</dropdown>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Content from '@/js/content'
|
||||
|
||||
import Dropdown from '@/components/common/Dropdown.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Dropdown,
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
//required: true, Cannot uncomment, since it can be null
|
||||
type: Number
|
||||
},
|
||||
all: {
|
||||
required: false,
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showPrivateCategories: {
|
||||
required: false,
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
filterContent(content) {
|
||||
if ( ! this.showPrivateCategories) {
|
||||
return content.filter(raid => raid.private !== true);
|
||||
}
|
||||
return content;
|
||||
},
|
||||
changeValue(e) {
|
||||
this.$emit('change', e);
|
||||
if (e.target.value === '') {
|
||||
this.$emit('input', null);
|
||||
}
|
||||
else {
|
||||
this.$emit('input', e.target.value);
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
content() {
|
||||
return Content;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
115
components/common/DataFilter.vue
Normal file
115
components/common/DataFilter.vue
Normal file
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<div class="flex flex-row items-center">
|
||||
<span class="pr-2">{{ category }}</span>
|
||||
|
||||
<span class="inline-flex flex-row flex-wrap btn-group">
|
||||
<button
|
||||
v-if="hasAll"
|
||||
class="btn btn-sm"
|
||||
:class="all ? 'btn-blue' : 'btn-white'"
|
||||
@click="clickAll()"
|
||||
>
|
||||
All
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="btn btn-sm relative"
|
||||
:class="getClassesForItem(item)"
|
||||
v-for="(item, index) in data_view"
|
||||
:key="index"
|
||||
@click="clickItem(index)"
|
||||
>
|
||||
{{ item.name }}
|
||||
<div
|
||||
v-if="count"
|
||||
class="absolute w-5 -top-2 -right-1 z-10 rounded-full text-xs leading-5 tracking-tight bg-tertiary text-primary"
|
||||
>
|
||||
{{ count[index] > 0 ? count[index] : '-' }}
|
||||
</div>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Utils from '@/js/utils.js'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
count: {
|
||||
type: Array,
|
||||
default: undefined
|
||||
},
|
||||
category: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
hasAll: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
all: true,
|
||||
data_view: [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clickAll() {
|
||||
// check
|
||||
if ( ! this.all) {
|
||||
this.all = true;
|
||||
this.data_view.forEach(e => e.checked = false);
|
||||
this.data.forEach(e => e.checked = true);
|
||||
}
|
||||
},
|
||||
clickItem(index) {
|
||||
this.data_view[index].checked = ! this.data_view[index].checked;
|
||||
|
||||
if (this.all === true) {
|
||||
this.all = false;
|
||||
// Propagate change
|
||||
for (let i=0; i<this.data.length; i++) {
|
||||
this.$set(this.data[i], 'checked', this.data_view[i].checked);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.$set(this.data[index], 'checked', this.data_view[index].checked);
|
||||
}
|
||||
},
|
||||
getClassesForItem(item) {
|
||||
let classes = item.checked ? 'btn-blue ' : 'btn-white ';
|
||||
if (this.count) {
|
||||
classes += 'pr-3 ';
|
||||
}
|
||||
return classes;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.hasAll === true) {
|
||||
// Copy data locally to deal with the All button
|
||||
this.data_view = Utils.copy(this.data);
|
||||
|
||||
if (this.data_view.some(e => ! e.checked)) {
|
||||
this.all = false;
|
||||
}
|
||||
else {
|
||||
this.data_view.forEach(e => e.checked = false);
|
||||
this.all = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Data view is the same as the data
|
||||
this.data_view = this.data;
|
||||
|
||||
// Disable All button
|
||||
this.all = false;
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
43
components/common/Dropdown.vue
Normal file
43
components/common/Dropdown.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<div class="inline-block relative">
|
||||
<select :value="value" @change="changeValue" class="block select select-sm w-full" ref="select" :disabled="disabled">
|
||||
<slot></slot>
|
||||
</select>
|
||||
|
||||
<div v-if="! disabled" class="pointer-events-none absolute inset-y-0 right-0 rounded-md flex items-center px-2 text-gray-700">
|
||||
<fa-icon :icon="['fas', 'angle-down']" class="text-xl"></fa-icon>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
required: false
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
required: false,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
changeValue(e) {
|
||||
this.$emit('change', e);
|
||||
this.$emit('input', this.$refs.select.value);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value() {
|
||||
// Selected index takes some time to update. Don't batch it in changeValue
|
||||
this.$nextTick().then(() => {
|
||||
this.$emit('update:index', this.$refs.select.selectedIndex);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
76
components/common/GoogleAds.vue
Normal file
76
components/common/GoogleAds.vue
Normal file
@@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<ins
|
||||
class="adsbygoogle responsive_ad"
|
||||
style="display:block"
|
||||
:style="$isDebug ? 'border: 1px solid grey;' : ''"
|
||||
data-ad-client="ca-pub-2769716391947040"
|
||||
:data-ad-slot="adSlot"
|
||||
:data-ad-region="ad_region"
|
||||
:key="ad_region"
|
||||
data-ad-format="fluid"
|
||||
data-full-width-responsive="true"
|
||||
></ins>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
adSlot: {
|
||||
required: true
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ad_region: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getNewAds() {
|
||||
if (VUE_ENV === 'server') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.ad_region = 'page-' + Math.random();
|
||||
|
||||
this.$nextTick(() => {
|
||||
try {
|
||||
(window.adsbygoogle = window.adsbygoogle || []).push({})
|
||||
} catch (error) {
|
||||
//console.error(error)
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getNewAds();
|
||||
},
|
||||
watch: {
|
||||
'$route.path'(to, from) {
|
||||
if (to !== from) {
|
||||
this.getNewAds();
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.responsive_ad {
|
||||
width: 320px;
|
||||
height: 100px;
|
||||
}
|
||||
@media(min-width: 500px) {
|
||||
.responsive_ad {
|
||||
width: 468px;
|
||||
height: 60px;
|
||||
}
|
||||
}
|
||||
@media(min-width: 800px) {
|
||||
.responsive_ad {
|
||||
width: 728px;
|
||||
height: 90px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
66
components/common/LikeButton.vue
Normal file
66
components/common/LikeButton.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<checkbox
|
||||
v-show="team_owner && ! isMyParty"
|
||||
:value="liked"
|
||||
@input="clickLike"
|
||||
:disabled="team_owner && ! isUserLogged"
|
||||
:title="isUserLogged ? '' : 'Log in to like this team'"
|
||||
:off="['far', 'circle']"
|
||||
:on="['far', 'face-grin-wide']"
|
||||
iconSize="text-3xl"
|
||||
>
|
||||
{{ liked ? 'Liked' : 'Like this team' }}
|
||||
</checkbox>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
import Checkbox from '@/components/common/Checkbox.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Checkbox,
|
||||
},
|
||||
props: {
|
||||
teamId: {
|
||||
type: Number
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clickLike(e) {
|
||||
if (e) {
|
||||
this.axios.get('/party/like/' + this.teamId)
|
||||
.then(_ => {
|
||||
this.$store.dispatch('addMessage', {message: 'You liked this party'});
|
||||
this.liked = e;
|
||||
})
|
||||
.catch(error => this.$store.dispatch('addAxiosErrorMessage', error));
|
||||
}
|
||||
else {
|
||||
this.axios.get('/party/unlike/' + this.teamId)
|
||||
.then(_ => {
|
||||
this.$store.dispatch('addMessage', {message: 'You stopped liking this party'});
|
||||
this.liked = e;
|
||||
})
|
||||
.catch(error => this.$store.dispatch('addAxiosErrorMessage', error));
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
team_owner: state => state.party_builder.team_owner,
|
||||
}),
|
||||
liked: {
|
||||
get() { return this.$store.state.party_builder.liked },
|
||||
set(value) { this.$store.commit('setLiked', value) }
|
||||
},
|
||||
isUserLogged() {
|
||||
return this.$store.getters.getUserId !== null;
|
||||
},
|
||||
isMyParty() {
|
||||
return this.team_owner === this.$store.getters.getUserId;
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
64
components/common/Modal.vue
Normal file
64
components/common/Modal.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div v-if="show" class="fixed inset-0 z-40 flex justify-center items-start bg-black/80" @click.self="close()">
|
||||
<div
|
||||
class="w-screen h-auto mt-8 bg-primary md:rounded flex flex-col overflow-hidden"
|
||||
:class="large ? 'md:w-11/12' : 'md:w-3/4 xl:w-3/5 2xl:1/2'"
|
||||
style="max-height: calc(100vh - 4rem);"
|
||||
>
|
||||
<div class="px-4 py-2 flex flex-col-reverse sm:flex-row sm:justify-between">
|
||||
<slot name="header"></slot>
|
||||
<button @click.prevent="close()" class="self-end sm:self-start">
|
||||
<fa-icon :icon="['fas', 'times-circle']" class="text-link-primary hover:text-link-hover text-2xl"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="overflow-auto break-all px-4" >
|
||||
<slot></slot>
|
||||
</div>
|
||||
|
||||
<div class="px-4 py-2 flex shrink-0">
|
||||
<slot name="footer"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
model: {
|
||||
prop: 'show',
|
||||
event: 'close'
|
||||
},
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
large: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.$emit("close", ! this.show);
|
||||
},
|
||||
toggleOverflow() {
|
||||
if (this.show === true) {
|
||||
document.querySelector("HTML").classList.add("overflow-hidden");
|
||||
}
|
||||
else {
|
||||
document.querySelector("HTML").classList.remove("overflow-hidden");
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
show() {
|
||||
this.toggleOverflow();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.toggleOverflow();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
49
components/common/StatInput.vue
Normal file
49
components/common/StatInput.vue
Normal file
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<label :title="longName">
|
||||
{{ shortName }}
|
||||
<input
|
||||
class="appearance-none text-primary bg-transparent"
|
||||
:class="alignRight ? 'text-right' : ''"
|
||||
type="tel"
|
||||
:style="'width: ' + length + 'ch;'"
|
||||
v-model.number.lazy="localProp"
|
||||
@keydown.arrow-up="incrementProp()"
|
||||
@keydown.arrow-down="decrementProp()"
|
||||
>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
prop: Number,
|
||||
shortName: String,
|
||||
longName: String,
|
||||
length: Number,
|
||||
max: Number,
|
||||
alignRight: Boolean,
|
||||
},
|
||||
methods: {
|
||||
incrementProp() {
|
||||
if (this.max === undefined || this.max > this.localProp) {
|
||||
this.localProp++;
|
||||
}
|
||||
},
|
||||
decrementProp() {
|
||||
if (this.localProp > 0) {
|
||||
this.localProp--;
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
localProp: {
|
||||
get() {
|
||||
return this.prop;
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('update:prop', value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user