Upgrade to AdminLTE v3

This commit is contained in:
Pig Fang 2019-11-24 14:32:58 +08:00
parent 5df36ae8ea
commit 52dae783e8
105 changed files with 2602 additions and 2290 deletions

View File

@ -364,7 +364,7 @@ class AdminController extends Controller
->addButton([
'text' => trans('options.cache.clear'),
'type' => 'a',
'class' => 'pull-right',
'class' => 'float-right',
'style' => 'warning',
'href' => '?clear-cache',
])

View File

@ -65,7 +65,6 @@ class HeadComposer
{
$view->with('styles', [
$this->webpack->url('style.css'),
$this->webpack->url('skins/'.option('color_scheme').'.min.css'),
]);
$view->with('inline_css', option('custom_css'));
}

View File

@ -57,7 +57,6 @@ class SideMenuComposer
}
if (Arr::has($item, 'children')) {
$classes[] = 'treeview';
$item['children'] = array_map(function ($item) {
return $this->transform($item);
}, $item['children']);

View File

@ -18,18 +18,12 @@ class UserMenuComposer
public function compose(View $view)
{
$user = auth()->user();
$view->with('user', $user);
$email = base64_encode($user->email);
$avatar = $user->avatar;
if ($this->request->is('skinlib*') || $this->request->is('/')) {
$view->with(
'tiny_avatar',
url('avatar/25/'.base64_encode($user->email).'.png?tid='.$user->avatar)
);
}
$view->with(
'avatar',
url('avatar/128/'.base64_encode($user->email).'.png?tid='.$user->avatar)
);
$view->with([
'user' => $user,
'avatar' => url('avatar/25/'.$email.'.png?tid='.$avatar),
]);
}
}

View File

@ -19,13 +19,6 @@ class UserPanelComposer
public function compose(View $view)
{
$user = auth()->user();
$roles = [
User::BANNED => 'banned',
User::NORMAL => 'normal',
User::ADMIN => 'admin',
User::SUPER_ADMIN => 'super-admin',
];
$role = $roles[$user->permission];
$avatar = url('avatar/45/'.base64_encode($user->email).'.png?tid='.$user->avatar);
$badges = [];
@ -33,7 +26,6 @@ class UserPanelComposer
$view->with([
'user' => $user,
'role' => trans("admin.users.status.$role"),
'avatar' => $avatar,
'badges' => $badges,
]);

View File

@ -148,7 +148,7 @@ class OptionForm
'name' => '',
], $info);
$classes = "el-button el-button--{$info['style']} ".implode(' ', (array) Arr::get($info, 'class'));
$classes = "btn btn-{$info['style']} ".implode(' ', (array) Arr::get($info, 'class'));
if ($info['href']) {
$this->buttons[] = "<a href='{$info['href']}' class='$classes'>{$info['text']}</a>";

View File

@ -21,7 +21,7 @@
"@babel/runtime": "^7.7.2",
"@fortawesome/fontawesome-free": "^5.11.2",
"@tweenjs/tween.js": "^18.4.2",
"admin-lte": "^2.4.10",
"admin-lte": "^3.0.1",
"echarts": "^4.5.0",
"element-theme-chalk": "^2.12.0",
"element-ui": "^2.12.0",

View File

@ -8,6 +8,7 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 v-t="'user.player.add-player'" class="modal-title" />
<button
type="button"
class="close"
@ -16,7 +17,6 @@
>
<span aria-hidden="true">&times;</span>
</button>
<h4 v-t="'user.player.add-player'" class="modal-title" />
</div>
<div class="modal-body">
<table class="table">
@ -24,24 +24,26 @@
<tr>
<td v-t="'general.player.player-name'" class="key" />
<td class="value">
<el-input v-model="name" type="text" />
<input v-model="name" class="form-control" type="text">
</td>
</tr>
</tbody>
</table>
<div class="callout callout-info">
<ul style="padding: 0 0 0 20px; margin: 0;">
<ul class="m-0 p-0 pl-3">
<li>{{ rule }}</li>
<li>{{ length }}</li>
</ul>
</div>
</div>
<div class="modal-footer">
<el-button data-dismiss="modal">{{ $t('general.close') }}</el-button>
<el-button type="primary" data-test="addPlayer" @click="addPlayer">
<div class="modal-footer d-flex justify-content-between">
<button class="btn btn-default" data-dismiss="modal">
{{ $t('general.close') }}
</button>
<button class="btn btn-primary" data-test="addPlayer" @click="addPlayer">
{{ $t('general.submit') }}
</el-button>
</button>
</div>
</div>
</div>

View File

@ -8,6 +8,7 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 v-t="'user.closet.use-as.title'" class="modal-title" />
<button
type="button"
class="close"
@ -16,7 +17,6 @@
>
<span aria-hidden="true">&times;</span>
</button>
<h4 v-t="'user.closet.use-as.title'" class="modal-title" />
</div>
<div class="modal-body">
<template v-if="players.length !== 0">
@ -35,17 +35,18 @@
</template>
<p v-else v-t="'user.closet.use-as.empty'" />
</div>
<div class="modal-footer">
<div class="modal-footer d-flex justify-content-between">
<a
v-if="allowAdd"
v-t="'user.closet.use-as.add'"
data-toggle="modal"
data-target="#modal-add-player"
class="el-button pull-left"
class="btn btn-default"
href="#"
/>
<el-button type="primary" data-test="submit" @click="submit">
<button class="btn btn-primary" data-test="submit" @click="submit">
{{ $t('general.submit') }}
</el-button>
</button>
</div>
</div>
</div>

View File

@ -1,6 +1,6 @@
<template>
<div v-if="recaptcha" class="row">
<div class="col-xs-12" style="padding-bottom: 5px">
<div class="d-block ml-2 pb-3">
<vue-recaptcha
ref="recaptcha"
:size="invisible ? 'invisible' : ''"
@ -9,22 +9,20 @@
/>
</div>
</div>
<div v-else class="row">
<div class="col-xs-8">
<div class="form-group has-feedback">
<input
ref="captcha"
v-model="value"
type="text"
class="form-control"
:placeholder="$t('auth.captcha')"
required
>
</div>
<div v-else class="d-flex">
<div class="form-group mb-3 mr-2">
<input
ref="captcha"
v-model="value"
type="text"
class="form-control"
:placeholder="$t('auth.captcha')"
required
>
</div>
<div class="col-xs-4">
<div>
<img
class="pull-right captcha"
class="captcha"
:src="`${baseUrl}/auth/captcha?v=${time}`"
alt="CAPTCHA"
:title="$t('auth.change-captcha')"

View File

@ -1,48 +1,51 @@
<template>
<texture-item :class="{ 'item-selected': selected }">
<div @click="$emit('select')">
<img :src="previewLink">
<div class="card mr-3 mb-3 closet-item" :class="{ shadow: selected }">
<div class="card-body texture-img" @click="$emit('select')">
<img class="card-img-top" :src="previewLink">
</div>
<div class="card-footer pb-2 pt-2 pl-1 pr-1">
<div class="container d-flex justify-content-between">
<span data-test="name" :title="name">
{{ textureName }} <small>({{ type }})</small>
</span>
<template #footer :class="{ 'item-selected': selected }">
<p class="texture-name">
<span :title="name">{{ textureName }} <small>({{ type }})</small></span>
</p>
<a
:href="linkToSkinlib"
:title="$t('user.viewInSkinlib')"
class="more"
data-toggle="tooltip"
data-placement="bottom"
><i class="fas fa-share" /></a>
<span
id="more-button"
:title="$t('general.more')"
class="more"
data-toggle="dropdown"
aria-haspopup="true"
><i class="fas fa-cog" /></span>
<ul class="dropup dropdown-menu" aria-labelledby="more-button">
<li><a v-t="'user.renameItem'" @click="rename" /></li>
<li><a v-t="'user.removeItem'" @click="removeClosetItem" /></li>
<li><a v-if="type !== 'cape'" v-t="'user.setAsAvatar'" @click="setAsAvatar" /></li>
</ul>
</template>
</texture-item>
<a class="float-right dropdown">
<span
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
<i class="fas fa-cog text-gray" />
</span>
<div class="dropdown-menu">
<a class="dropdown-item" href="#" @click="rename">
{{ $t('user.renameItem') }}
</a>
<a class="dropdown-item" href="#" @click="removeClosetItem">
{{ $t('user.removeItem') }}
</a>
<a :href="linkToSkinlib" class="dropdown-item">
{{ $t('user.viewInSkinlib') }}
</a>
<a
v-if="type !== 'cape'"
class="dropdown-item"
href="#"
@click="setAsAvatar"
>{{ $t('user.setAsAvatar') }}</a>
</div>
</a>
</div>
</div>
</div>
</template>
<script>
import TextureItem from './TextureItem.vue'
import setAsAvatar from './mixins/setAsAvatar'
import removeClosetItem from './mixins/removeClosetItem'
export default {
name: 'ClosetItem',
components: {
TextureItem,
},
mixins: [
removeClosetItem,
setAsAvatar,
@ -105,3 +108,19 @@ export default {
},
}
</script>
<style lang="stylus">
.closet-item
width 235px
transition-property box-shadow
transition-duration 0.3s
&:hover
box-shadow 0 .5rem 1rem rgba(0,0,0,.15)
cursor pointer
.fa-cog:hover
color #000
.texture-img
background #eff1f0
</style>

View File

@ -1,9 +1,11 @@
<template>
<div class="box box-default">
<div class="box-header with-border">
<h3 class="box-title" style="width: 100%;">
<span v-html="$t(title)" /> <!-- eslint-disable-line vue/no-v-html -->
<span data-toggle="tooltip" class="badge bg-light-blue">{{ indicator }}</span>
<div class="card">
<div class="card-header">
<div class="d-flex justify-content-between">
<h3 class="card-title">
<span v-html="$t(title)" /> <!-- eslint-disable-line vue/no-v-html -->
<span class="badge bg-olive">{{ indicator }}</span>
</h3>
<div class="operations">
<i
data-toggle="tooltip"
@ -35,14 +37,14 @@
@click="reset"
/>
</div>
</h3>
</div>
</div>
<div class="box-body">
<div class="card-body">
<div ref="previewer" class="previewer-3d">
<!-- Container for 3D Preview -->
</div>
</div>
<div v-if="$slots.footer" class="box-footer">
<div v-if="$slots.footer" class="card-footer">
<slot name="footer" />
</div>
</div>
@ -174,14 +176,10 @@ export default {
cursor move
.operations
display inline
float right
i
padding .5em .5em
display inline
i:hover
color #555
cursor pointer
&:hover
color #555
cursor pointer
</style>

View File

@ -1,46 +1,43 @@
<template>
<a :href="urlToDetail">
<texture-item>
<div class="item-body">
<img :src="urlToPreview">
<a class="ml-3 mr-2 mb-2" :href="urlToDetail">
<div class="card skinlib-item">
<div class="card-body texture-img">
<div v-if="!isPublic" class="ribbon-wrapper">
<div class="ribbon bg-pink">{{ $t('skinlib.private') }}</div>
</div>
<img class="card-img-top" :src="urlToPreview">
</div>
<div class="card-footer pb-0 pt-2 pl-1 pr-1">
<div class="container d-flex justify-content-between">
<p>
<span :title="name">{{ name }}
<small>{{ $t('skinlib.filter.' + type) }}</small>
</span>
</p>
<template #footer>
<p class="texture-name">
<span :title="name">{{ name }}
<small>{{ $t('skinlib.filter.' + type) }}</small>
</span>
</p>
<a
:title="likeActionText"
class="btn-like"
:class="{ liked }"
href="#"
@click.stop="toggleLiked"
>
<i class="fas fa-heart" />
<span>{{ likes }}</span>
</a>
</div>
<a
:title="likeActionText"
class="more like"
:class="{ liked, anonymous }"
href="#"
@click.stop="toggleLiked"
>
<i class="fas fa-heart" />
<span>{{ likes }}</span>
</a>
<small v-if="!isPublic" class="more private-label">
{{ $t('skinlib.private') }}
</small>
</template>
</texture-item>
</div>
</div>
</a>
</template>
<script>
import TextureItem from './TextureItem.vue'
import addClosetItem from './mixins/addClosetItem'
import removeClosetItem from './mixins/removeClosetItem'
export default {
name: 'SkinLibItem',
components: {
TextureItem,
},
mixins: [
addClosetItem,
removeClosetItem,
@ -94,30 +91,18 @@ export default {
</script>
<style lang="stylus">
.texture-name
width 65%
display inline-block
overflow hidden
text-overflow ellipsis
white-space nowrap
.skinlib-item
width 245px
transition-property box-shadow
transition-duration 0.3s
&:hover
box-shadow 0 .5rem 1rem rgba(0, 0, 0, 0.15)
@media (min-width: 1200px)
.item
width 250px
.texture-img
background #eff1f0
.item-body > img
margin-left 50px
.texture-name
width 65%
.item-footer
a
color #fff
.like:hover, .liked
.btn-like
color #6c757d
&.liked, &:hover
color #e0353b
.private-label
margin-top 2px
</style>

View File

@ -1,87 +0,0 @@
<template>
<div class="item">
<div class="item-body">
<slot />
</div>
<div class="item-footer">
<slot name="footer" />
</div>
</div>
</template>
<script>
export default {
name: 'TextureItem',
}
</script>
<style lang="stylus">
.item
display block
background #EFF1F0
box-shadow 0 1px 1px rgba(0, 0, 0, 0.1)
border-radius 2px
float left
position relative
margin-right 20px
margin-bottom 20px
cursor pointer
width 210px
height 196px
transition box-shadow 0.1s ease-in-out 0s
.item-body
height 166px
img
max-width 100%
margin-left 30px
margin-top 16px
width 150px
@media (max-width: 756px)
.item
width 45%
margin-right 5%
.item-body > img
margin-left 25%
.texture-name
width 65%
@media (max-width: 520px)
.item
width 100%
.item-body > img
margin-left 30%
.texture-name
width 80%
.item:hover
box-shadow 0 6px 12px rgba(0, 0, 0, 0.175)
.item-selected
box-shadow 0 6px 12px rgba(0, 0, 0, 0.175)
.item-footer
background #50b3ec
color #fff
font-size 16px
height 30px
padding 3px 8px
.more
float right
margin-left 6px
margin-right 3px
color #fff
.more:hover
color #dadada
small
font-size 50%
</style>

View File

@ -12,12 +12,9 @@ export async function checkForUpdates(): Promise<void> {
if (response.ok) {
const data = await response.json()
const el = document.querySelector(`[href="${blessing.base_url}/admin/update"]`)
const el = document.querySelector(`[href="${blessing.base_url}/admin/update"] p`)
if (data.available && el) {
el.innerHTML += `
<span class="pull-right-container">
<span class="label label-primary pull-right">1</span>
</span>`
el.innerHTML += '<span class="right badge badge-primary">New</span>'
}
}
}
@ -27,12 +24,9 @@ export async function checkForPluginUpdates(): Promise<void> {
if (response.ok) {
const data = await response.json()
const el = document.querySelector(`[href="${blessing.base_url}/admin/plugins/market"]`)
const el = document.querySelector(`[href="${blessing.base_url}/admin/plugins/market"] p`)
if (data.available && el) {
el.innerHTML += `
<span class="pull-right-container">
<span class="label label-success pull-right">${data.plugins.length}</span>
</span>`
el.innerHTML += `<span class="right badge badge-success">${data.plugins.length}</span>`
}
}
}

View File

@ -1,5 +1,5 @@
function handler() {
const header = document.querySelector('.main-header')
const header = document.querySelector('.navbar')
/* istanbul ignore else */
if (header) {
window.addEventListener('scroll', () => {

View File

@ -1,16 +1,16 @@
/* eslint-disable import/no-extraneous-dependencies */
import './public-path' // Must be first
import 'jquery'
import 'bootstrap/js/collapse'
import 'bootstrap/js/dropdown'
import 'bootstrap/js/modal'
import 'bootstrap/js/transition'
import 'admin-lte/build/js/Layout'
import 'admin-lte/build/js/PushMenu'
import 'admin-lte/build/js/Tree'
import $ from 'jquery'
import 'bootstrap'
import 'admin-lte'
import './i18n'
import './net'
import './event'
import './notification'
import './element'
import './logout'
window.addEventListener('load', () => {
// @ts-ignore
$('[data-toggle="tooltip"]').tooltip()
})

View File

@ -20,23 +20,25 @@ export function showModal(
const destroyOnClose = options.destroyOnClose !== false
const dom = `
<div class="modal modal-${type} fade in">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">${title}</h4>
</div>
<div class="modal-body">
<p>${message}</p>
</div>
<div class="modal-footer">
<button type="button" ${onClick} class="btn ${btnType}">${btnText}</button>
</div>
</div>
<div class="modal fade in">
<div class="modal-dialog">
<div class="modal-content bg-${type}">
<div class="modal-header">
<h4 class="modal-title">${title}</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>${message}</p>
</div>
<div class="modal-footer">
<button type="button" ${onClick} class="btn btn-outline-light ${btnType}">
${btnText}
</button>
</div>
</div>
</div>
</div>`
$(dom)

View File

@ -14,12 +14,12 @@ export default [
{
path: 'user/closet',
component: () => import('../views/user/Closet.vue'),
el: '.content',
el: '.content > .container-fluid',
},
{
path: 'user/player',
component: () => import('../views/user/Players.vue'),
el: '.content',
el: '.content > .container-fluid',
},
{
path: 'user/player/bind',
@ -29,36 +29,38 @@ export default [
{
path: 'user/reports',
component: () => import('../views/user/Report.vue'),
el: '.content',
el: '.content > .container-fluid',
},
{
path: 'user/profile',
component: () => import('../views/user/Profile.vue'),
el: '.content',
el: '.content > .container-fluid',
},
{
path: 'user/oauth/manage',
component: () => import('../views/user/OAuth.vue'),
el: '.content',
el: '.content > .container-fluid',
},
{
path: 'admin',
module: [() => import('../views/admin/Dashboard')],
module: [
() => import('../views/admin/Dashboard'),
],
},
{
path: 'admin/users',
component: () => import('../views/admin/Users.vue'),
el: '.content',
el: '.content > .container-fluid',
},
{
path: 'admin/players',
component: () => import('../views/admin/Players.vue'),
el: '.content',
el: '.content > .container-fluid',
},
{
path: 'admin/reports',
component: () => import('../views/admin/Reports.vue'),
el: '.content',
el: '.content > .container-fluid',
},
{
path: 'admin/customize',
@ -74,12 +76,12 @@ export default [
{
path: 'admin/plugins/manage',
component: () => import('../views/admin/Plugins.vue'),
el: '.content',
el: '.content > .container-fluid',
},
{
path: 'admin/plugins/market',
component: () => import('../views/admin/Market.vue'),
el: '.content',
el: '.content > .container-fluid',
},
{
path: 'admin/update',
@ -114,11 +116,11 @@ export default [
{
path: 'skinlib/show/(\\d+)',
component: () => import('../views/skinlib/Show.vue'),
el: '.content > .row:nth-child(1)',
el: '.content > .container-fluid > .row:nth-child(1)',
},
{
path: 'skinlib/upload',
component: () => import('../views/skinlib/Upload.vue'),
el: '.content',
el: '.content > .container-fluid',
},
]

View File

@ -1,11 +1,8 @@
.login-logo a
font-family Minecraft, Ubuntu, 'Segoe UI', 'Microsoft Yahei', 'Microsoft Jhenghei', sans-serif
font-family Minecraft, 'Segoe UI', 'Microsoft Yahei', sans-serif
transition all 0.2s ease-in-out
&:hover
color #42a5f5
.captcha
cursor pointer
.auth-btn.el-button
width 100%

View File

@ -1,42 +1,13 @@
@import './auth'
@import './admin'
font_stack = Ubuntu, 'Segoe UI', 'Microsoft Yahei', 'Microsoft Jhenghei', sans-serif
@font-face
font-family 'Ubuntu'
src url('../fonts/ubuntu.woff2') format('woff2'), url('../fonts/ubuntu.woff') format('woff')
@font-face
font-family 'Minecraft'
src url('../fonts/minecraft.woff2') format('woff2'), url('../fonts/minecraft.woff') format('woff')
body, h1, h2, h3, h4, h5, h6
font-family font_stack
.logo-lg, .navbar-brand
.brand-link, .navbar-brand
font-family Minecraft
// AdminLTE 2 is not compatible with Font Awesome 5
.main-header .sidebar-toggle::before
content ''
.box-footer > p
margin 6px 15px 5px 0
@media (max-width: 767px)
.dropdown-menu > li.locale
a
color #777
a:hover
background-color #e1e3e9
color #333
/* hide the text on mobile phone pages */
.description-text
display none
.key
vertical-align middle
@ -54,15 +25,8 @@ body, h1, h2, h3, h4, h5, h6
td.value
width 90%
.main-header .navbar .user-menu .user-image
border-radius 10%
.breadcrumb
font-size 14px
.navbar-nav > .user-menu > .dropdown-menu > li.user-header
height unset
#language-menu li
a
color #777
a:hover
background-color #e1e3e9
color #333
.user-panel .info
cursor default

View File

@ -6,87 +6,28 @@ body
background-size cover
background-repeat no-repeat
background-position center 0
height 100vh
.main-header
.navbar
transition color 0.25s ease-in-out, border-color 0.25s ease-in-out, background-color 0.25s ease-in-out
.navbar-brand
font-family Minecraft, 'Segoe UI', 'Microsoft Yahei', 'Microsoft Jhenghei', sans-serif
border-right 0
.navbar-custom-menu .navbar-nav > li
a.btn.btn-login
background-color transparent
border-radius 5px
border 1px solid #fff
color #fff !important
margin-top 7px
margin-left 10px
padding 8px 20px
transition border-color 0.25s ease-in-out, background-color 0.3s ease-in-out
.navbar
transition color 0.25s ease-in-out, border-color 0.25s ease-in-out, background-color 0.25s ease-in-out
a.btn.btn-login:hover, a.btn.btn-login:focus
background-color #006acc !important
.navbar-brand
font-family Minecraft, 'Segoe UI', 'Microsoft Yahei', 'Microsoft Jhenghei', sans-serif
border-right 0
.main-header.transparent
.navbar-brand
.transparent
.navbar-brand, .navbar-header > a
color #5e5e5e
.navbar-header > a
color #5e5e5e
.navbar
&.navbar
background-color rgba(255, 255, 255, 0.2)
.navbar-nav
li
a
border 0
color #5e5e5e
a:hover
background rgba(0, 0, 0, 0.1)
color #f6f6f6
.active > a
background rgba(0, 0, 0, 0.1)
color #f6f6f6
.user-menu li
a.btn
border 1px solid #ddd
color #5e5e5e
a:hover
background-color transparent
a.btn:hover
background-color #e7e7e7
border-color #adadad
.navbar-custom-menu .navbar-nav > li
a.btn.btn-login
background-color #0078e7
border 1px solid #0078e7
.nickname
color #5e5e5e
.content-wrapper
background-color transparent
border none
.main-footer
background-color transparent
border none
div
color #fff !important
a
color #fff !important
.navbar-nav li a
border 0
color #5e5e5e
&:hover
background rgba(0, 0, 0, 0.2)
color #f6f6f6
.splash
width 80%
@ -138,7 +79,7 @@ body
.splash-head
font-size 300%
.container .button
.button
color white
padding 0.8em 2.5em
border-radius 5px
@ -147,7 +88,8 @@ body
font-size 120%
transition color 0.25s ease-in-out, border-color 0.25s ease-in-out, background-color 0.25s ease-in-out
.container .button:hover
.button:hover
color white
background-color rgba(255, 255, 255, 0.2)
hr
@ -201,3 +143,14 @@ Wrap Sections
.col-lg-6:last-child
text-align right
padding-top 20px
#copyright
color #fff
&.with-intro
background #222
padding 16px 0 20px
&.without-intro
position fixed
bottom 0
width 100%
padding 0 50px 16px 50px

View File

@ -1,5 +1,5 @@
<template>
<section class="content">
<div class="container-fluid">
<vue-good-table
:rows="plugins"
:columns="columns"
@ -20,7 +20,7 @@
<span
v-for="(constraint, name) in props.row.dependencies.all"
:key="name"
class="label"
class="badge"
:class="`bg-${name in props.row.dependencies.unsatisfied ? 'red' : 'green'}`"
>
{{ name }}: {{ constraint }}
@ -30,10 +30,9 @@
</span>
<span v-else-if="props.column.field === 'operations'">
<template v-if="props.row.installed">
<el-button
<button
v-if="props.row.update_available"
type="success"
size="medium"
class="btn btn-success"
:disabled="installing === props.row.name"
@click="updatePlugin(props.row)"
>
@ -43,27 +42,17 @@
<template v-else>
<i class="fas fa-sync-alt" /> {{ $t('admin.updatePlugin') }}
</template>
</el-button>
<el-button
v-else-if="props.row.enabled"
type="primary"
size="medium"
disabled
>
</button>
<button v-else-if="props.row.enabled" class="btn btn-primary" disabled>
<i class="fas fa-check" /> {{ $t('admin.statusEnabled') }}
</el-button>
<el-button
v-else
type="primary"
size="medium"
@click="enablePlugin(props.row)"
>
</button>
<button v-else class="btn btn-primary" @click="enablePlugin(props.row)">
<i class="fas fa-plug" /> {{ $t('admin.enablePlugin') }}
</el-button>
</button>
</template>
<el-button
<button
v-else
size="medium"
class="btn btn-default"
:disabled="installing === props.row.name"
@click="installPlugin(props.row)"
>
@ -73,12 +62,12 @@
<template v-else>
<i class="fas fa-download" /> {{ $t('admin.installPlugin') }}
</template>
</el-button>
</button>
</span>
<span v-else v-text="props.formattedRow[props.column.field]" />
</template>
</vue-good-table>
</section>
</div>
</template>
<script>
@ -115,6 +104,7 @@ export default {
label: this.$t('admin.pluginVersion'),
sortable: false,
globalSearchDisabled: true,
width: '5%',
},
{
field: 'dependencies',
@ -127,6 +117,7 @@ export default {
label: this.$t('admin.operationsTitle'),
sortable: false,
globalSearchDisabled: true,
width: '12%',
},
],
installing: '',

View File

@ -1,5 +1,5 @@
<template>
<section class="content">
<div class="container-fluid">
<vue-good-table
mode="remote"
:rows="players"
@ -46,17 +46,17 @@
</a>
</span>
<span v-else-if="props.column.field === 'operations'">
<el-button
<button
data-toggle="modal"
data-target="#modal-change-texture"
size="medium"
class="btn btn-default"
@click="textureChanges.originalIndex = props.row.originalIndex"
>{{ $t('admin.changeTexture') }}</el-button>
<el-button
type="danger"
size="medium"
@click="deletePlayer(props.row)"
>{{ $t('admin.deletePlayer') }}</el-button>
>
{{ $t('admin.changeTexture') }}
</button>
<button class="btn btn-danger" @click="deletePlayer(props.row)">
{{ $t('admin.deletePlayer') }}
</button>
</span>
<span v-else v-text="props.formattedRow[props.column.field]" />
</template>
@ -71,6 +71,7 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 v-t="'admin.changeTexture'" class="modal-title" />
<button
type="button"
class="close"
@ -79,7 +80,6 @@
>
<span aria-hidden="true">&times;</span>
</button>
<h4 v-t="'admin.changeTexture'" class="modal-title" />
</div>
<div class="modal-body">
<div class="form-group">
@ -99,16 +99,18 @@
>
</div>
</div>
<div class="modal-footer">
<el-button data-dismiss="modal">{{ $t('general.close') }}</el-button>
<el-button type="primary" data-test="changeTexture" @click="changeTexture">
<div class="modal-footer d-flex justify-content-between">
<button class="btn btn-default" data-dismiss="modal">
{{ $t('general.close') }}
</button>
<button class="btn btn-primary" data-test="changeTexture" @click="changeTexture">
{{ $t('general.submit') }}
</el-button>
</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div>
</div>
</div>
</section>
</div>
</template>
<script>

View File

@ -1,5 +1,5 @@
<template>
<section class="content">
<div class="container-fluid">
<vue-good-table
:rows="plugins"
:columns="columns"
@ -60,7 +60,7 @@
<span
v-for="(constraint, name) in props.row.dependencies.all"
:key="name"
class="label"
class="badge"
:class="`bg-${name in props.row.dependencies.unsatisfied ? 'red' : 'green'}`"
>
{{ name }}: {{ constraint }}
@ -71,7 +71,7 @@
<span v-else v-text="props.formattedRow[props.column.field]" />
</template>
</vue-good-table>
</section>
</div>
</template>
<script>
@ -174,8 +174,11 @@ export default {
a
color #337ab7
.plugin > td:first-child
border-left 5px solid transparent
.plugin:nth-of-type(2n+1) > td:first-child
border-left 5px solid rgba(51, 68, 109, 0.03)
.plugin:nth-of-type(2n) > td:first-child
border-left 5px solid #fff
.plugin-enabled
background-color #f7fcfe

View File

@ -1,5 +1,5 @@
<template>
<section class="content">
<div class="container-fluid">
<vue-good-table
mode="remote"
:rows="reports"
@ -34,16 +34,16 @@
{{ $t(`report.status.${props.row.status}`) }}
</span>
<span v-else-if="props.column.field === 'ops'">
<el-button size="medium" @click="reject(props.row)">
<button class="btn btn-default" @click="reject(props.row)">
{{ $t('report.reject') }}
</el-button>
</button>
</span>
<span v-else>
{{ props.formattedRow[props.column.field] }}
</span>
</template>
</vue-good-table>
</section>
</div>
</template>
<script>

View File

@ -9,12 +9,12 @@
>
<template #table-row="props">
<span v-if="props.column.field === 'operations'">
<el-button size="medium" @click="modify(props.row)">
<button class="btn btn-default" @click="modify(props.row)">
{{ $t('admin.i18n.modify') }}
</el-button>
<el-button type="danger" size="medium" @click="remove(props.row)">
</button>
<button class="btn btn-danger" @click="remove(props.row)">
{{ $t('admin.i18n.delete') }}
</el-button>
</button>
</span>
<span v-else-if="props.column.field === 'text'">
<span v-if="props.row.text" v-text="props.formattedRow[props.column.field]" />

View File

@ -1,14 +1,16 @@
<template>
<span>
<el-button
<button
v-if="!updating"
type="primary"
class="btn btn-primary"
:disabled="!canUpdate"
@click="update"
>{{ $t('admin.updateButton') }}</el-button>
<el-button v-else disabled type="primary">
>
{{ $t('admin.updateButton') }}
</button>
<button v-else disabled class="btn btn-primary">
<i class="fa fa-spinner fa-spin" /> {{ $t('admin.downloading') }}
</el-button>
</button>
<div
id="modal-download"
@ -24,7 +26,7 @@
<div class="modal-body">
<div class="progress">
<div
class="progress-bar progress-bar-striped active"
class="progress-bar progress-bar-striped bg-primary"
role="progressbar"
aria-valuenow="0"
aria-valuemin="0"

View File

@ -1,5 +1,5 @@
<template>
<section class="content">
<div class="container-fluid">
<vue-good-table
mode="remote"
:rows="users"
@ -62,28 +62,26 @@
<i
class="fas btn-edit"
:class="{ 'fa-toggle-on': props.row.verified, 'fa-toggle-off': !props.row.verified }"
style="font-size: 18px;"
/>
</a>
</span>
<div v-else-if="props.column.field === 'operations'">
<el-button size="medium" @click="changePassword(props.row)">
<button class="btn btn-default" @click="changePassword(props.row)">
{{ $t('admin.changePassword') }}
</el-button>
<el-button
</button>
<button
:disabled="props.row.permission >= 2 || (props.row.operations === 1 && props.row.permission >= 1)"
type="danger"
size="medium"
class="btn btn-danger"
data-test="deleteUser"
@click="deleteUser(props.row)"
>
{{ $t('admin.deleteUser') }}
</el-button>
</button>
</div>
<span v-else v-text="props.formattedRow[props.column.field]" />
</template>
</vue-good-table>
</section>
</div>
</template>
<script>
@ -328,6 +326,13 @@ export default {
.operations-menu
margin-left -35px
.fa-edit
cursor pointer
.fa-toggle-on, .fa-toggle-off
font-size 18px
cursor pointer
.row-at-bottom
margin-top -100px
</style>

View File

@ -1,6 +1,6 @@
<template>
<form @submit.prevent="submit">
<div class="form-group has-feedback">
<div class="input-group mb-3">
<input
v-model="email"
type="email"
@ -8,31 +8,36 @@
:placeholder="$t('auth.email')"
required
>
<span class="glyphicon glyphicon-envelope form-control-feedback" />
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-envelope" />
</div>
</div>
</div>
<captcha ref="captcha" />
<div class="callout callout-success" :class="{ hide: !successMsg }">{{ successMsg }}</div>
<div class="callout callout-warning" :class="{ hide: !warningMsg }">{{ warningMsg }}</div>
<div class="alert alert-success" :class="{ 'd-none': !successMsg }">
<i class="icon fas fa-check" />
{{ successMsg }}
</div>
<div class="alert alert-warning" :class="{ 'd-none': !warningMsg }">
<i class="icon fas fa-exclamation-triangle" />
{{ warningMsg }}
</div>
<div class="row">
<div class="col-xs-7">
<a v-t="'auth.forgot.login-link'" :href="`${baseUrl}/auth/login`" class="text-center" />
</div>
<div class="col-xs-5">
<el-button
type="primary"
native-type="submit"
:disabled="pending"
class="auth-btn"
>
<template v-if="pending">
<i class="fa fa-spinner fa-spin" /> {{ $t('auth.sending') }}
</template>
<span v-else>{{ $t('auth.forgot.button') }}</span>
</el-button>
</div>
<div class="d-flex justify-content-between">
<a v-t="'auth.forgot.login-link'" :href="`${baseUrl}/auth/login`" class="text-center" />
<button
class="btn btn-primary"
type="submit"
:disabled="pending"
>
<template v-if="pending">
<i class="fa fa-spinner fa-spin" /> {{ $t('auth.sending') }}
</template>
<span v-else>{{ $t('auth.forgot.button') }}</span>
</button>
</div>
</form>
</template>

View File

@ -1,15 +1,19 @@
<template>
<form @submit.prevent="login">
<div class="form-group has-feedback">
<div class="input-group mb-3">
<input
v-model="identification"
class="form-control"
:placeholder="$t('auth.identification')"
required
>
<span class="glyphicon glyphicon-envelope form-control-feedback" />
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-envelope" />
</div>
</div>
</div>
<div class="form-group has-feedback">
<div class="input-group mb-3">
<input
v-model="password"
type="password"
@ -17,37 +21,37 @@
:placeholder="$t('auth.password')"
required
>
<span class="glyphicon glyphicon-lock form-control-feedback" />
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-lock" />
</div>
</div>
</div>
<captcha v-if="tooManyFails" ref="captcha" />
<div class="callout callout-warning" :class="{ hide: !warningMsg }">{{ warningMsg }}</div>
<div class="alert alert-warning" :class="{ 'd-none': !warningMsg }">
<i class="icon fas fa-exclamation-triangle" />
{{ warningMsg }}
</div>
<div class="row">
<div class="col-xs-6">
<div class="d-flex justify-content-between mb-3">
<div>
<el-switch v-model="remember" :active-text="$t('auth.keep')" />
</div>
<div class="col-xs-6">
<a v-t="'auth.forgot-link'" class="pull-right" :href="`${baseUrl}/auth/forgot`" />
</div>
<a v-t="'auth.forgot-link'" :href="`${baseUrl}/auth/forgot`" />
</div>
<div class="row">
<div class="col-xs-12">
<el-button
type="primary"
native-type="submit"
:disabled="pending"
class="auth-btn"
>
<template v-if="pending">
<i class="fa fa-spinner fa-spin" /> {{ $t('auth.loggingIn') }}
</template>
<span v-else>{{ $t('auth.login') }}</span>
</el-button>
</div>
</div>
<button
class="btn btn-block btn-primary"
type="submit"
:disabled="pending"
>
<template v-if="pending">
<i class="fa fa-spinner fa-spin" /> {{ $t('auth.loggingIn') }}
</template>
<span v-else>{{ $t('auth.login') }}</span>
</button>
</form>
</template>
@ -127,11 +131,3 @@ export default {
},
}
</script>
<style lang="stylus">
#login-button
margin-top 5px
.el-button
margin-top 10px
</style>

View File

@ -1,6 +1,6 @@
<template>
<form @submit.prevent="submit">
<div class="form-group has-feedback">
<div class="input-group mb-3">
<input
v-model="email"
type="email"
@ -8,9 +8,13 @@
:placeholder="$t('auth.email')"
required
>
<span class="glyphicon glyphicon-envelope form-control-feedback" />
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-envelope" />
</div>
</div>
</div>
<div class="form-group has-feedback">
<div class="input-group mb-3">
<input
v-model="password"
type="password"
@ -20,9 +24,13 @@
minlength="8"
maxlength="32"
>
<span class="glyphicon glyphicon-lock form-control-feedback" />
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-lock" />
</div>
</div>
</div>
<div class="form-group has-feedback">
<div class="input-group mb-3">
<input
ref="confirm"
v-model="confirm"
@ -33,12 +41,16 @@
minlength="8"
maxlength="32"
>
<span class="glyphicon glyphicon-log-in form-control-feedback" />
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-sign-in-alt" />
</div>
</div>
</div>
<div
v-if="requirePlayer"
class="form-group has-feedback"
class="input-group mb-3"
:title="$t('auth.player-name-intro')"
data-placement="top"
data-toggle="tooltip"
@ -50,11 +62,15 @@
:placeholder="$t('auth.player-name')"
required
>
<span class="glyphicon glyphicon-pencil form-control-feedback" />
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-gamepad" />
</div>
</div>
</div>
<div
v-else
class="form-group has-feedback"
class="input-group mb-3"
:title="$t('auth.nickname-intro')"
data-placement="top"
data-toggle="tooltip"
@ -66,30 +82,37 @@
:placeholder="$t('auth.nickname')"
required
>
<span class="glyphicon glyphicon-pencil form-control-feedback" />
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-gamepad" />
</div>
</div>
</div>
<captcha ref="captcha" />
<div class="callout callout-info" :class="{ hide: !infoMsg }">{{ infoMsg }}</div>
<div class="callout callout-warning" :class="{ hide: !warningMsg }">{{ warningMsg }}</div>
<div class="alert alert-info" :class="{ 'd-none': !infoMsg }">
<i class="icon fas fa-info" />
{{ infoMsg }}
</div>
<div class="alert alert-warning" :class="{ 'd-none': !warningMsg }">
<i class="icon fas fa-exclamation-triangle" />
{{ warningMsg }}
</div>
<div class="row">
<div class="col-xs-7">
<a v-t="'auth.login-link'" :href="`${baseUrl}/auth/login`" class="text-center" />
</div>
<div class="col-xs-5">
<el-button
type="primary"
native-type="submit"
<div class="d-flex justify-content-between mb-3">
<a v-t="'auth.login-link'" :href="`${baseUrl}/auth/login`" class="text-center" />
<div>
<button
class="btn btn-primary"
type="submit"
:disabled="pending"
class="auth-btn"
>
<template v-if="pending">
<i class="fa fa-spinner fa-spin" /> {{ $t('auth.registering') }}
</template>
<span v-else>{{ $t('auth.register-button') }}</span>
</el-button>
</button>
</div>
</div>
</form>

View File

@ -1,6 +1,6 @@
<template>
<form @submit.prevent="reset">
<div class="form-group has-feedback">
<div class="input-group mb-3">
<input
v-model="password"
type="password"
@ -10,9 +10,13 @@
minlength="8"
maxlength="32"
>
<span class="glyphicon glyphicon-lock form-control-feedback" />
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-lock" />
</div>
</div>
</div>
<div class="form-group has-feedback">
<div class="input-group mb-3">
<input
ref="confirm"
v-model="confirm"
@ -23,28 +27,32 @@
minlength="8"
maxlength="32"
>
<span class="glyphicon glyphicon-log-in form-control-feedback" />
</div>
<div class="callout callout-info" :class="{ hide: !infoMsg }">{{ infoMsg }}</div>
<div class="callout callout-warning" :class="{ hide: !warningMsg }">{{ warningMsg }}</div>
<div class="row">
<div class="col-xs-7" />
<div class="col-xs-5">
<el-button
type="primary"
native-type="submit"
:disabled="pending"
class="auth-btn"
>
<template v-if="pending">
<i class="fa fa-spinner fa-spin" /> {{ $t('auth.resetting') }}
</template>
<span v-else>{{ $t('auth.reset-button') }}</span>
</el-button>
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-sign-in-alt" />
</div>
</div>
</div>
<div class="alert alert-info" :class="{ 'd-none': !infoMsg }">
<i class="icon fas fa-info" />
{{ infoMsg }}
</div>
<div class="alert alert-warning" :class="{ 'd-none': !warningMsg }">
<i class="icon fas fa-exclamation-triangle" />
{{ warningMsg }}
</div>
<button
class="btn btn-primary float-right"
type="submit"
:disabled="pending"
>
<template v-if="pending">
<i class="fa fa-spinner fa-spin" /> {{ $t('auth.resetting') }}
</template>
<span v-else>{{ $t('auth.reset-button') }}</span>
</button>
</form>
</template>

View File

@ -2,71 +2,122 @@
<div class="content-wrapper">
<div class="container">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>{{ $t('general.skinlib') }}</h1>
<ol class="breadcrumb">
<li><i class="fas fa-tags" /> {{ $t('skinlib.nowShowing') }}</li>
<li>
<span v-if="filter === 'cape'" v-t="'general.cape'" />
<span v-else>
{{ $t('general.skin') }}
{{ $t('skinlib.filter.' + filter) }}
</span>
</li>
<li>{{ uploaderIndicator }}</li>
<li class="active">{{ sortIndicator }}</li>
</ol>
</section>
<div class="content-header">
<div class="container-fluid d-flex justify-content-between flex-wrap">
<h1>{{ $t('general.skinlib') }}</h1>
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item">
<i class="fas fa-tags" /> {{ $t('skinlib.nowShowing') }}
</li>
<li class="breadcrumb-item">
<span v-if="filter === 'cape'" v-t="'general.cape'" />
<span v-else>
{{ $t('general.skin') }}
{{ $t('skinlib.filter.' + filter) }}
</span>
</li>
<li class="breadcrumb-item">{{ uploaderIndicator }}</li>
<li class="breadcrumb-item active">{{ sortIndicator }}</li>
</ol>
</div>
</div>
<!-- Main content -->
<section class="content">
<div class="box box-default">
<div class="box-header">
<div class="form-group row">
<form class="col-md-6" @submit.prevent="submitSearch">
<el-input
v-model="keyword"
:placeholder="$t('vendor.datatable.search')"
clearable
>
<template #prepend>
<el-select v-model="filter" class="texture-type-select">
<el-option :label="$t('general.skin')" value="skin" />
<el-option label="Steve" value="steve" />
<el-option label="Alex" value="alex" />
<el-option :label="$t('general.cape')" value="cape" />
</el-select>
</template>
<template #append>
<el-button data-test="btn-search" @click="submitSearch">
<div class="card">
<div class="card-body">
<div class="form-group pt-0 mb-3 d-flex justify-content-between">
<form @submit.prevent="submitSearch">
<div class="input-group">
<div class="input-group-prepend">
<button
class="btn btn-default dropdown-toggle"
type="button"
data-toggle="dropdown"
>
{{ filterText }}
</button>
<div class="dropdown-menu">
<button
class="dropdown-item"
:class="{ active: filter === 'skin' }"
@click="filter = 'skin'"
>
{{ $t('general.skin') }}
</button>
<button
class="dropdown-item"
:class="{ active: filter === 'steve' }"
@click="filter = 'steve'"
>
Steve
</button>
<button
class="dropdown-item"
:class="{ active: filter === 'alex' }"
@click="filter = 'alex'"
>
Alex
</button>
<button
class="dropdown-item"
:class="{ active: filter === 'cape' }"
@click="filter = 'cape'"
>
{{ $t('general.cape') }}
</button>
</div>
</div>
<input
v-model="keyword"
class="form-control"
type="text"
data-test="keyword"
:placeholder="$t('vendor.datatable.search')"
>
<div class="input-group-append">
<button
class="btn btn-primary pl-3 pr-3"
data-test="btn-search"
@click="submitSearch"
>
{{ $t('general.submit') }}
</el-button>
</template>
</el-input>
</button>
</div>
</div>
</form>
<div class="col-md-6 advanced-filter">
<el-button-group class="pull-right">
<el-button plain @click="sort = 'likes'">
<div class="d-none d-sm-block">
<div class="btn-group">
<button
class="btn bg-olive"
:class="{ active: sort === 'likes' }"
@click="sort = 'likes'"
>
{{ $t('skinlib.sort.likes') }}
</el-button>
<el-button plain @click="sort = 'time'">
</button>
<button
class="btn bg-olive"
:class="{ active: sort === 'time' }"
@click="sort = 'time'"
>
{{ $t('skinlib.sort.time') }}
</el-button>
<el-button plain @click="uploader = currentUid">
</button>
<button
class="btn bg-olive"
:class="{ active: uploader === currentUid }"
@click="uploader = currentUid"
>
{{ $t('skinlib.seeMyUpload') }}
</el-button>
<el-button plain @click="reset">
</button>
<button class="btn bg-olive" @click="reset">
{{ $t('skinlib.reset') }}
</el-button>
</el-button-group>
</button>
</div>
</div>
</div>
</div>
<!-- Container of Skin Library -->
<div class="box-body">
<template v-if="items.length">
<div v-if="items.length" class="d-flex flex-wrap">
<skin-lib-item
v-for="(item, index) in items"
:key="item.tid"
@ -79,8 +130,8 @@
:anonymous="anonymous"
@like-toggled="onLikeToggled(index, $event)"
/>
</template>
<p v-else style="text-align: center; margin: 30px 0;">
</div>
<p v-else class="text-center m-5">
{{ $t('general.noResult') }}
</p>
</div>
@ -89,8 +140,14 @@
<paginate
v-model="page"
:page-count="totalPages"
class="pull-right"
class="float-right mr-3"
container-class="pagination pagination-sm no-margin"
page-class="page-item"
page-link-class="page-link"
prev-class="page-item"
prev-link-class="page-link"
next-class="page-item"
next-link-class="page-link"
first-button-text="«"
prev-text=""
next-text=""
@ -106,26 +163,18 @@
{{ $t('general.loading') }}
</span>
</div>
</div><!-- /.box -->
</section><!-- /.content -->
</div><!-- /.container -->
</div><!-- /.content-wrapper -->
</div>
</section>
</div>
</div>
</template>
<script>
import Vue from 'vue'
import Paginate from 'vuejs-paginate'
import {
ButtonGroup, Select, Option,
} from 'element-ui'
import { queryString, queryStringify } from '../../scripts/utils'
import SkinLibItem from '../../components/SkinLibItem.vue'
import emitMounted from '../../components/mixins/emitMounted'
Vue.use(ButtonGroup)
Vue.use(Select)
Vue.use(Option)
export default {
name: 'SkinLibrary',
components: {
@ -157,6 +206,16 @@ export default {
? this.$t('skinlib.filter.uploader', { uid: this.uploader })
: this.$t('skinlib.filter.allUsers')
},
filterText() {
switch (this.filter) {
case 'steve':
return 'Steve'
case 'alex':
return 'Alex'
default:
return this.$t(`general.${this.filter}`)
}
},
sortIndicator() {
return this.$t(`skinlib.sort.${this.sort}`)
},
@ -243,14 +302,4 @@ export default {
margin-top 25px
color #000
font-size 20px
.texture-type-select
width 90px
.advanced-filter
@media (max-width 850px)
display none
.btn-tail
margin-left 6px
</style>

View File

@ -8,82 +8,84 @@
:init-position-z="60"
>
<template #footer>
<el-button v-if="anonymous" disabled :title="$t('skinlib.show.anonymous')">
{{ $t('skinlib.addToCloset') }}
</el-button>
<template v-else>
<el-button
v-if="liked"
type="success"
size="medium"
data-toggle="modal"
data-target="#modal-use-as"
@click="fetchPlayersList"
>
{{ $t('skinlib.apply') }}
</el-button>
<el-button
v-if="liked"
type="primary"
size="medium"
data-test="removeFromCloset"
@click="removeFromCloset"
>
{{ $t('skinlib.removeFromCloset') }}
</el-button>
<el-button
v-else
type="primary"
size="medium"
data-test="addToCloset"
@click="addToCloset"
>
{{ $t('skinlib.addToCloset') }}
</el-button>
<el-button
v-if="type !== 'cape'"
size="medium"
data-test="setAsAvatar"
@click="setAsAvatar"
>
{{ $t('user.setAsAvatar') }}
</el-button>
<el-button
v-if="canBeDownloaded"
size="medium"
data-test="download"
@click="download"
>
{{ $t('skinlib.show.download') }}
</el-button>
<el-button
type="warning"
size="medium"
data-test="report"
@click="report"
>
{{ $t('skinlib.report.title') }}
</el-button>
</template>
<div
class="btn likes pull-right"
style="cursor: auto;"
:style="{ color: liked ? '#e0353b' : '#333' }"
:title="$t('skinlib.show.likes')"
<button
v-if="anonymous"
class="btn btn-outline-secondary"
disabled
:title="$t('skinlib.show.anonymous')"
>
<i class="fas fa-heart" />
<span>{{ likes }}</span>
{{ $t('skinlib.addToCloset') }}
</button>
<div v-else class="d-flex justify-content-between">
<div>
<button
v-if="liked"
class="btn btn-outline-success mr-2"
data-toggle="modal"
data-target="#modal-use-as"
@click="fetchPlayersList"
>
{{ $t('skinlib.apply') }}
</button>
<button
v-if="liked"
class="btn btn-outline-primary mr-2"
data-test="removeFromCloset"
@click="removeFromCloset"
>
{{ $t('skinlib.removeFromCloset') }}
</button>
<button
v-else
class="btn btn-outline-primary mr-2"
data-test="addToCloset"
@click="addToCloset"
>
{{ $t('skinlib.addToCloset') }}
</button>
<button
v-if="type !== 'cape'"
class="btn btn-outline-info mr-2"
data-test="setAsAvatar"
@click="setAsAvatar"
>
{{ $t('user.setAsAvatar') }}
</button>
<button
v-if="canBeDownloaded"
class="btn btn-outline-info mr-2"
data-test="download"
@click="download"
>
{{ $t('skinlib.show.download') }}
</button>
<button
class="btn btn-outline-info mr-2"
data-test="report"
@click="report"
>
{{ $t('skinlib.report.title') }}
</button>
</div>
<div
class="pt-2 likes"
:class="[liked ? 'text-red' : 'text-gray']"
:title="$t('skinlib.show.likes')"
>
<i class="fas fa-heart" />
<span>{{ likes }}</span>
</div>
</div>
</template>
</previewer>
</div>
<div class="col-md-4">
<div class="box box-primary">
<div class="box-header with-border">
<h3 v-t="'skinlib.show.detail'" class="box-title" />
<div class="card card-primary">
<div class="card-header">
<h3 v-t="'skinlib.show.detail'" class="card-title" />
</div>
<div class="box-body">
<div class="card-body">
<table class="table">
<tbody>
<tr>
@ -98,8 +100,8 @@
<tr>
<td v-t="'skinlib.show.model'" />
<td>
<template v-if="type === 'cape'">{{ $t('general.cape') }}</template>
<template v-else>{{ type }}</template>
<span v-if="type === 'cape'">{{ $t('general.cape') }}</span>
<span v-else>{{ type }}</span>
<small v-if="hasEditPermission">
<a v-t="'skinlib.show.edit'" href="#" @click="changeModel" />
</small>
@ -117,16 +119,12 @@
</tr>
<tr>
<td v-t="'skinlib.show.uploader'" />
<template v-if="uploaderNickName !== null">
<td>
<a
:href="`${baseUrl}/skinlib?filter=${type === 'cape' ? 'cape' : 'skin'}&uploader=${uploader}`"
>{{ uploaderNickName }}</a>
</td>
</template>
<template v-else>
<td><span v-t="'general.unexistent-user'" /></td>
</template>
<td v-if="uploaderNickName !== null">
<a
:href="`${baseUrl}/skinlib?filter=${type === 'cape' ? 'cape' : 'skin'}&uploader=${uploader}`"
>{{ uploaderNickName }}</a>
</td>
<td v-else><span v-t="'general.unexistent-user'" /></td>
</tr>
<tr>
<td v-t="'skinlib.show.upload-at'" />
@ -134,23 +132,27 @@
</tr>
</tbody>
</table>
</div><!-- /.box-body -->
</div><!-- /.box -->
</div>
</div>
<div v-if="hasEditPermission" class="box box-warning">
<div class="box-header with-border">
<h3 v-t="'admin.operationsTitle'" class="box-title" />
</div><!-- /.box-header -->
<div class="box-body">
<div v-if="hasEditPermission" class="card card-warning">
<div class="card-header">
<h3 v-t="'admin.operationsTitle'" class="card-title" />
</div>
<div class="card-body">
<p v-t="'skinlib.show.manage-notice'" />
</div><!-- /.box-body -->
</div>
<div class="box-footer">
<el-button type="warning" @click="togglePrivacy">{{ $t(togglePrivacyText) }}</el-button>
<el-button type="danger" class="pull-right" @click="deleteTexture">
{{ $t('skinlib.show.delete-texture') }}
</el-button>
</div><!-- /.box-footer -->
<div class="card-footer">
<div class="container d-flex justify-content-between">
<button class="btn btn-warning" @click="togglePrivacy">
{{ $t(togglePrivacyText) }}
</button>
<button class="btn btn-danger" @click="deleteTexture">
{{ $t('skinlib.show.delete-texture') }}
</button>
</div>
</div>
</div>
</div>

View File

@ -1,12 +1,17 @@
<template>
<section class="content">
<div class="container-fluid">
<div class="row">
<div class="col-md-6">
<div class="box box-primary">
<div class="box-body">
<div class="card card-primary">
<div class="card-body">
<div class="form-group">
<label v-t="'skinlib.upload.texture-name'" for="name" />
<el-input v-model="name" :placeholder="textureNameRule" clearable />
<input
v-model="name"
type="text"
:placeholder="textureNameRule"
class="form-control"
>
</div>
<div class="form-group">
@ -31,50 +36,40 @@
drop=".file-dnd"
@input-file="inputFile"
>
<el-button type="primary" size="medium">
<button class="btn btn-primary">
{{ $t('skinlib.upload.select-file') }}
</el-button>
</button>
</file-upload>
<el-button
<button
v-show="hasFile"
size="medium"
class="pull-right"
class="btn btn-danger float-right"
data-test="remove"
@click="remove"
>
<i class="fas fa-trash-alt" />
{{ $t('skinlib.upload.remove') }}
</el-button>
</button>
</div>
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-if="contentPolicy" class="callout callout-warning" v-html="contentPolicy" />
</div>
<div class="box-footer">
<el-switch
v-model="isPrivate"
:active-text="$t('skinlib.upload.set-as-private')"
class="pull-right"
:title="$t('skinlib.upload.privacy-notice')"
/>
<el-button
v-if="uploading"
type="success"
size="medium"
disabled
>
<i class="fa fa-spinner fa-spin" /> {{ $t('skinlib.uploading') }}
</el-button>
<el-button
v-else
type="success"
size="medium"
@click="upload"
>
{{ $t('skinlib.upload.button') }}
</el-button>
&nbsp;
<div class="card-footer">
<div class="container pl-0 pr-0 d-flex justify-content-between">
<el-switch
v-model="isPrivate"
class="mt-2"
:active-text="$t('skinlib.upload.set-as-private')"
:title="$t('skinlib.upload.privacy-notice')"
/>
<button v-if="uploading" class="btn btn-success" disabled>
<i class="fa fa-spinner fa-spin" /> {{ $t('skinlib.uploading') }}
</button>
<button v-else class="btn btn-success" @click="upload">
{{ $t('skinlib.upload.button') }}
</button>
</div>
<div v-if="hasFile" class="callout callout-info bottom-notice">
<p>{{ $t('skinlib.upload.cost', { score: scoreCost }) }}</p>
</div>
@ -85,7 +80,7 @@
<p>{{ $t('skinlib.upload.award', { score: award }) }}</p>
</div>
</div>
</div><!-- /.box -->
</div>
</div>
<div class="col-md-6">
<previewer
@ -95,7 +90,7 @@
/>
</div>
</div>
</section>
</div>
</template>
<script>

View File

@ -2,8 +2,8 @@
<form @submit.prevent="submit">
<div v-if="players.length">
<p v-t="'user.bindExistedPlayer'" />
<div class="form-group">
<select v-model="selected" class="player-select">
<div class="form-group mb-3">
<select v-model="selected" class="form-control player-select">
<option v-for="name in players" :key="name">{{ name }}</option>
</select>
</div>
@ -11,25 +11,23 @@
<div v-else>
<p v-t="'user.bindNewPlayer'" />
<div class="form-group has-feedback">
<div class="form-group mb-3">
<input
v-model="selected"
class="form-control"
:placeholder="$t('general.player.player-name')"
>
<span class="glyphicon glyphicon-user form-control-feedback" />
</div>
</div>
<div v-show="message" class="callout callout-warning" v-text="message" />
<div v-show="message" class="alert alert-warning" v-text="message" />
<el-button type="primary" native-type="submit" :disabled="pending">
<button class="btn btn-primary float-right" type="submit" :disabled="pending">
<template v-if="pending">
<i class="fa fa-spinner fa-spin" /> {{ $t('general.wait') }}
</template>
<span v-else>{{ $t('general.submit') }}</span>
</el-button>
</button>
</form>
</template>

View File

@ -1,67 +1,66 @@
<template>
<section class="content">
<div class="container-fluid">
<email-verification />
<div class="row">
<!-- Left col -->
<div class="col-md-8">
<!-- Custom tabs -->
<div class="nav-tabs-custom">
<!-- Tabs within a box -->
<ul class="nav nav-tabs">
<li :class="{ active: category === 'skin' }">
<a
v-t="'general.skin'"
href="#"
class="category-switch"
data-toggle="tab"
@click="switchCategory"
/>
</li>
<li :class="{ active: category === 'cape' }">
<a
v-t="'general.cape'"
href="#"
class="category-switch"
data-toggle="tab"
@click="switchCategory"
/>
</li>
<li>
<a
v-t="'user.closet.upload'"
:href="`${baseUrl}/skinlib/upload`"
class="category-switch"
/>
</li>
<li class="pull-right" style="padding: 7px;">
<div class="has-feedback pull-right">
<div class="user-search-form">
<input
v-model="query"
type="text"
class="form-control input-sm"
:placeholder="$t('user.typeToSearch')"
@input="search"
<div class="card card-primary card-tabs">
<div class="card-header p-0 pt-1 pl-1">
<div class="d-flex justify-content-between">
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item">
<a
class="nav-link"
:class="{ active: category === 'skin' }"
href="#"
data-toggle="pill"
role="tab"
@click="switchCategory"
>
<span class="glyphicon glyphicon-search form-control-feedback" />
</div>
{{ $t('general.skin') }}
</a>
</li>
<li class="nav-item">
<a
class="nav-link"
:class="{ active: category === 'cape' }"
href="#"
@click="switchCategory"
>
{{ $t('general.cape') }}
</a>
</li>
<li class="nav-item d-none d-md-block">
<a
v-t="'user.closet.upload'"
:href="`${baseUrl}/skinlib/upload`"
class="nav-link"
/>
</li>
</ul>
<div class="mr-3 my-2 my-lg-0">
<input
v-model="query"
class="form-control mr-sm-2"
type="search"
aria-label="Search"
:placeholder="$t('user.typeToSearch')"
@input="search"
>
</div>
</li>
</ul>
<div class="tab-content no-padding">
</div>
</div>
<div class="card-body">
<div
v-if="category === 'skin'"
id="skin-category"
class="tab-pane box-body"
:class="{ active: category === 'skin' }"
>
<div v-if="skinItems.length === 0" class="empty-msg">
<div v-if="skinItems.length === 0" class="text-center p-3">
<div v-if="query !== ''" v-t="'general.noResult'" />
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-else v-html="$t('user.emptyClosetMsg', { url: linkToSkin })" />
</div>
<div v-else>
<div v-else class="d-flex flex-wrap">
<closet-item
v-for="(item, index) in skinItems"
:key="item.tid"
@ -77,10 +76,9 @@
<div
v-else
id="cape-category"
class="tab-pane box-body"
:class="{ active: category === 'cape' }"
>
<div v-if="capeItems.length === 0" class="empty-msg">
<div v-if="capeItems.length === 0" class="text-center p-3">
<div v-if="query !== ''" v-t="'general.noResult'" />
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-else v-html="$t('user.emptyClosetMsg', { url: linkToCape })" />
@ -99,13 +97,19 @@
</div>
</div>
</div>
<div class="box-footer">
<div class="card-footer">
<paginate
v-if="category === 'skin'"
v-model="skinCurrentPage"
:page-count="skinTotalPages"
class="pull-right"
class="float-right"
container-class="pagination pagination-sm no-margin"
page-class="page-item"
page-link-class="page-link"
prev-class="page-item"
prev-link-class="page-link"
next-class="page-item"
next-link-class="page-link"
first-button-text="«"
prev-text=""
next-text=""
@ -117,8 +121,14 @@
v-else
v-model="capeCurrentPages"
:page-count="capeTotalPages"
class="pull-right"
class="float-right"
container-class="pagination pagination-sm no-margin"
page-class="page-item"
page-link-class="page-link"
prev-class="page-item"
prev-link-class="page-link"
next-class="page-item"
next-link-class="page-link"
first-button-text="«"
prev-text=""
next-text=""
@ -127,10 +137,9 @@
:first-last-button="true"
/>
</div>
</div><!-- /.nav-tabs-custom -->
</div>
</div>
<!-- Right col -->
<div class="col-md-4">
<previewer
closet-mode
@ -139,24 +148,26 @@
:model="model"
>
<template #footer>
<el-button
type="primary"
data-toggle="modal"
data-target="#modal-use-as"
@click="fetchPlayersList"
>
{{ $t('user.useAs') }}
</el-button>
<el-button data-test="resetSelected" class="pull-right" @click="resetSelected">
{{ $t('user.resetSelected') }}
</el-button>
<div class="d-flex justify-content-between">
<button
class="btn btn-primary"
data-toggle="modal"
data-target="#modal-use-as"
@click="fetchPlayersList"
>
{{ $t('user.useAs') }}
</button>
<button class="btn btn-default" data-test="resetSelected" @click="resetSelected">
{{ $t('user.resetSelected') }}
</button>
</div>
</template>
</previewer>
</div>
</div>
<apply-to-player-dialog ref="useAs" :skin="selectedSkin" :cape="selectedCape" />
<add-player-dialog @add="fetchPlayersList" />
</section><!-- /.content -->
</div>
</template>
<script>
@ -274,38 +285,3 @@ export default {
},
}
</script>
<style lang="stylus">
.empty-msg
text-align center
font-size 16px
padding 10px 0
.texture-name
width 65%
display inline-block
overflow hidden
text-overflow ellipsis
white-space nowrap
small
font-size 75%
.item-footer > .dropdown-menu
margin-left 180px
.box-title
a
color #6d6d6d
a.selected
color #3c8dbc
.breadcrumb
a
margin-right 10px
color #444
a:hover
color #3c8dbc
</style>

View File

@ -1,60 +1,47 @@
<template>
<div>
<email-verification />
<div class="box">
<div class="box-header with-border">
<h3 v-t="'user.used.title'" class="box-title" />
</div><!-- /.box-header -->
<div class="box-body">
<div class="card card-primary card-outline">
<div class="card-header">
<h3 v-t="'user.used.title'" class="card-title" />
</div>
<div class="card-body">
<div class="row">
<div class="col-md-1" />
<div class="col-md-6">
<table class="usage-table" border="0">
<tbody>
<tr>
<td class="text-center">
<b v-t="'user.used.players'" />
</td>
<td class="circle-gap" />
<td class="text-center">
<b v-t="'user.used.storage'" />
</td>
</tr>
<tr class="line-gap" />
<tr>
<td>
<el-progress
type="circle"
:percentage="~~playersPercentage"
color="#00429B"
/>
</td>
<td class="circle-gap" />
<td>
<el-progress
type="circle"
:percentage="~~storagePercentage"
color="#008C95"
/>
</td>
</tr>
<tr class="line-gap" />
<tr>
<td class="text-center">
<b>{{ playersUsed }}</b> / {{ playersTotal }}
</td>
<td class="circle-gap" />
<td class="text-center">
<template v-if="storageUsed > 1024">
<b>{{ ~~(storageUsed / 1024) }}</b> / {{ ~~(storageTotal / 1024) }} MB
</template>
<template v-else>
<b>{{ storageUsed }}</b> / {{ storageTotal }} KB
</template>
</td>
</tr>
</tbody>
</table>
<div class="info-box bg-teal">
<span class="info-box-icon">
<i class="fas fa-gamepad" />
</span>
<div class="info-box-content">
<span class="info-box-text">{{ $t('user.used.players') }}</span>
<span class="info-box-number">
<b>{{ playersUsed }}</b> / {{ playersTotal }}
</span>
<div class="progress">
<div class="progress-bar" :style="{ width: playersPercentage + '%' }" />
</div>
</div>
</div>
<div class="info-box bg-maroon">
<span class="info-box-icon">
<i class="fas fa-hdd" />
</span>
<div class="info-box-content">
<span class="info-box-text">{{ $t('user.used.storage') }}</span>
<span class="info-box-number">
<template v-if="storageUsed > 1024">
<b>{{ ~~(storageUsed / 1024) }}</b> / {{ ~~(storageTotal / 1024) }} MB
</template>
<template v-else>
<b>{{ storageUsed }}</b> / {{ storageTotal }} KB
</template>
</span>
<div class="progress">
<div class="progress-bar" :style="{ width: storagePercentage + '%' }" />
</div>
</div>
</div>
</div>
<div class="col-md-4">
<p class="text-center score-title">
@ -64,45 +51,37 @@
{{ animatedScore }}
</p>
<p v-t="'user.score-notice'" class="text-center score-notice" />
</div><!-- /.col -->
</div><!-- /.row -->
</div><!-- ./box-body -->
<div class="box-footer">
<el-button
</div>
</div>
</div>
<div class="card-footer">
<button
v-if="canSign"
class="btn btn-primary pull-left"
type="primary"
round
class="btn bg-gradient-primary pl-5 pr-5"
:disabled="signing"
@click="sign"
>
<i class="far fa-calendar-check" aria-hidden="true" /> &nbsp;{{ $t('user.sign') }}
</el-button>
<el-button
</button>
<button
v-else
class="btn btn-primary pull-left"
type="primary"
round
class="btn bg-gradient-primary pl-4 pr-4"
:title="$t('user.last-sign', { time: lastSignAt.toLocaleString() })"
disabled
>
<i class="far fa-calendar-check" aria-hidden="true" /> &nbsp;
{{ remainingTimeText }}
</el-button>
</div><!-- /.box-footer -->
</button>
</div>
</div>
</div>
</template>
<script>
import Vue from 'vue'
import { Progress } from 'element-ui'
import Tween from '@tweenjs/tween.js'
import EmailVerification from '../../components/EmailVerification.vue'
import emitMounted from '../../components/mixins/emitMounted'
Vue.use(Progress)
const ONE_DAY = 24 * 3600 * 1000
export default {
@ -213,15 +192,6 @@ export default {
</script>
<style lang="stylus">
.usage-table
margin 0 auto
.circle-gap
width 14%
.line-gap
height 12px
.score-title
margin-top 5px

View File

@ -1,13 +1,13 @@
<template>
<section class="content">
<el-button
<div class="container-fluid">
<button
type="primary"
class="btn-create-app"
class="btn-create-app btn btn-primary"
data-toggle="modal"
data-target="#modal-create"
>
{{ $t('user.oauth.create') }}
</el-button>
</button>
<vue-good-table
:rows="clients"
:columns="columns"
@ -39,9 +39,9 @@
</a>
</span>
<span v-else-if="props.column.field === 'operations'">
<el-button type="danger" data-test="remove" @click="remove(props.row)">
<button class="btn btn-danger" data-test="remove" @click="remove(props.row)">
{{ $t('report.delete') }}
</el-button>
</button>
</span>
<span v-else>
{{ props.formattedRow[props.column.field] }}
@ -58,6 +58,7 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 v-t="'user.oauth.create'" class="modal-title" />
<button
type="button"
class="close"
@ -66,7 +67,6 @@
>
<span aria-hidden="true">&times;</span>
</button>
<h4 v-t="'user.oauth.create'" class="modal-title" />
</div>
<div class="modal-body">
<table class="table">
@ -74,28 +74,30 @@
<tr>
<td v-t="'user.oauth.name'" class="key" />
<td class="value">
<el-input v-model="name" type="text" />
<input v-model="name" class="form-control" type="text">
</td>
</tr>
<tr>
<td v-t="'user.oauth.redirect'" class="key" />
<td class="value">
<el-input v-model="callback" type="text" />
<input v-model="callback" class="form-control" type="text">
</td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
<el-button data-dismiss="modal">{{ $t('general.close') }}</el-button>
<el-button type="primary" data-test="create" @click="create">
<div class="modal-footer d-flex justify-content-between">
<button class="btn btn-default" data-dismiss="modal">
{{ $t('general.close') }}
</button>
<button class="btn btn-primary" data-test="create" @click="create">
{{ $t('general.submit') }}
</el-button>
</button>
</div>
</div>
</div>
</div>
</section>
</div>
</template>
<script>

View File

@ -1,9 +1,9 @@
<template>
<section class="content">
<div class="container-fluid">
<div class="row">
<div class="col-md-6">
<div class="box box-primary">
<div class="box-body table-responsive no-padding">
<div class="card card-primary">
<div class="card-body table-responsive p-0">
<table class="table table-hover">
<thead>
<tr>
@ -24,44 +24,39 @@
<td class="pid">{{ player.pid }}</td>
<td class="player-name">{{ player.name }}</td>
<td>
<el-button size="medium" @click="changeName(player)">
<button class="btn btn-default" @click="changeName(player)">
{{ $t('user.player.edit-pname') }}
</el-button>
<el-button
size="medium"
type="warning"
</button>
<button
class="btn btn-warning"
data-toggle="modal"
data-target="#modal-clear-texture"
>
{{ $t('user.player.delete-texture') }}
</el-button>
<el-button
size="medium"
type="danger"
@click="deletePlayer(player, index)"
>
</button>
<button class="btn btn-danger" @click="deletePlayer(player, index)">
{{ $t('user.player.delete-player') }}
</el-button>
</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="box-footer clearfix">
<el-button type="primary" data-toggle="modal" data-target="#modal-add-player">
<i class="fas fa-plus" aria-hidden="true" /> &nbsp;{{ $t('user.player.add-player') }}
</el-button>
<div class="card-footer">
<button class="btn btn-primary" data-toggle="modal" data-target="#modal-add-player">
<i class="fas fa-plus" aria-hidden="true" />&nbsp;{{ $t('user.player.add-player') }}
</button>
</div>
</div>
<div v-once class="box box-default">
<div class="box-header with-border">
<h3 v-t="'general.tip'" class="box-title" />
</div><!-- /.box-header -->
<div class="box-body">
<div v-once class="card">
<div class="card-header">
<h3 v-t="'general.tip'" class="card-title" />
</div>
<div class="card-body">
<p v-t="'user.player.login-notice'" />
</div><!-- /.box-body -->
</div><!-- /.box -->
</div>
</div>
</div>
<div class="col-md-6">
@ -73,17 +68,17 @@
title="user.player.player-info"
>
<template #footer>
<el-button data-test="to2d" @click="togglePreviewer">
<button class="btn btn-default" data-test="to2d" @click="togglePreviewer">
{{ $t('user.switch2dPreview') }}
</el-button>
</button>
</template>
</previewer>
<div v-else class="box">
<div class="box-header with-border">
<div v-else class="card">
<div class="card-header card-outline">
<!-- eslint-disable-next-line vue/no-v-html -->
<h3 class="box-title" v-html="$t('user.player.player-info')" />
<h3 class="card-title" v-html="$t('user.player.player-info')" />
</div>
<div class="box-body">
<div class="card-body">
<div id="preview-2d">
<p>
{{ $t('general.skin') }}
@ -107,13 +102,13 @@
<span v-else v-t="'user.player.texture-empty'" class="skin2d" />
</p>
</div>
</div><!-- /.box-body -->
<div class="box-footer">
<el-button @click="togglePreviewer">
{{ $t('user.switch3dPreview') }}
</el-button>
</div>
</div><!-- /.box -->
<div class="card-footer">
<button class="btn btn-default" @click="togglePreviewer">
{{ $t('user.switch3dPreview') }}
</button>
</div>
</div>
</div>
</div>
@ -128,6 +123,7 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 v-t="'user.chooseClearTexture'" class="modal-title" />
<button
type="button"
class="close"
@ -136,7 +132,6 @@
>
<span aria-hidden="true">&times;</span>
</button>
<h4 v-t="'user.chooseClearTexture'" class="modal-title" />
</div>
<div class="modal-body">
<label class="form-group">
@ -147,16 +142,18 @@
<input v-model="clear.cape" type="checkbox"> {{ $t('general.cape') }}
</label>
</div>
<div class="modal-footer">
<el-button data-dismiss="modal">{{ $t('general.close') }}</el-button>
<el-button type="primary" data-test="clearTexture" @click="clearTexture">
<div class="modal-footer d-flex justify-content-between">
<button class="btn btn-default" data-dismiss="modal">
{{ $t('general.close') }}
</button>
<button class="btn btn-primary" data-test="clearTexture" @click="clearTexture">
{{ $t('general.submit') }}
</el-button>
</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div>
</div>
</div>
</section>
</div>
</template>
<script>
@ -317,7 +314,4 @@ export default {
#preview-2d > p
height 64px
line-height 64px
.form-group
cursor pointer
</style>

View File

@ -1,26 +1,30 @@
<template>
<section class="content">
<div class="container-fluid">
<email-verification />
<div class="row">
<div class="col-md-6">
<div v-once class="box box-primary">
<div class="box-header with-border">
<h3 v-t="'user.profile.avatar.title'" class="box-title" />
</div><!-- /.box-header -->
<div v-once class="card card-primary">
<div class="card-header">
<h3 v-t="'user.profile.avatar.title'" class="card-title" />
</div>
<!-- eslint-disable-next-line vue/no-v-html -->
<div class="box-body" v-html="$t('user.profile.avatar.notice')" /><!-- /.box-body -->
<div class="box-footer">
<el-button type="primary" data-test="resetAvatar" @click="resetAvatar">
<div class="card-body" v-html="$t('user.profile.avatar.notice')" />
<div class="card-footer">
<button class="btn btn-primary" data-test="resetAvatar" @click="resetAvatar">
{{ $t('user.resetAvatar') }}
</el-button>
</button>
</div>
</div>
<form class="box box-warning" data-test="changePassword" @submit.prevent="changePassword">
<div class="box-header with-border">
<h3 v-t="'user.profile.password.title'" class="box-title" />
</div><!-- /.box-header -->
<div class="box-body">
<form
class="card card-warning"
data-test="changePassword"
@submit.prevent="changePassword"
>
<div class="card-header">
<h3 v-t="'user.profile.password.title'" class="card-title" />
</div>
<div class="card-body">
<div class="form-group">
<label v-t="'user.profile.password.old'" />
<input
@ -55,21 +59,25 @@
maxlength="32"
>
</div>
</div><!-- /.box-body -->
<div class="box-footer">
<el-button type="primary" native-type="submit">
{{ $t('user.profile.password.button') }}
</el-button>
</div>
</form><!-- /.box -->
<div class="card-footer">
<button class="btn btn-primary" type="submit">
{{ $t('user.profile.password.button') }}
</button>
</div>
</form>
</div>
<div class="col-md-6">
<form class="box box-primary" data-test="changeNickName" @submit.prevent="changeNickName">
<div class="box-header with-border">
<h3 v-t="'user.profile.nickname.title'" class="box-title" />
</div><!-- /.box-header -->
<div class="box-body">
<div class="form-group has-feedback">
<form
class="card card-primary"
data-test="changeNickName"
@submit.prevent="changeNickName"
>
<div class="card-header">
<h3 v-t="'user.profile.nickname.title'" class="card-title" />
</div>
<div class="card-body">
<div class="form-group">
<input
v-model="nickname"
type="text"
@ -77,22 +85,25 @@
:placeholder="$t('user.profile.nickname.rule')"
required
>
<span class="glyphicon glyphicon-user form-control-feedback" />
</div>
</div><!-- /.box-body -->
<div class="box-footer">
<el-button type="primary" native-type="submit">
</div>
<div class="card-footer">
<button class="btn btn-primary" type="submit">
{{ $t('general.submit') }}
</el-button>
</button>
</div>
</form>
<form class="box box-warning" data-test="changeEmail" @submit.prevent="changeEmail">
<div class="box-header with-border">
<h3 v-t="'user.profile.email.title'" class="box-title" />
</div><!-- /.box-header -->
<div class="box-body">
<div class="form-group has-feedback">
<form
class="card card-warning"
data-test="changeEmail"
@submit.prevent="changeEmail"
>
<div class="card-header">
<h3 v-t="'user.profile.email.title'" class="card-title" />
</div>
<div class="card-body">
<div class="form-group">
<input
ref="email"
v-model="email"
@ -101,9 +112,8 @@
:placeholder="$t('user.profile.email.new')"
required
>
<span class="glyphicon glyphicon-envelope form-control-feedback" />
</div>
<div class="form-group has-feedback">
<div class="form-group">
<input
ref="currentPassword"
v-model="currentPassword"
@ -112,47 +122,51 @@
:placeholder="$t('user.profile.email.password')"
required
>
<span class="glyphicon glyphicon-lock form-control-feedback" />
</div>
</div><!-- /.box-body -->
<div class="box-footer">
<el-button type="primary" native-type="submit">
</div>
<div class="card-footer">
<button class="btn btn-primary" type="submit">
{{ $t('user.profile.email.button') }}
</el-button>
</button>
</div>
</form>
<div class="box box-danger">
<div class="box-header with-border">
<h3 v-t="'user.profile.delete.title'" class="box-title" />
</div><!-- /.box-header -->
<div class="box-body">
<div class="card card-danger">
<div class="card-header">
<h3 v-t="'user.profile.delete.title'" class="card-title" />
</div>
<div class="card-body">
<template v-if="isAdmin">
<p v-t="'user.profile.delete.admin'" />
<el-button type="danger" disabled>
<button class="btn btn-danger" disabled>
{{ $t('user.profile.delete.button') }}
</el-button>
</button>
</template>
<template v-else>
<p v-t="{ path: 'user.profile.delete.notice', args: { site: siteName } }" />
<el-button type="danger" data-toggle="modal" data-target="#modal-delete-account">
<button
class="btn btn-danger"
data-toggle="modal"
data-target="#modal-delete-account"
>
{{ $t('user.profile.delete.button') }}
</el-button>
</button>
</template>
</div><!-- /.box-body -->
</div>
</div>
</div>
</div>
<div
id="modal-delete-account"
class="modal modal-danger fade"
class="modal fade"
tabindex="-1"
role="dialog"
>
<form class="modal-dialog" data-test="deleteAccount" @submit.prevent="deleteAccount">
<div class="modal-content">
<div class="modal-content bg-danger">
<div class="modal-header">
<h4 v-t="'user.profile.delete.modal-title'" class="modal-title" />
<button
type="button"
class="close"
@ -161,7 +175,6 @@
>
<span aria-hidden="true">&times;</span>
</button>
<h4 v-t="'user.profile.delete.modal-title'" class="modal-title" />
</div>
<div class="modal-body">
<!-- eslint-disable-next-line vue/no-v-html -->
@ -176,23 +189,23 @@
>
<br>
</div>
<div class="modal-footer">
<div class="modal-footer d-flex justify-content-between">
<button
v-t="'general.close'"
type="button"
class="btn btn-outline"
class="btn btn-outline-light"
data-dismiss="modal"
/>
<button
v-t="'general.submit'"
type="submit"
class="btn btn-outline"
class="btn btn-outline-light"
/>
</div>
</div><!-- /.modal-content -->
</form><!-- /.modal-dialog -->
</div><!-- /.modal -->
</section><!-- /.content -->
</div>
</form>
</div>
</div>
</template>
<script>

View File

@ -1,5 +1,5 @@
<template>
<section class="content">
<div class="container-fluid">
<vue-good-table
:rows="reports"
:columns="columns"
@ -22,7 +22,7 @@
</span>
</template>
</vue-good-table>
</section>
</div>
</template>
<script>

View File

@ -24,7 +24,6 @@ test('add player', async () => {
{ name: 'the-new' }
)
await flushPromises()
await flushPromises()
expect(wrapper.text()).not.toContain('the-new')
expect(Vue.prototype.$message.warning).toBeCalledWith('fail')

View File

@ -16,21 +16,26 @@ function factory(opt = {}) {
test('computed values', () => {
const wrapper = mount(ClosetItem, { propsData: factory() })
expect(wrapper.find('img').attributes('src')).toBe('/preview/1.png')
expect(wrapper.find('a.more').attributes('href')).toBe('/skinlib/show/1')
expect(
wrapper
.findAll('.dropdown-item')
.at(2)
.attributes('href')
).toBe('/skinlib/show/1')
})
test('selected item', () => {
const wrapper = mount(ClosetItem, { propsData: factory({ selected: true }) })
expect(wrapper.find('.item').classes('item-selected')).toBeTrue()
expect(wrapper.find('.card').classes('shadow')).toBeTrue()
})
test('click item body', () => {
const wrapper = mount(ClosetItem, { propsData: factory() })
wrapper.find('.item').trigger('click')
wrapper.find('.card').trigger('click')
expect(wrapper.emitted().select).toBeUndefined()
wrapper.find('.item-body > div').trigger('click')
wrapper.find('.card-body').trigger('click')
expect(wrapper.emitted().select).toBeTruthy()
})
@ -47,8 +52,7 @@ test('rename texture', async () => {
return Promise.resolve({ value: 'new-name' } as MessageBoxData)
})
const wrapper = mount(ClosetItem, { propsData: factory() })
const button = wrapper.findAll('.dropdown-menu > li').at(0)
.find('a')
const button = wrapper.findAll('.dropdown-item').at(0)
button.trigger('click')
await flushPromises()
@ -59,7 +63,7 @@ test('rename texture', async () => {
button.trigger('click')
await flushPromises()
expect(wrapper.find('.texture-name > span').text()).toBe('new-name (steve)')
expect(wrapper.find('[data-test="name"]').text()).toBe('new-name (steve)')
expect(Vue.prototype.$http.post).toBeCalledWith(
'/user/closet/rename/1',
{ name: 'new-name' }
@ -75,8 +79,7 @@ test('remove texture', async () => {
.mockResolvedValue('confirm')
const wrapper = mount(ClosetItem, { propsData: factory() })
const button = wrapper.findAll('.dropdown-menu > li').at(1)
.find('a')
const button = wrapper.findAll('.dropdown-item').at(1)
button.trigger('click')
await flushPromises()
@ -100,8 +103,7 @@ test('set as avatar', async () => {
.mockResolvedValue('confirm')
const wrapper = mount(ClosetItem, { propsData: factory() })
const button = wrapper.findAll('.dropdown-menu > li').at(2)
.find('a')
const button = wrapper.findAll('.dropdown-item').at(3)
document.body.innerHTML += '<img alt="User Image" src="a">'
button.trigger('click')
@ -120,6 +122,5 @@ test('set as avatar', async () => {
test('no avatar option if texture is cape', () => {
const wrapper = mount(ClosetItem, { propsData: factory({ type: 'cape' }) })
const button = wrapper.findAll('.dropdown-menu > li').at(2)
expect(button.isEmpty()).toBeTrue()
expect(wrapper.findAll('.dropdown-item')).toHaveLength(3)
})

View File

@ -28,7 +28,7 @@ test('anonymous user', () => {
const wrapper = mount(SkinLibItem, {
propsData: { anonymous: true },
})
const button = wrapper.find('.more')
const button = wrapper.find('.btn-like')
expect(button.attributes('title')).toBe('skinlib.anonymous')
button.trigger('click')
expect(Vue.prototype.$http.post).not.toBeCalled()
@ -48,7 +48,7 @@ test('liked state', () => {
const wrapper = mount(SkinLibItem, {
propsData: { liked: true, anonymous: false },
})
const button = wrapper.find('.like')
const button = wrapper.find('.btn-like')
expect(button.attributes('title')).toBe('skinlib.removeFromCloset')
expect(button.classes('liked')).toBeTrue()
@ -66,7 +66,7 @@ test('remove from closet', async () => {
tid: 1, liked: true, anonymous: false,
},
})
wrapper.find('.like').trigger('click')
wrapper.find('.btn-like').trigger('click')
await flushPromises()
expect(wrapper.emitted('like-toggled')[0]).toEqual([false])
})
@ -89,7 +89,7 @@ test('add to closet', async () => {
tid: 1, liked: false, anonymous: false,
},
})
const button = wrapper.find('.like')
const button = wrapper.find('.btn-like')
button.trigger('click')
expect(Vue.prototype.$http.post).not.toBeCalled()

View File

@ -16,17 +16,17 @@ test('check for BS updates', async () => {
json: () => Promise.resolve({ available: true }),
})
document.body.innerHTML = '<a href="/admin/update"></a>'
document.body.innerHTML = '<a href="/admin/update"><p></p></a>'
await checkForUpdates()
expect(window.fetch).toBeCalledWith('/admin/update/check', init)
expect(document.querySelector('a')!.innerHTML).toBe('')
expect(document.querySelector('p')!.innerHTML).toBe('')
await checkForUpdates()
expect(document.querySelector('a')!.innerHTML).toBe('')
expect(document.querySelector('p')!.innerHTML).toBe('')
await checkForUpdates()
expect(document.querySelector('a')!.innerHTML).toContain('1')
expect(document.querySelector('p')!.innerHTML).toContain('New')
})
test('check for plugins updates', async () => {
@ -41,17 +41,17 @@ test('check for plugins updates', async () => {
json: () => Promise.resolve({ available: true, plugins: [{}] }),
})
document.body.innerHTML = '<a href="/admin/plugins/market"></a>'
document.body.innerHTML = '<a href="/admin/plugins/market"><p></p></a>'
await checkForPluginUpdates()
expect(window.fetch).toBeCalledWith('/admin/plugins/market/check', init)
expect(document.querySelector('a')!.innerHTML).toBe('')
expect(document.querySelector('p')!.innerHTML).toBe('')
await checkForPluginUpdates()
expect(document.querySelector('a')!.innerHTML).toBe('')
expect(document.querySelector('p')!.innerHTML).toBe('')
await checkForPluginUpdates()
expect(document.querySelector('a')!.innerHTML).toContain('1')
expect(document.querySelector('p')!.innerHTML).toContain('1')
})
test('do not update anything if element not found', async () => {

View File

@ -6,20 +6,20 @@ window.blessing.extra = {
test('should be transparent at top', () => {
Object.assign(window, { innerHeight: 900 })
document.body.innerHTML = '<header class="main-header"></header>'
document.body.innerHTML = '<nav class="navbar"></nav>'
handler()
window.dispatchEvent(new Event('scroll'))
expect(
document.querySelector('header')!.classList.contains('transparent')
document.querySelector('nav')!.classList.contains('transparent')
).toBeTrue()
})
test('should not be transparent at bottom', () => {
Object.assign(window, { innerHeight: 900, scrollY: 800 })
document.body.innerHTML = '<header class="main-header transparent"></header>'
document.body.innerHTML = '<nav class="navbar transparent"></nav>'
handler()
window.dispatchEvent(new Event('scroll'))
expect(
document.querySelector('header')!.classList.contains('transparent')
document.querySelector('nav')!.classList.contains('transparent')
).toBeFalse()
})

View File

@ -17,8 +17,8 @@ test('render dependencies', async () => {
await flushPromises()
expect(wrapper.text()).toContain('admin.noDependencies')
expect(wrapper.find('span.label.bg-green').text()).toBe('a: ^1.0.0')
expect(wrapper.find('span.label.bg-red').text()).toBe('c: ^2.0.0')
expect(wrapper.find('span.badge.bg-green').text()).toBe('a: ^1.0.0')
expect(wrapper.find('span.badge.bg-red').text()).toBe('c: ^2.0.0')
})
test('render operation buttons', async () => {

View File

@ -1,6 +1,5 @@
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import { Button } from 'element-ui'
import { MessageBoxData } from 'element-ui/types/message-box'
import { flushPromises } from '../../utils'
import Players from '@/views/admin/Players.vue'
@ -30,13 +29,9 @@ test('change texture', async () => {
const wrapper = mount(Players)
await flushPromises()
const button = wrapper.find('[data-test=changeTexture]')
wrapper
.findAll(Button)
.at(0)
.trigger('click')
wrapper.findAll('.btn-default').trigger('click')
wrapper.find('.modal-body').find('input')
.setValue('5')
wrapper.find('.modal-body input').setValue('5')
button.trigger('click')
await flushPromises()
@ -134,7 +129,7 @@ test('delete player', async () => {
const wrapper = mount(Players)
await flushPromises()
const button = wrapper.findAll(Button).at(1)
const button = wrapper.find('.btn-danger')
button.trigger('click')
expect(Vue.prototype.$http.post).not.toBeCalled()

View File

@ -19,8 +19,8 @@ test('render dependencies', async () => {
await flushPromises()
expect(wrapper.text()).toContain('admin.noDependencies')
expect(wrapper.find('span.label.bg-green').text()).toBe('a: ^1.0.0')
expect(wrapper.find('span.label.bg-red').text()).toBe('c: ^2.0.0')
expect(wrapper.find('span.badge.bg-green').text()).toBe('a: ^1.0.0')
expect(wrapper.find('span.badge.bg-red').text()).toBe('c: ^2.0.0')
})
test('render operation buttons', async () => {

View File

@ -1,6 +1,5 @@
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import { Button } from 'element-ui'
import { MessageBoxData } from 'element-ui/types/message-box'
import { flushPromises } from '../../utils'
import Translations from '@/views/admin/Translations.vue'
@ -34,7 +33,7 @@ test('modify line', async () => {
const wrapper = mount(Translations)
await flushPromises()
const button = wrapper.findAll(Button).at(0)
const button = wrapper.find('.btn-default')
button.trigger('click')
await flushPromises()
@ -72,7 +71,7 @@ test('delete line', async () => {
const wrapper = mount(Translations)
await flushPromises()
const button = wrapper.findAll(Button).at(1)
const button = wrapper.find('.btn-danger')
button.trigger('click')
await flushPromises()

View File

@ -2,7 +2,6 @@ import Vue from 'vue'
import { mount } from '@vue/test-utils'
import Users from '@/views/admin/Users.vue'
import '@/scripts/i18n'
import { Button } from 'element-ui'
import { MessageBoxData } from 'element-ui/types/message-box'
import { flushPromises } from '../../utils'
@ -344,7 +343,7 @@ test('change password', async () => {
const wrapper = mount(Users)
await flushPromises()
const button = wrapper.findAll(Button).at(0)
const button = wrapper.find('.btn-default')
button.trigger('click')
expect(Vue.prototype.$http.post).not.toBeCalled()
@ -481,7 +480,7 @@ test('delete user', async () => {
const wrapper = mount(Users)
await flushPromises()
const button = wrapper.findAll(Button).at(1)
const button = wrapper.find('.btn-danger')
button.trigger('click')
expect(Vue.prototype.$http.post).not.toBeCalled()

View File

@ -20,8 +20,8 @@ test('submit forgot form', async () => {
.mockResolvedValueOnce({ code: 0, message: 'ok' })
const wrapper = mount(Forgot, { stubs: { Captcha } })
const form = wrapper.find('form')
const warning = wrapper.find('.callout-warning')
const success = wrapper.find('.callout-success')
const warning = wrapper.find('.alert-warning')
const success = wrapper.find('.alert-success')
wrapper.find('[type="email"]').setValue('a@b.c')
form.trigger('submit')

View File

@ -31,7 +31,7 @@ test('login', async () => {
})
const wrapper = mount(Login, { stubs: { Captcha } })
const form = wrapper.find('form')
const warning = wrapper.find('.callout-warning')
const warning = wrapper.find('.alert-warning')
wrapper.find('input').setValue('a@b.c')
wrapper.find('[type="password"]').setValue('123')

View File

@ -31,8 +31,8 @@ test('register', async () => {
.mockResolvedValueOnce({ code: 0, message: 'ok' })
const wrapper = mount(Register, { stubs: { Captcha } })
const form = wrapper.find('form')
const info = wrapper.find('.callout-info')
const warning = wrapper.find('.callout-warning')
const info = wrapper.find('.alert-info')
const warning = wrapper.find('.alert-warning')
wrapper.find('[type="email"]').setValue('a@b.c')
wrapper.findAll('[type="password"]').at(0)

View File

@ -13,8 +13,8 @@ test('reset password', async () => {
},
})
const form = wrapper.find('form')
const info = wrapper.find('.callout-info')
const warning = wrapper.find('.callout-warning')
const info = wrapper.find('.alert-info')
const warning = wrapper.find('.alert-warning')
wrapper.findAll('[type="password"]').at(0)
.setValue('12345678')

View File

@ -1,62 +1,9 @@
import Vue from 'vue'
import { mount } from '@vue/test-utils'
// @ts-ignore
import Button from 'element-ui/lib/button'
import { flushPromises } from '../../utils'
import { queryString } from '@/scripts/utils'
import List from '@/views/skinlib/List.vue'
jest.mock('element-ui', () => ({
Select: {
install(vue: typeof Vue) {
vue.component('ElSelect', {
render(h) {
return h('select', {
on: {
change: (event: Event) => this.$emit(
'change',
(event.target as HTMLSelectElement).value
),
},
attrs: {
value: this.value,
},
}, this.$slots.default)
},
props: {
value: String,
},
model: {
prop: 'value',
event: 'change',
},
})
},
},
Option: {
install(vue: typeof Vue) {
vue.component('ElOption', {
render(h) {
return h('option', { attrs: { value: this.value } }, this.label)
},
props: {
label: String,
value: String,
},
})
},
},
ButtonGroup: {
install(vue: typeof Vue) {
vue.component('ElButtonGroup', {
render(h) {
return h('div', {}, this.$slots.default)
},
})
},
},
}))
beforeEach(() => {
window.history.pushState(null, '', 'skinlib')
})
@ -93,22 +40,42 @@ test('toggle texture type', () => {
},
})
const wrapper = mount(List)
const select = wrapper.find({ name: 'ElSelect' })
const options = wrapper.findAll('.dropdown-item')
const btnSkin = options.at(0)
const btnSteve = options.at(1)
const btnAlex = options.at(2)
const btnCape = options.at(3)
const dropdownToggle = wrapper.find('.dropdown-toggle')
const breadcrumb = wrapper.find('.breadcrumb')
expect(btnSkin.classes()).toContain('active')
expect(btnSteve.classes()).not.toContain('active')
expect(btnAlex.classes()).not.toContain('active')
expect(btnCape.classes()).not.toContain('active')
expect(dropdownToggle.text()).toContain('general.skin')
expect(breadcrumb.text()).toContain('skinlib.filter.skin')
select.setValue('steve')
select.trigger('change')
btnSteve.trigger('click')
expect(btnSkin.classes()).not.toContain('active')
expect(btnSteve.classes()).toContain('active')
expect(btnAlex.classes()).not.toContain('active')
expect(btnCape.classes()).not.toContain('active')
expect(dropdownToggle.text()).toContain('Steve')
expect(breadcrumb.text()).toContain('skinlib.filter.steve')
expect(queryString('filter')).toBe('steve')
expect(Vue.prototype.$http.get).toBeCalledWith(
'/skinlib/data',
{
filter: 'steve', uploader: 0, sort: 'time', keyword: '', page: 1,
}
)
expect(queryString('filter')).toBe('steve')
select.setValue('alex')
select.trigger('change')
btnAlex.trigger('click')
expect(btnSkin.classes()).not.toContain('active')
expect(btnSteve.classes()).not.toContain('active')
expect(btnAlex.classes()).toContain('active')
expect(btnCape.classes()).not.toContain('active')
expect(dropdownToggle.text()).toContain('Alex')
expect(breadcrumb.text()).toContain('skinlib.filter.alex')
expect(Vue.prototype.$http.get).toBeCalledWith(
'/skinlib/data',
@ -117,8 +84,13 @@ test('toggle texture type', () => {
}
)
expect(queryString('filter')).toBe('alex')
select.setValue('cape')
select.trigger('change')
btnCape.trigger('click')
expect(btnSkin.classes()).not.toContain('active')
expect(btnSteve.classes()).not.toContain('active')
expect(btnAlex.classes()).not.toContain('active')
expect(btnCape.classes()).toContain('active')
expect(dropdownToggle.text()).toContain('general.cape')
expect(breadcrumb.text()).toContain('general.cape')
expect(Vue.prototype.$http.get).toBeCalledWith(
'/skinlib/data',
@ -138,13 +110,11 @@ test('check specified uploader', async () => {
const wrapper = mount(List)
await flushPromises()
const breadcrumb = wrapper.find('.breadcrumb')
const button = wrapper
.find('.advanced-filter')
.findAll(Button)
.at(2)
const button = wrapper.findAll('.bg-olive').at(2)
expect(breadcrumb.text()).toContain('skinlib.filter.allUsers')
button.trigger('click')
expect(button.classes()).toContain('active')
expect(breadcrumb.text()).toContain('skinlib.filter.uploader')
expect(Vue.prototype.$http.get).toBeCalledWith(
'/skinlib/data',
@ -162,7 +132,7 @@ test('sort items', () => {
},
})
const wrapper = mount(List)
const buttons = wrapper.find('.advanced-filter').findAll(Button)
const buttons = wrapper.findAll('.bg-olive')
const sortByLikes = buttons.at(0)
const sortByTime = buttons.at(1)
@ -174,6 +144,7 @@ test('sort items', () => {
}
)
expect(wrapper.text()).toContain('skinlib.sort.likes')
expect(sortByLikes.classes()).toContain('active')
expect(queryString('sort')).toBe('likes')
sortByTime.trigger('click')
@ -184,6 +155,7 @@ test('sort items', () => {
}
)
expect(wrapper.text()).toContain('skinlib.sort.time')
expect(sortByTime.classes()).toContain('active')
expect(queryString('sort')).toBe('time')
})
@ -194,8 +166,9 @@ test('search by keyword', () => {
},
})
const wrapper = mount(List)
const input = wrapper.find('[data-test="keyword"]')
wrapper.setData({ keyword: 'a' })
input.setValue('a')
wrapper.find('form').trigger('submit')
expect(Vue.prototype.$http.get).toBeCalledWith(
'/skinlib/data',
@ -205,7 +178,7 @@ test('search by keyword', () => {
)
expect(queryString('keyword')).toBe('a')
wrapper.setData({ keyword: 'b' })
input.setValue('b')
wrapper.find('[data-test="btn-search"]').trigger('click')
expect(Vue.prototype.$http.get).toBeCalledWith(
'/skinlib/data',
@ -223,10 +196,12 @@ test('reset all filters', () => {
},
})
const wrapper = mount(List)
wrapper.findAll('option').at(3)
.setSelected()
wrapper
.findAll('.dropdown-item')
.at(3)
.trigger('click')
wrapper.setData({ keyword: 'abc' })
const buttons = wrapper.find('.advanced-filter').findAll(Button)
const buttons = wrapper.findAll('.bg-olive')
buttons.at(1).trigger('click')
Vue.prototype.$http.get.mockClear()

View File

@ -1,6 +1,5 @@
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import { Button } from 'element-ui'
import Show from '@/views/skinlib/Show.vue'
import { MessageBoxData } from 'element-ui/types/message-box'
import { flushPromises } from '../../utils'
@ -35,7 +34,7 @@ test('button for adding to closet should be disabled if not auth', () => {
},
stubs: { previewer },
})
expect(wrapper.find(Button).attributes('disabled')).toBe('disabled')
expect(wrapper.find('.btn').attributes('disabled')).toBe('disabled')
})
test('button for adding to closet should be enabled if auth', () => {
@ -59,7 +58,7 @@ test('likes count indicator', async () => {
stubs: { previewer },
})
await flushPromises()
expect(wrapper.find('.likes').attributes('style')).toContain('color: rgb(224, 53, 59)')
expect(wrapper.find('.likes').classes()).toContain('text-red')
expect(wrapper.find('.likes').text()).toContain('2')
})
@ -79,7 +78,7 @@ test('render basic information', async () => {
},
})
await flushPromises()
const text = wrapper.find('.box-primary').text()
const text = wrapper.find('.card-primary').text()
expect(text).toContain('my-texture')
expect(text).toContain('alex')
expect(text).toContain('123...')
@ -130,7 +129,7 @@ test('operation panel should not be rendered if user is anonymous', async () =>
},
})
await flushPromises()
expect(wrapper.find('.box-warning').exists()).toBeFalse()
expect(wrapper.find('.card-warning').exists()).toBeFalse()
})
test('operation panel should not be rendered if not privileged', async () => {
@ -142,7 +141,7 @@ test('operation panel should not be rendered if not privileged', async () => {
},
})
await flushPromises()
expect(wrapper.find('.box-warning').exists()).toBeFalse()
expect(wrapper.find('.card-warning').exists()).toBeFalse()
})
test('operation panel should be rendered if privileged', async () => {
@ -154,7 +153,7 @@ test('operation panel should be rendered if privileged', async () => {
},
})
await flushPromises()
expect(wrapper.find('.box-warning').exists()).toBeTrue()
expect(wrapper.find('.card-warning').exists()).toBeTrue()
})
test('download texture', async () => {
@ -303,7 +302,9 @@ test('change texture model', async () => {
},
stubs: { previewer },
})
const button = wrapper.findAll('small').at(1)
const button = wrapper
.findAll('small')
.at(1)
.find('a')
button.trigger('click')
@ -336,10 +337,7 @@ test('toggle privacy', async () => {
},
stubs: { previewer },
})
const button = wrapper
.find('.box-warning')
.findAll(Button)
.at(0)
const button = wrapper.find('.btn-warning')
button.trigger('click')
expect(Vue.prototype.$http.post).not.toBeCalled()
@ -375,10 +373,7 @@ test('delete texture', async () => {
},
stubs: { previewer },
})
const button = wrapper
.find('.box-warning')
.findAll(Button)
.at(1)
const button = wrapper.find('.btn-danger')
button.trigger('click')
expect(Vue.prototype.$http.post).not.toBeCalled()
@ -472,5 +467,5 @@ test('truncate too long texture name', async () => {
},
})
await flushPromises()
expect(wrapper.find('.box-primary').text()).toContain('very-very-long-...')
expect(wrapper.find('.card-primary').text()).toContain('very-very-long-...')
})

View File

@ -130,7 +130,7 @@ test('upload file', async () => {
const wrapper = mount(Upload, {
stubs: ['file-upload'],
})
const button = wrapper.find('.box-footer > button')
const button = wrapper.find('.btn-success')
button.trigger('click')
expect(Vue.prototype.$http.post).not.toBeCalled()

View File

@ -32,7 +32,7 @@ test('submit', async () => {
form.trigger('submit')
await flushPromises()
expect(wrapper.find('.callout').text()).toBe('fail')
expect(wrapper.find('.alert').text()).toBe('fail')
form.trigger('submit')
await flushPromises()

View File

@ -38,8 +38,10 @@ test('switch tabs', () => {
const wrapper = mount(Closet)
const tabSkin = wrapper.findAll('.nav-tabs > li').at(0)
tabSkin.find('a').trigger('click')
wrapper
.findAll('.nav-link')
.at(0)
.trigger('click')
jest.runAllTicks()
expect(Vue.prototype.$http.get).toBeCalledWith(
'/user/closet-data',
@ -49,8 +51,10 @@ test('switch tabs', () => {
page: 1,
}
)
const tabCape = wrapper.findAll('.nav-tabs > li').at(1)
tabCape.find('a').trigger('click')
wrapper
.findAll('.nav-link')
.at(1)
.trigger('click')
jest.runAllTicks()
expect(Vue.prototype.$http.get).toBeCalledWith(
'/user/closet-data',
@ -66,13 +70,21 @@ test('different categories', () => {
Vue.prototype.$http.get.mockResolvedValue({ data: {} })
const wrapper = mount(Closet)
expect(wrapper.findAll('.nav-tabs > li').at(0)
.classes('active')).toBeTrue()
expect(
wrapper
.findAll('.nav-link')
.at(0)
.classes('active')
).toBeTrue()
expect(wrapper.find('#skin-category').classes('active')).toBeTrue()
wrapper.setData({ category: 'cape' })
expect(wrapper.findAll('.nav-tabs > li').at(1)
.classes('active')).toBeTrue()
expect(
wrapper
.findAll('.nav-link')
.at(1)
.classes('active')
).toBeTrue()
expect(wrapper.find('#cape-category').classes('active')).toBeTrue()
})

View File

@ -1,7 +1,6 @@
/* eslint-disable no-mixed-operators */
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import { Button } from 'element-ui'
import { flushPromises } from '../../utils'
import Dashboard from '@/views/user/Dashboard.vue'
@ -98,19 +97,19 @@ test('button `sign` state', async () => {
let wrapper = mount(Dashboard)
await flushPromises()
expect(wrapper.find(Button).attributes('disabled')).toBeNil()
expect(wrapper.find('button').attributes('disabled')).toBeNil()
wrapper = mount(Dashboard)
await flushPromises()
expect(wrapper.find(Button).attributes('disabled')).toBe('disabled')
expect(wrapper.find('button').attributes('disabled')).toBe('disabled')
wrapper = mount(Dashboard)
await flushPromises()
expect(wrapper.find(Button).attributes('disabled')).toBeNil()
expect(wrapper.find('button').attributes('disabled')).toBeNil()
wrapper = mount(Dashboard)
await flushPromises()
expect(wrapper.find(Button).attributes('disabled')).toBe('disabled')
expect(wrapper.find('button').attributes('disabled')).toBe('disabled')
})
test('remaining time', async () => {
@ -127,13 +126,13 @@ test('remaining time', async () => {
let wrapper = mount(Dashboard)
await flushPromises()
expect(wrapper.find(Button).text()).toMatch(/(29)|(30)/)
expect(wrapper.find(Button).text()).toContain('min')
expect(wrapper.find('button').text()).toMatch(/(29)|(30)/)
expect(wrapper.find('button').text()).toContain('min')
wrapper = mount(Dashboard)
await flushPromises()
expect(wrapper.find(Button).text()).toContain('23')
expect(wrapper.find(Button).text()).toContain('hour')
expect(wrapper.find('button').text()).toContain('23')
expect(wrapper.find('button').text()).toContain('hour')
Vue.prototype.$t = origin
})
@ -154,7 +153,7 @@ test('sign', async () => {
},
})
const wrapper = mount(Dashboard)
const button = wrapper.find(Button)
const button = wrapper.find('button')
await flushPromises()
button.trigger('click')
@ -171,7 +170,7 @@ test('sign', async () => {
test('disable button when signing', () => {
Vue.prototype.$http.get.mockResolvedValue(scoreInfo())
const wrapper = mount(Dashboard)
const button = wrapper.find(Button)
const button = wrapper.find('button')
expect(button.attributes('disabled')).toBeFalsy()
wrapper.setData({ signing: true })
expect(button.attributes('disabled')).toBeTruthy()

View File

@ -1,6 +1,5 @@
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import { Button } from 'element-ui'
import { MessageBoxData } from 'element-ui/types/message-box'
import { flushPromises } from '../../utils'
import Players from '@/views/user/Players.vue'
@ -101,7 +100,7 @@ test('change player name', async () => {
})
const wrapper = mount(Players)
await flushPromises()
const button = wrapper.findAll(Button).at(0)
const button = wrapper.find('.btn-default')
button.trigger('click')
expect(Vue.prototype.$http.post).not.toBeCalled()
@ -132,7 +131,7 @@ test('delete player', async () => {
.mockResolvedValue('confirm')
const wrapper = mount(Players)
await flushPromises()
const button = wrapper.findAll(Button).at(2)
const button = wrapper.findAll('.btn-danger')
button.trigger('click')
expect(Vue.prototype.$http.post).not.toBeCalled()

View File

@ -5,16 +5,27 @@
<title>{% block title %}{% endblock %} - {{ site_name }}</title>
</head>
<body class="hold-transition {{ color_scheme }} sidebar-mini">
<body class="hold-transition sidebar-mini">
<div class="wrapper">
{{ include('shared.header') }}
{{ include('shared.sidebar', {scope: 'admin'}) }}
<div class="content-wrapper">
<section class="content-header">
<h1>{{ block('title') }}</h1>
</section>
<div class="content-header">
<div class="container-fluid">
<div class="d-flex justify-content-between flex-wrap">
<div>
<h1 class="m-0 text-dark">{{ block('title') }}</h1>
</div>
<div>
<div class="breadcrumb"></div>
</div>
</div>
</div>
</div>
<section class="content">
{% block content %}{% endblock %}
<div class="container-fluid">
{% block content %}{% endblock %}
</div>
</section>
</div>
<footer class="main-footer">

View File

@ -5,14 +5,14 @@
{% block content %}
<div class="row">
<div class="col-md-3">
<form class="box box-primary" method="post" action="{{ url('/admin/customize?action=color') }}">
<form class="card box-primary" method="post" action="{{ url('/admin/customize?action=color') }}">
{{ csrf_field() }}
<div class="box-header with-border">
<h3 class="box-title">
<div class="card-header">
<h3 class="card-title">
{{ trans('admin.customize.change-color.title') }}
</h3>
</div>
<div class="box-body no-padding">
<div class="card-body p-0">
<table class="table table-striped bring-up nth-2-center" id="change-color">
<tbody>
{% for color in colors %}
@ -52,10 +52,10 @@
</tbody>
</table>
</div>
<div class="box-footer">
<div class="card-footer">
<input
type="submit"
class="el-button el-button--primary"
class="btn btn-primary"
value="{{ trans('general.submit') }}"
name="submit_color"
>

View File

@ -7,15 +7,21 @@
<div class="col-lg-8"><div id="table"></div></div>
<div class="col-lg-4">
<form action="{{ url('/admin/i18n') }}" method="post">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">{{ trans('admin.i18n.add') }}</h3>
<div class="card card-primary">
<div class="card-header">
<h3 class="card-title">{{ trans('admin.i18n.add') }}</h3>
</div>
<div class="box-body">
<div class="card-body p-0">
{% if errors.any %}
<div class="callout callout-danger">{{ errors.first }}</div>
<div class="alert alert-danger m-3">
<i class="icon fas fa-exclamation-triangle"></i>
{{ errors.first }}
</div>
{% elseif session_pull('success') %}
<div class="callout callout-success">{{ trans('admin.i18n.added') }}</div>
<div class="alert alert-success m-3">
<i class="icon fas fa-check"></i>
{{ trans('admin.i18n.added') }}
</div>
{% endif %}
{{ csrf_field() }}
<table class="table">
@ -41,11 +47,11 @@
</tbody>
</table>
</div>
<div class="box-footer">
<div class="card-footer">
<input
type="submit"
value="{{ trans('general.submit') }}"
class="el-button el-button--primary"
class="btn btn-primary"
>
</div>
</div>

View File

@ -7,7 +7,7 @@
<div class="col-md-6">
<div class="row">
<div class="col-md-6">
<div class="small-box bg-aqua">
<div class="small-box bg-info">
<div class="inner">
<h3>{{ sum.users }}</h3>
<p>{{ trans('admin.index.total-users') }}</p>
@ -61,13 +61,13 @@
</div>
</div>
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ trans('admin.notifications.send.title') }}</h3>
<div class="card">
<div class="card-header">
<h3 class="card-title">{{ trans('admin.notifications.send.title') }}</h3>
</div>
<form method="post" action="{{ url('/admin/notifications/send') }}">
{{ csrf_field() }}
<div class="box-body">
<div class="card-body">
{% if errors.any %}
<div class="callout callout-danger">{{ errors.first }}</div>
{% endif %}
@ -113,11 +113,11 @@
<textarea name="content" class="form-control" rows="3"></textarea>
</div>
</div>
<div class="box-footer">
<div class="card-footer">
<input
type="submit"
value="{{ trans('general.submit') }}"
class="el-button el-button--primary"
class="btn btn-primary"
>
</div>
</form>
@ -125,11 +125,11 @@
</div>
<div class="col-md-6">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">{{ trans('admin.index.overview') }}</h3>
<div class="card card-primary">
<div class="card-header">
<h3 class="card-title">{{ trans('admin.index.overview') }}</h3>
</div>
<div class="box-body"><div id="chart"></div></div>
<div class="card-body"><div id="chart"></div></div>
</div>
</div>
</div>

View File

@ -6,7 +6,7 @@
@yield('style')
</head>
<body class="hold-transition {{ option('color_scheme') }} sidebar-mini">
<body class="hold-transition sidebar-mini">
<div class="wrapper">
@include('shared.header')
@include('shared.sidebar', ['scope' => 'admin'])

View File

@ -5,11 +5,11 @@
{% block content %}
<div class="row">
<div class="col-md-6">
<div class="box">
<div class="box-header">
<h3 class="box-title">{{ trans('admin.status.info') }}</h3>
<div class="card card-info">
<div class="card-header">
<h3 class="card-title">{{ trans('admin.status.info') }}</h3>
</div>
<div class="box-body">
<div class="card-body">
<table class="table table-bordered table-striped">
<tbody>
{% for category, info in detail %}

View File

@ -5,11 +5,11 @@
{% block content %}
<div class="row">
<div class="col-md-6">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">{{ trans('admin.update.info.title') }}</h3>
<div class="card card-primary">
<div class="card-header">
<h3 class="card-title">{{ trans('admin.update.info.title') }}</h3>
</div>
<div class="box-body">
<div class="card-body">
{% if extra.canUpdate %}
<div class="callout callout-info">
{{ trans('admin.update.info.available') }}
@ -53,25 +53,26 @@
</table>
{% endif %}
</div>
<div class="box-footer">
<div class="card-footer">
<span id="update-button"></span>
<a
target="_blank"
class="el-button pull-right"
class="btn btn-default float-right"
href="https://github.com/bs-community/blessing-skin-server/releases"
>
{{ trans('admin.update.info.check-github') }}
</a>
</div>
</div>
<div class="box box-default">
<div class="box-header with-border">
<h3 class="box-title">
</div>
<div class="col-md-6">
<div class="card card-info">
<div class="card-header">
<h3 class="card-title">
{{ trans('admin.update.cautions.title') }}
</h3>
</div>
<div class="box-body">
<div class="card-body">
{% for text in trans('admin.update.cautions.text')|split('\n') %}
<p>{{ text }}</p>
{% endfor %}

View File

@ -11,8 +11,10 @@
<a href="{{ url('/') }}">{{ site_name }}</a>
</div>
<div class="login-box-body">
{% block content %}{% endblock %}
<div class="card">
<div class="card-body login-card-body">
{% block content %}{% endblock %}
</div>
</div>
</div>

View File

@ -6,29 +6,31 @@
<p class="login-box-msg">{{ trans('auth.bind.message') }}</p>
<form method="post" id="login-form" action="{{ url('/auth/bind') }}">
{{ csrf_field() }}
<div class="form-group has-feedback">
<div class="input-group mb-3">
<input
name="email"
type="email"
class="form-control"
placeholder="{{ trans('auth.email') }}"
>
<span class="glyphicon glyphicon-envelope form-control-feedback"></span>
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-envelope" />
</div>
</div>
</div>
<p>{{ trans('auth.bind.introduction') }}</p>
{% if errors.any %}
<div id="msg" class="callout callout-warning">{{ errors.first }}</div>
<div class="alert alert-warning">
<i class="icon fas fa-exclamation-triangle" />
{{ errors.first }}
</div>
{% endif %}
<div class="row">
<div class="col-xs-8"></div>
<div class="col-xs-4">
<button type="submit" class="btn btn-primary btn-block btn-flat">
{{ trans('auth.bind.button') }}
</button>
</div>
</div>
<button type="submit" class="btn btn-primary btn-block mt-3">
{{ trans('auth.bind.button') }}
</button>
</form>
{% endblock %}

View File

@ -5,7 +5,9 @@
{% block content %}
<p class="login-box-msg">{{ trans('auth.forgot.message') }}</p>
{% if session_has('msg') %}
<div class="callout callout-warning">{{ session_pull('msg') }}</div>
<div class="alert alert-warning">
{{ session_pull('msg') }}
</div>
{% endif %}
<form></form>
{% endblock %}

View File

@ -5,13 +5,13 @@
{% block content %}
<p class="login-box-msg">{{ trans('auth.login.message') }}</p>
{% if session_has('msg') %}
<div class="callout callout-warning">{{ session_pull('msg') }}</div>
<div class="alert alert-warning">
{{ session_pull('msg') }}
</div>
{% endif %}
<form></form>
<br>
<a href="{{ url('auth/register') }}" class="pull-left" style="margin-top: -10px;">
{{ trans('auth.register-link') }}
</a>
<a href="{{ url('auth/register') }}">{{ trans('auth.register-link') }}</a>
{% endblock %}
{% block before_foot %}

View File

@ -6,14 +6,10 @@
<p class="login-box-msg">
{{ trans('auth.verify.message', {sitename: site_name}) }}
</p>
<div class="callout callout-success">
<div class="alert alert-success mb-5">
<i class="icon fa fa-check"></i> {{ trans('auth.verify.success') }}
</div>
<div class="row">
<div class="col-xs-6 pull-right">
<a href="{{ url('/') }}" class="btn btn-primary btn-block btn-flat">
{{ trans('auth.verify.button') }}
</a>
</div>
</div>
<a href="{{ url('/') }}" class="btn btn-primary btn-block">
{{ trans('auth.verify.button') }}
</a>
{% endblock %}

View File

@ -1 +0,0 @@
<span class="input-group-addon">{{ $value }}</span>

View File

@ -0,0 +1,3 @@
<div class="input-group-append">
<span class="input-group-text">{{ value }}</span>
</div>

View File

@ -1,11 +1,11 @@
<div class="box box-{{ $type }}">
<div class="box-header with-border">
<h3 class="box-title">{{ $title }} {!! $hint ?? '' !!}</h3>
</div><!-- /.box-header -->
<div class="card card-{{ $type }}">
<div class="card-header">
<h3 class="card-title">{{ $title }} {!! $hint ?? '' !!}</h3>
</div>
<form method="post">
@csrf
<input type="hidden" name="option" value="{{ $id }}">
<div class="box-body">
<div class="card-body">
@foreach($messages as $msg)
{!! $msg !!}
@ -31,8 +31,8 @@
</table>
@endif
</div><!-- /.box-body -->
<div class="box-footer">
</div>
<div class="card-footer">
@foreach($buttons as $button)
{!! $button !!}
@endforeach

View File

@ -10,69 +10,46 @@
{% else %}
background-image: url('{{ home_pic_url }}');
{% endif %}
height: 100vh;
}
{% if hide_intro %}
#copyright {
color: white;
position: fixed;
bottom: 0;
width: 100%;
padding: 0 50px 16px 50px;
}
{% else %}
#copyright {
background: #222;
padding: 16px 0 20px;
color: white;
}
{% endif %}
</style>
</head>
<body class="hold-transition {{ color_scheme }} layout-top-nav">
<body class="hold-transition layout-top-nav">
<div class="hp-wrapper">
{% if fixed_bg %}
<div id="fixed-bg" style="background-image: url('{{ home_pic_url }}')"></div>
{% endif %}
<header class="main-header {{ transparent_navbar ? 'transparent' }}">
<nav class="navbar navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<a href="{{ url('/') }}" class="navbar-brand">{{ site_name }}</a>
</div>
<div class="collapse navbar-collapse pull-left" id="navbar-collapse">
<ul class="nav navbar-nav">
<li class="active">
<a href="{{ url('/') }}">{{ trans('general.index') }}</a>
</li>
<li>
<a href="{{ url('skinlib') }}">{{ trans('general.skinlib') }}</a>
</li>
</ul>
</div>
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
{{ include('shared.languages') }}
{% if auth_check() %}
{{ include('shared.user-menu') }}
{% else %}
<li class="dropdown user user-menu">
<a href="{{ url('auth/login') }}" class="btn btn-login">
{{ trans('general.login') }}
</a>
</li>
{% endif %}
</ul>
</div>
<nav class="navbar navbar-expand fixed-top navbar-light navbar-white
ml-0 {{ transparent_navbar ? 'transparent' }}"
>
<div class="container">
<div class="navbar-header">
<a href="{{ url('/') }}" class="navbar-brand">{{ site_name }}</a>
</div>
</nav>
</header>
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
<li class="nav-item">
<a class="nav-link" href="{{ url('skinlib') }}">{{ trans('general.skinlib') }}</a>
</li>
{{ include('shared.languages') }}
{% if auth_check() %}
{{ include('shared.user-menu') }}
{% else %}
<li class="nav-item">
<a class="nav-link" href="{{ url('auth/login') }}">
<i class="icon fas fa-sign-in-alt"></i>
{{ trans('general.login') }}
</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="splash">
@ -87,11 +64,11 @@
</a>
{% else %}
{% if user_can_register %}
<a href="{{ url('auth/register') }}" id="btn-register" class="button">
<a href="{{ url('auth/register') }}" class="button">
{{ trans('general.register') }}
</a>
{% else %}
<a href="{{ url('auth/login') }}" id="btn-close-register" class="button">
<a href="{{ url('auth/login') }}" class="button">
{{ trans('general.login') }}
</a>
{% endif %}
@ -101,7 +78,7 @@
</div>
{% if hide_intro %}
<div id="copyright">
<div id="copyright" class="without-intro">
<div class="container">
{{ include('shared.copyright') }}
</div>
@ -112,34 +89,36 @@
{% if not hide_intro %}
<div id="intro">
<div class="container">
<div class="row text-center">
<div class="text-center">
<h1>{{ trans('index.features.title') }}</h1>
<br>
<br>
{% for item in ['first', 'second', 'third'] %}
<div class="col-lg-4">
<i class="fas {{ trans("index.features.#{item}.icon") }}" aria-hidden="true"></i>
<h3>{{ trans("index.features.#{item}.name") }}</h3>
<p>{{ trans("index.features.#{item}.desc") }}</p>
</div>
{% endfor %}
<div class="container d-flex">
{% for item in ['first', 'second', 'third'] %}
<div class="col-lg-4">
<i class="fas {{ trans("index.features.#{item}.icon") }} mb-3" aria-hidden="true"></i>
<h3>{{ trans("index.features.#{item}.name") }}</h3>
<p>{{ trans("index.features.#{item}.desc") }}</p>
</div>
{% endfor %}
</div>
</div>
<br>
</div>
</div>
<div id="footerwrap">
<div class="container">
<div class="container d-flex">
<div class="col-lg-6">
{{ trans('index.introduction', {sitename: site_name}) }}
</div>
<div class="col-lg-6">
<a href="{{ url('auth/register') }}" id="btn-register" class="button">
<a href="{{ url('auth/register') }}" class="button">
{{ trans('index.start') }}
</a>
</div>
</div>
</div>
<div id="copyright">
<div id="copyright" class="with-intro">
<div class="container">
{{ include('shared.copyright') }}
</div>

View File

@ -1,7 +1,7 @@
{% set repo = 'https://github.com/bs-community/blessing-skin-server' %}
<!-- YOU CAN NOT MODIFIY THE COPYRIGHT TEXT W/O PERMISSION -->
<div id="copyright-text" class="pull-right hidden-xs">
<div id="copyright-text" class="float-right d-none d-sm-inline">
{% if copyright == 0 %}
Powered with ❤ by <a href="{{ repo }}">Blessing Skin Server</a>.
{% elseif copyright == 1 %}
@ -15,5 +15,4 @@
{% endif %}
</div>
<!-- Default to the left -->
{{ custom_copyright|raw }}

View File

@ -1,26 +1,15 @@
<header class="main-header">
<!-- Logo -->
<a href="{{ url('/') }}" class="logo">
<!-- mini logo for sidebar mini 50x50 pixels -->
<span class="logo-mini"> <i class="fas fa-bookmark"></i> </span>
<!-- logo for regular state and mobile devices -->
<span class="logo-lg">{{ site_name }}</span>
</a>
<nav class="main-header navbar navbar-expand navbar-white navbar-light">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" data-widget="pushmenu" href="#">
<i class="fas fa-bars"></i>
</a>
</li>
</ul>
<!-- Header Navbar -->
<nav class="navbar navbar-static-top" role="navigation">
<!-- Sidebar toggle button-->
<a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button">
<i class="fas fa-bars"></i>
<span class="sr-only">Toggle navigation</span>
</a>
<!-- Navbar Right Menu -->
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
{{ include('shared.notifications') }}
{{ include('shared.languages') }}
{{ include('shared.user-menu') }}
</ul>
</div>
</nav>
</header>
<ul class="navbar-nav ml-auto">
{{ include('shared.notifications') }}
{{ include('shared.languages') }}
{{ include('shared.user-menu') }}
</ul>
</nav>

View File

@ -1,14 +1,14 @@
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<li class="nav-item dropdown">
<a class="nav-link" data-toggle="dropdown" href="#">
<i class="fas fa-language" aria-hidden="true"></i>
<span class="description-text">{{ current }}</span>
<span class="caret"></span>
<span class="d-none d-sm-inline">{{ current }}</span>
</a>
<ul class="dropdown-menu" role="menu" id="language-menu">
<div class="dropdown-menu dropdown-menu-lg dropdown-menu-right">
{% for lang in langs %}
<li class="locale">
<a href="{{ lang.url }}">{{ lang.name }}</a>
</li>
<a href="{{ lang.url }}" class="dropdown-item locale">
{{ lang.name }}
</a>
<div class="dropdown-divider"></div>
{% endfor %}
</ul>
</div>
</li>

View File

@ -1,25 +1,24 @@
<li class="dropdown notifications-menu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="fas fa-bell"></i>
<li class="nav-item dropdown">
<a class="nav-link" data-toggle="dropdown" href="#">
<i class="far fa-bell"></i>
{% if amount > 0 %}
<span class="label label-warning notifications-counter">{{ amount }}</span>
<span class="badge badge-warning navbar-badge notifications-counter">
{{ amount }}
</span>
{% endif %}
</a>
<ul class="dropdown-menu">
<div class="dropdown-menu dropdown-menu-lg dropdown-menu-right">
{% if amount == 0 %}
<li class="header text-center">{{ trans('user.no-unread') }}</li>
<p class="text-center text-muted pt-2 pb-2">{{ trans('user.no-unread') }}</p>
{% else %}
<li>
<ul class="menu notifications-list">
{% for notification in notifications %}
<li>
<a href="#" data-nid="{{ notification.id }}">
<i class="far fa-circle text-aqua"></i> {{ notification.data.title }}
</a>
</li>
{% endfor %}
</ul>
</li>
<div class="notifications-list">
{% for notification in notifications %}
<a href="#" class="dropdown-item" data-nid="{{ notification.id }}">
<i class="far fa-circle text-info"></i> {{ notification.data.title }}
</a>
<div class="dropdown-divider"></div>
{% endfor %}
</div>
{% endif %}
</ul>
</div>
</li>

View File

@ -1,13 +1,11 @@
<li class="{{ item.classes|join(' ') }}">
<li class="nav-item {{ item.classes|join(' ') }}">
{% if item.children %}
<a href="#">
<i class="fas {{ item.icon }}"></i> &nbsp;
<span>{{ trans(item.title) }}</span>
<span class="pull-right-container">
<i class="fas fa-angle-left pull-right"></i>
</span>
<a class="nav-link" href="#">
<i class="nav-icon fas {{ item.icon }}"></i>
<p>{{ trans(item.title) }}</p>
<i class="right fas fa-angle-left"></i>
</a>
<ul class="treeview-menu">
<ul class="nav nav-treeview">
{% for child in item.children %}
{{ include('shared.side-menu-item', {item: child}) }}
{% endfor %}
@ -15,13 +13,14 @@
{% else %}
<a
href="{{ url(item.link) }}"
class="nav-link"
{% if attribute(item, 'new-tab') %}
target="_blank"
rel="noopener noreferrer"
{% endif %}
>
<i class="{{ item.icon == 'fa-circle' ? 'far' : 'fas' }} {{ item.icon }}"></i>
&nbsp;<span>{{ trans(item.title) }}</span>
<i class="nav-icon {{ item.icon == 'fa-circle' ? 'far' : 'fas' }} {{ item.icon }}"></i>
&nbsp;<p>{{ trans(item.title) }}</p>
</a>
{% endif %}
</li>

View File

@ -1,44 +1,53 @@
<aside class="main-sidebar">
<section class="sidebar">
<aside class="main-sidebar sidebar-dark-primary elevation-3">
<a href="{{ url('/') }}" class="brand-link text-center">
<span class="brand-text font-weight-light">{{ site_name }}</span>
</a>
<div class="sidebar">
{{ include('shared.user-panel') }}
<ul class="sidebar-menu tree" data-widget="tree">
<nav class="mt-2">
<ul
class="nav nav-pills nav-sidebar flex-column nav-child-indent"
data-widget="treeview"
role="menu"
>
{% if scope == 'user' %}
{% if scope == 'user' %}
<li class="header">{{ trans('general.user-center') }}</li>
{{ include('shared.side-menu', {type: 'user'}) }}
<li class="header">{{ trans('general.explore') }}</li>
{{ include('shared.side-menu', {type: 'explore'}) }}
{% if auth_user().admin %}
<li class="header">{{ trans('general.manage') }}</li>
<li>
<a href="{{ url('admin') }}">
<i class="fas fa-cog"></i> &nbsp;
<span>{{ trans('general.admin-panel') }}</span>
<li class="nav-header">{{ trans('general.user-center') }}</li>
{{ include('shared.side-menu', {type: 'user'}) }}
<li class="nav-header">{{ trans('general.explore') }}</li>
{{ include('shared.side-menu', {type: 'explore'}) }}
{% if auth_user().admin %}
<li class="nav-header">{{ trans('general.manage') }}</li>
<li class="nav-item">
<a class="nav-link" href="{{ url('admin') }}">
<i class="nav-icon fas fa-cog"></i>
<p>{{ trans('general.admin-panel') }}</p>
</a>
</li>
{% endif %}
{% elseif scope == 'admin' %}
<li class="nav-header">{{ trans('general.admin-panel') }}</li>
{{ include('shared.side-menu', {type: 'admin'}) }}
<li class="nav-header">{{ trans('general.back') }}</li>
<li class="nav-item">
<a class="nav-link" href="{{ url('user') }}">
<i class="nav-icon fas fa-user"></i> &nbsp;
<p>{{ trans('general.user-center') }}</p>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url('skinlib') }}">
<i class="nav-icon fas fa-archive"></i> &nbsp;
<p>{{ trans('general.skinlib') }}</p>
</a>
</li>
{% endif %}
{% elseif scope == 'admin' %}
<li class="header">{{ trans('general.admin-panel') }}</li>
{{ include('shared.side-menu', {type: 'admin'}) }}
<li class="header">{{ trans('general.back') }}</li>
<li>
<a href="{{ url('user') }}">
<i class="fas fa-user"></i> &nbsp;
<span>{{ trans('general.user-center') }}</span>
</a>
</li>
<li>
<a href="{{ url('skinlib') }}">
<i class="fas fa-archive"></i> &nbsp;
<span>{{ trans('general.skinlib') }}</span>
</a>
</li>
{% endif %}
</ul>
</section>
</ul>
</nav>
</div>
</aside>

View File

@ -1,47 +1,31 @@
<li class="dropdown user user-menu">
<!-- Menu Toggle Button -->
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
{% if tiny_avatar %}
<img src="{{ tiny_avatar }}" class="user-image" alt="User Image">
{% else %}
<i class="fas fa-user"></i>
{% endif %}
<!-- hidden-xs hides the username on small devices so only the image appears. -->
<span class="hidden-xs nickname">{{ user.nickname ?? user.email }}</span>
<li class="nav-item dropdown user-menu">
<a href="#" class="nav-link" data-toggle="dropdown">
<img src="{{ avatar }}" class="user-image img-circle elevation-2" alt="User Image">
<span class="d-none d-md-inline d-sm-block">{{ user.nickname ?? user.email }}</span>
</a>
<ul class="dropdown-menu">
<li class="user-header">
<img src="{{ avatar }}" alt="User Image">
<p>{{ user.email }}</p>
</li>
<div class="dropdown-menu dropdown-menu-lg dropdown-menu-right">
<a class="dropdown-item" href="{{ url('user') }}">
{{ trans('general.user-center') }}
</a>
<a class="dropdown-item" href="{{ url('user/profile') }}">
{{ trans('general.profile') }}
</a>
<div class="dropdown-divider"></div>
{% if user.admin %}
<li class="user-body">
<div class="row">
<div class="col-xs-4 text-center">
<a href="{{ url('admin') }}">{{ trans('general.admin-panel') }}</a>
</div>
<div class="col-xs-4 text-center">
<a href="{{ url('admin/users') }}">{{ trans('general.user-manage') }}</a>
</div>
<div class="col-xs-4 text-center">
<a href="{{ url('admin/options') }}">{{ trans('general.options') }}</a>
</div>
</div>
</li>
<a class="dropdown-item" href="{{ url('admin') }}">
{{ trans('general.admin-panel') }}
</a>
<a class="dropdown-item" href="{{ url('admin/users') }}">
{{ trans('general.user-manage') }}
</a>
<a class="dropdown-item" href="{{ url('admin/reports') }}">
{{ trans('general.report-manage') }}
</a>
<div class="dropdown-divider"></div>
{% endif %}
<!-- Menu Footer-->
<li class="user-footer">
<div class="pull-left">
<a href="{{ url('user') }}" class="btn btn-default btn-flat">
{{ trans('general.user-center') }}
</a>
</div>
<div class="pull-right">
<button id="logout-button" class="btn btn-default btn-flat">
{{ trans('general.logout') }}
</button>
</div>
</li>
</ul>
<a class="dropdown-item" href="#" id="logout-button">
{{ trans('general.logout') }}
</a>
</div>
</li>

View File

@ -1,20 +1,16 @@
<div class="user-panel">
<div class="pull-left image">
<img src="{{ avatar }}" alt="User Image">
<div class="user-panel mt-3 mb-3 {{ badges|length > 0 ? 'pb-2' }}">
<div class="d-flex">
<div class="image">
<img src="{{ avatar }}" class="img-circle elevation-2" alt="User Image">
</div>
<div class="info">
<a class="d-block">{{ user.nickname ?? user.email }}</a>
</div>
</div>
<div class="pull-left info">
<p class="nickname">{{ user.nickname ?? user.email }}</p>
<i class="fas fa-circle text-success"></i> {{ role }}
{% if badges|length == 1 %}
<small class="label bg-{{ badges[0][1] }}">{{ badges[0][0] }}</small>
{% endif %}
</div>
</div>
{% if badges|length > 1 %}
<div class="user-panel" style="padding-top: 0">
<div class="mt-3 ml-2 mr-2 d-flex justify-content-between flex-wrap">
{% for badge in badges %}
<small class="label bg-{{ badge[1] }}">{{ badge[0] }}</small>
<span class="badge bg-{{ badge[1] }} mb-1">{{ badge[0] }}</span>
{% endfor %}
</div>
{% endif %}
</div>

View File

@ -5,71 +5,61 @@
<title>{% block title %}{% endblock %} - {{ site_name }}</title>
</head>
<body class="hold-transition {{ color_scheme }} layout-top-nav">
<body class="hold-transition layout-top-nav">
<div class="wrapper">
<header class="main-header">
<nav class="navbar navbar-static-top">
<div class="container">
<div class="navbar-header">
<a href="{{ url('/') }}" class="navbar-brand">{{ site_name }}</a>
<button
type="button"
class="navbar-toggle collapsed"
data-toggle="collapse"
data-target="#navbar-collapse"
>
<i class="fas fa-bars"></i>
</button>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse pull-left" id="navbar-collapse">
<ul class="nav navbar-nav">
<li class="active">
<a href="{{ url('skinlib') }}">{{ trans('general.skinlib') }}</a>
</li>
{% if auth_check() %}
<li>
<a href="{{ url('user/closet') }}">
{{ trans('general.my-closet') }}
</a>
</li>
{% endif %}
</ul>
</div>
<!-- Navbar Right Menu -->
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
{% if auth_check() %}
<li>
<a href="{{ url('skinlib/upload') }}">
<i class="fas fa-upload" aria-hidden="true"></i>&nbsp;
<span class="description-text">
{{ trans('skinlib.general.upload-new-skin') }}
</span>
</a>
</li>
{{ include('shared.notifications') }}
{% endif %}
{{ include('shared.languages') }}
{% if auth_check() %}
{{ include('shared.user-menu') }}
{% else %}
<li class="dropdown user user-menu">
<a href="{{ url('auth/login') }}">
<i class="fas fa-user"></i>
<span class="hidden-xs nickname">
{{ trans('general.anonymous') }}
</span>
</a>
</li>
{% endif %}
</ul>
</div>
<nav class="navbar navbar-expand navbar-light navbar-white ml-0">
<div class="container">
<div class="navbar-header">
<a href="{{ url('/') }}" class="navbar-brand">{{ site_name }}</a>
</div>
</nav>
</header>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="nav-item active">
<a class="nav-link" href="{{ url('skinlib') }}">
{{ trans('general.skinlib') }}
</a>
</li>
{% if auth_check() %}
<li class="nav-item">
<a class="nav-link" href="{{ url('user/closet') }}">
{{ trans('general.my-closet') }}
</a>
</li>
{% endif %}
</ul>
</div>
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
{% if auth_check() %}
<li class="nav-item">
<a class="nav-link" href="{{ url('skinlib/upload') }}">
<i class="fas fa-upload" aria-hidden="true"></i>&nbsp;
<span class="d-none d-sm-inline">
{{ trans('skinlib.general.upload-new-skin') }}
</span>
</a>
</li>
{{ include('shared.notifications') }}
{% endif %}
{{ include('shared.languages') }}
{% if auth_check() %}
{{ include('shared.user-menu') }}
{% else %}
<li class="nav-item">
<a class="nav-link" href="{{ url('auth/login') }}">
<i class="fas fa-user"></i>
<span class="d-none d-sm-inline">
{{ trans('general.anonymous') }}
</span>
</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
{% block content %}{% endblock %}

View File

@ -5,27 +5,36 @@
{% block content %}
<div class="content-wrapper">
<div class="container">
<section class="content-header">
<h1>{{ trans('skinlib.show.title') }}</h1>
</section>
<div class="content-header">
<div class="container-fluid">
<div class="d-flex justify-content-between flex-wrap">
<div>
<h1 class="m-0 text-dark">{{ trans('skinlib.show.title') }}</h1>
</div>
<div>
<div class="breadcrumb"></div>
</div>
</div>
</div>
</div>
<section class="content">
<div class="row"></div>
<div class="container-fluid">
<div class="row"></div>
{% if comment_script %}
<div class="row">
<div class="col-md-12">
<div class="box box-default">
<div class="box-header with-border">
<h3 class="box-title">{{ trans('skinlib.show.comment') }}</h3>
{% if comment_script %}
<div class="container-fluid p-0">
<div class="card">
<div class="card-header">
<h3 class="card-title">{{ trans('skinlib.show.comment') }}</h3>
</div>
<div class="box-body">
<div class="card-body">
{{ comment_script|raw }}
</div>
</div>
</div>
</div>
{% endif %}
{% endif %}
</div>
</section>
</div>
</div>

View File

@ -5,10 +5,21 @@
{% block content %}
<div class="content-wrapper">
<div class="container">
<section class="content-header">
<h1>{{ block('title') }}</h1>
<div class="content-header">
<div class="container-fluid">
<div class="d-flex justify-content-between flex-wrap">
<div>
<h1 class="m-0 text-dark">{{ block('title') }}</h1>
</div>
<div>
<div class="breadcrumb"></div>
</div>
</div>
</div>
</div>
<section class="content">
<div class="container-fluid"></div>
</section>
<section class="content"></section>
</div>
</div>
{% endblock %}

View File

@ -5,16 +5,27 @@
<title>{% block title %}{% endblock %} - {{ site_name }}</title>
</head>
<body class="hold-transition {{ color_scheme }} sidebar-mini">
<body class="hold-transition sidebar-mini">
<div class="wrapper">
{{ include('shared.header') }}
{{ include('shared.sidebar', {scope: 'user'}) }}
<div class="content-wrapper">
<section class="content-header">
<h1>{{ block('title') }}</h1>
</section>
<div class="content-header">
<div class="container-fluid">
<div class="d-flex justify-content-between flex-wrap">
<div>
<h1 class="m-0 text-dark">{{ block('title') }}</h1>
</div>
<div>
<div class="breadcrumb"></div>
</div>
</div>
</div>
</div>
<section class="content">
{% block content %}{% endblock %}
<div class="container-fluid">
{% block content %}{% endblock %}
</div>
</section>
</div>
<footer class="main-footer">

View File

@ -3,6 +3,8 @@
{% block title %}{{ trans('user.player.bind.title') }}{% endblock %}
{% block content %}
<p class="login-box-msg">{{ trans('user.player.bind.title') }}</p>
<p class="login-box-msg">
<b>{{ trans('user.player.bind.title') }}</b>
</p>
<form></form>
{% endblock %}

View File

@ -5,24 +5,25 @@
{% block content %}
<div class="row">
<div class="col-md-7">
<div class="box" id="usage-box">
<div class="box-header with-border"></div>
<div class="box-body"></div>
<div class="box-footer"></div>
<div class="card" id="usage-box">
<div class="card-header"></div>
<div class="card-body"></div>
<div class="card-footer"></div>
</div>
</div>
<div class="col-md-5">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">{{ trans('user.announcement') }}</h3>
<div class="card card-primary card-outline">
<div class="card-header">
<h3 class="card-title">{{ trans('user.announcement') }}</h3>
{% if auth_user().admin %}
&nbsp;
<a href="{{ url('/admin/options') }}">
<i class="fas fa-edit"></i>
</a>
{% endif %}
</div>
<div class="box-body">
<div class="card-body">
{{ announcement|raw }}
</div>
</div>
@ -32,13 +33,13 @@
{% block before_foot %}
<div id="modal-score-instruction" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">{{ trans('user.score-intro.title') }}</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title">{{ trans('user.score-intro.title') }}</h4>
</div>
<div class="modal-body">
{{ score_intro|nl2br }}
@ -54,7 +55,7 @@
</div>
</div>
<div class="modal-footer">
<button class="el-button" data-dismiss="modal">{{ trans('general.close') }}</button>
<button class="btn btn-default" data-dismiss="modal">{{ trans('general.close') }}</button>
</div>
</div>
</div>

View File

@ -6,7 +6,7 @@
@yield('style')
</head>
<body class="hold-transition {{ option('color_scheme') }} sidebar-mini">
<body class="hold-transition sidebar-mini">
<div class="wrapper">
@include('shared.header')
@include('shared.sidebar', ['scope' => 'user'])

View File

@ -1,33 +1,31 @@
{% extends 'auth.base' %}
{% block title %}{{ trans('auth.oauth.authorization.title') }}{% endblock %}
{% block title %}
{{ trans('auth.oauth.authorization.title') }}
{% endblock %}
{% block content %}
<p class="login-box-msg">
{{ trans('auth.oauth.authorization.introduction', {name: client.name}) }}
</p>
<div class="row">
<div class="col-xs-6">
<form method="post" action="{{ route('passport.authorizations.approve') }}">
{{ csrf_field() }}
<input type="hidden" name="state" value="{{ request.state }}">
<input type="hidden" name="client_id" value="{{ client.id }}">
<button type="submit" class="btn btn-success btn-block btn-flat">
{{ trans('auth.oauth.authorization.button') }}
</button>
</form>
</div>
<p class="login-box-msg">
{{ trans('auth.oauth.authorization.introduction', {name: client.name}) }}
</p>
<div class="d-flex justify-content-between">
<form method="post" action="{{ route('passport.authorizations.approve') }}">
{{ csrf_field() }}
<input type="hidden" name="state" value="{{ request.state }}">
<input type="hidden" name="client_id" value="{{ client.id }}">
<button type="submit" class="btn btn-success btn-block pl-5 pr-5">
{{ trans('auth.oauth.authorization.button') }}
</button>
</form>
<div class="col-xs-6">
<form method="post" action="{{ route('passport.authorizations.deny') }}">
{{ csrf_field() }}
{{ method_field('DELETE') }}
<input type="hidden" name="state" value="{{ request.state }}">
<input type="hidden" name="client_id" value="{{ client.id }}">
<button class="btn btn-default btn-block btn-flat">
{{ trans('general.cancel') }}
</button>
</form>
</div>
</div>
<form method="post" action="{{ route('passport.authorizations.deny') }}">
{{ csrf_field() }}
{{ method_field('DELETE') }}
<input type="hidden" name="state" value="{{ request.state }}">
<input type="hidden" name="client_id" value="{{ client.id }}">
<button class="btn btn-default btn-block pl-5 pr-5">
{{ trans('general.cancel') }}
</button>
</form>
</div>
{% endblock %}

View File

@ -30,7 +30,7 @@ class SideMenuComposerTest extends TestCase
$this->actingAs($user);
$crawler = new Crawler($this->get('/user/oauth/manage')->getContent());
$this->assertCount(1, $crawler->filter('aside .treeview'));
$this->assertCount(1, $crawler->filter('aside .nav-treeview'));
$this->assertCount(2, $crawler->filter('aside .active'));
}

View File

@ -7,16 +7,6 @@ use App\Models\User;
class UserMenuComposerTest extends TestCase
{
public function testAvatar()
{
$user = factory(User::class)->make();
$this->actingAs($user)
->get('/user')
->assertSee(
url('avatar/128/'.base64_encode($user->email).'.png?tid='.$user->avatar)
);
}
public function testTinyAvatar()
{
$user = factory(User::class)->make();
$this->actingAs($user)
@ -31,7 +21,7 @@ class UserMenuComposerTest extends TestCase
);
$this->actingAs($user)
->get('/user')
->assertDontSee(
->assertSee(
url('avatar/25/'.base64_encode($user->email).'.png?tid='.$user->avatar)
);
}

Some files were not shown because too many files have changed in this diff Show More