mirror of
https://github.com/Bubka/2FAuth.git
synced 2025-08-13 23:38:32 +02:00
Add a Light theme and a theme detection/selection feature
This commit is contained in:
27
resources/js/app.js
vendored
27
resources/js/app.js
vendored
@ -18,7 +18,32 @@ const app = new Vue({
|
||||
appSettings: window.appSettings,
|
||||
appConfig: window.appConfig,
|
||||
isDemoApp: window.isDemoApp,
|
||||
isTestingApp: window.isTestingApp
|
||||
isTestingApp: window.isTestingApp,
|
||||
prefersDarkScheme: window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
},
|
||||
|
||||
computed: {
|
||||
showDarkMode: function() {
|
||||
return this.appSettings.theme == 'dark' ||
|
||||
(this.appSettings.theme == 'system' && this.prefersDarkScheme)
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)')
|
||||
this.$nextTick(() => {
|
||||
this.mediaQueryList.addEventListener('change', this.setDarkScheme)
|
||||
})
|
||||
},
|
||||
|
||||
beforeDestroy () {
|
||||
this.mediaQueryList.removeEventListener('change', this.setDarkScheme)
|
||||
},
|
||||
|
||||
methods: {
|
||||
setDarkScheme ({ matches }) {
|
||||
this.prefersDarkScheme = matches
|
||||
}
|
||||
},
|
||||
i18n,
|
||||
router,
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<footer class="has-background-black-ter">
|
||||
<footer>
|
||||
<div class="columns is-gapless" v-if="showButtons">
|
||||
<div class="column has-text-centered">
|
||||
<div class="field is-grouped">
|
||||
|
@ -26,14 +26,14 @@
|
||||
<div v-if="showRules" class="columns is-mobile is-size-7 mt-0">
|
||||
<div class="column is-one-third">
|
||||
<span class="has-text-weight-semibold">{{ $t("auth.forms.mandatory_rules") }}</span><br />
|
||||
<span class="is-underscored" :class="{'has-background-success-dark is-dot' : IsLongEnough}"></span>{{ $t('auth.forms.is_long_enough') }}<br/>
|
||||
<span class="is-underscored" :class="{'is-dot' : IsLongEnough}"></span>{{ $t('auth.forms.is_long_enough') }}<br/>
|
||||
</div>
|
||||
<div class="column">
|
||||
<span class="has-text-weight-semibold">{{ $t("auth.forms.optional_rules_you_should_follow") }}</span><br />
|
||||
<span class="is-underscored" :class="{'has-background-success-dark is-dot' : hasLowerCase}"></span>{{ $t('auth.forms.has_lower_case') }}<br/>
|
||||
<span class="is-underscored" :class="{'has-background-success-dark is-dot' : hasUpperCase}"></span>{{ $t('auth.forms.has_upper_case') }}<br/>
|
||||
<span class="is-underscored" :class="{'has-background-success-dark is-dot' : hasSpecialChar}"></span>{{ $t('auth.forms.has_special_char') }}<br/>
|
||||
<span class="is-underscored" :class="{'has-background-success-dark is-dot' : hasNumber}"></span>{{ $t('auth.forms.has_number') }}
|
||||
<span class="is-underscored" :class="{'is-dot' : hasLowerCase}"></span>{{ $t('auth.forms.has_lower_case') }}<br/>
|
||||
<span class="is-underscored" :class="{'is-dot' : hasUpperCase}"></span>{{ $t('auth.forms.has_upper_case') }}<br/>
|
||||
<span class="is-underscored" :class="{'is-dot' : hasSpecialChar}"></span>{{ $t('auth.forms.has_special_char') }}<br/>
|
||||
<span class="is-underscored" :class="{'is-dot' : hasNumber}"></span>{{ $t('auth.forms.has_number') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -5,12 +5,15 @@
|
||||
<button
|
||||
role="radio"
|
||||
type="button"
|
||||
class="button is-dark"
|
||||
class="button"
|
||||
:aria-checked="form[fieldName] === choice.value"
|
||||
:disabled="isDisabled"
|
||||
v-for="(choice, index) in choices"
|
||||
:key="index"
|
||||
:class="{ 'is-link' : form[fieldName] === choice.value }"
|
||||
:class="{
|
||||
'is-link' : form[fieldName] === choice.value,
|
||||
'is-dark' : $root.showDarkMode
|
||||
}"
|
||||
v-on:click.stop="setRadio(choice.value)"
|
||||
>
|
||||
<input
|
||||
|
@ -5,7 +5,7 @@
|
||||
<section class="section">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-three-quarters">
|
||||
<div class="box has-text-centered has-background-black-ter is-shadowless">
|
||||
<div class="modal-slot box has-text-centered is-shadowless">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
@ -14,7 +14,7 @@
|
||||
</div>
|
||||
<div v-if="this.showcloseButton" class="fullscreen-footer">
|
||||
<!-- Close button -->
|
||||
<button ref="closeModalButton" class="button is-dark is-rounded" @click.stop="closeModal">
|
||||
<button ref="closeModalButton" class="button is-rounded" :class="{'is-dark' : $root.showDarkMode}" @click.stop="closeModal">
|
||||
{{ $t('commons.close') }}
|
||||
</button>
|
||||
</div>
|
||||
|
@ -3,10 +3,10 @@
|
||||
<figure class="image is-64x64" :class="{ 'no-icon': !internal_icon }" style="display: inline-block">
|
||||
<img :src="$root.appConfig.subdirectory + '/storage/icons/' + internal_icon" v-if="internal_icon" :alt="$t('twofaccounts.icon_to_illustrate_the_account')">
|
||||
</figure>
|
||||
<p class="is-size-4 has-text-grey-light has-ellipsis">{{ internal_service }}</p>
|
||||
<p class="is-size-6 has-text-grey has-ellipsis">{{ internal_account }}</p>
|
||||
<p class="is-size-4 has-ellipsis" :class="$root.showDarkMode ? 'has-text-grey-light' : 'has-text-grey'">{{ internal_service }}</p>
|
||||
<p class="is-size-6 has-ellipsis" :class="$root.showDarkMode ? 'has-text-grey' : 'has-text-grey-light'">{{ internal_account }}</p>
|
||||
<p>
|
||||
<span role="log" ref="otp" tabindex="0" class="otp is-size-1 has-text-white is-clickable px-3" @click="copyOTP(internal_password)" @keyup.enter="copyOTP(internal_password)" :title="$t('commons.copy_to_clipboard')">
|
||||
<span role="log" ref="otp" tabindex="0" class="otp is-size-1 is-clickable px-3" :class="$root.showDarkMode ? 'has-text-white' : 'has-text-grey-dark'" @click="copyOTP(internal_password)" @keyup.enter="copyOTP(internal_password)" :title="$t('commons.copy_to_clipboard')">
|
||||
{{ displayedOtp }}
|
||||
</span>
|
||||
</p>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="options-header has-background-black-ter">
|
||||
<div class="options-header">
|
||||
<responsive-width-wrapper>
|
||||
<div class="tabs is-centered is-fullwidth">
|
||||
<ul>
|
||||
|
4
resources/js/mixins.js
vendored
4
resources/js/mixins.js
vendored
@ -97,6 +97,10 @@ Vue.mixin({
|
||||
// url
|
||||
// week
|
||||
},
|
||||
|
||||
setTheme(theme) {
|
||||
document.documentElement.dataset.theme = theme;
|
||||
}
|
||||
}
|
||||
|
||||
})
|
10
resources/js/packages/fontawesome.js
vendored
10
resources/js/packages/fontawesome.js
vendored
@ -38,7 +38,10 @@ import {
|
||||
faEyeSlash,
|
||||
faExternalLinkAlt,
|
||||
faCamera,
|
||||
faFileDownload
|
||||
faFileDownload,
|
||||
faSun,
|
||||
faMoon,
|
||||
faDesktop
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
import {
|
||||
@ -81,7 +84,10 @@ library.add(
|
||||
faEyeSlash,
|
||||
faExternalLinkAlt,
|
||||
faCamera,
|
||||
faFileDownload
|
||||
faFileDownload,
|
||||
faSun,
|
||||
faMoon,
|
||||
faDesktop
|
||||
);
|
||||
|
||||
Vue.component('font-awesome-icon', FontAwesomeIcon)
|
@ -2,10 +2,10 @@
|
||||
<responsive-width-wrapper>
|
||||
<h1 class="title has-text-grey-dark">{{ pagetitle }}</h1>
|
||||
<p class="block">
|
||||
<span class="has-text-white"><span class="is-size-5">2FAuth</span> v{{ appVersion }}</span><br />
|
||||
<span :class="$root.showDarkMode ? 'has-text-white':'has-text-black'"><span class="is-size-5">2FAuth</span> v{{ appVersion }}</span><br />
|
||||
{{ $t('commons.2fauth_teaser')}}
|
||||
</p>
|
||||
<img src="logo.svg" style="height: 32px" alt="2FAuth logo" />
|
||||
<img class="about-logo" src="logo.svg" alt="2FAuth logo" />
|
||||
<p class="block" :class="showUserOptions ? 'mb-5' : '' ">
|
||||
©Bubka <a class="is-size-7" href="https://github.com/Bubka/2FAuth/blob/master/LICENSE">AGPL-3.0 license</a>
|
||||
</p>
|
||||
@ -13,25 +13,25 @@
|
||||
{{ $t('commons.resources') }}
|
||||
</h2>
|
||||
<div class="buttons">
|
||||
<a class="button is-dark" href="https://github.com/Bubka/2FAuth" target="_blank">
|
||||
<a class="button" :class="{'is-dark' : $root.showDarkMode}" href="https://github.com/Bubka/2FAuth" target="_blank">
|
||||
<span class="icon is-small">
|
||||
<font-awesome-icon :icon="['fab', 'github-alt']" />
|
||||
</span>
|
||||
<span>Github</span>
|
||||
</a>
|
||||
<a class="button is-dark" href="https://docs.2fauth.app/" target="_blank">
|
||||
<a class="button" :class="{'is-dark' : $root.showDarkMode}" href="https://docs.2fauth.app/" target="_blank">
|
||||
<span class="icon is-small">
|
||||
<font-awesome-icon :icon="['fas', 'book']" />
|
||||
</span>
|
||||
<span>Docs</span>
|
||||
</a>
|
||||
<a class="button is-dark" href="https://demo.2fauth.app/" target="_blank">
|
||||
<a class="button" :class="{'is-dark' : $root.showDarkMode}" href="https://demo.2fauth.app/" target="_blank">
|
||||
<span class="icon is-small">
|
||||
<font-awesome-icon :icon="['fas', 'flask']" />
|
||||
</span>
|
||||
<span>Demo</span>
|
||||
</a>
|
||||
<a class="button is-dark" href="https://docs.2fauth.app/resources/rapidoc.html" target="_blank">
|
||||
<a class="button" :class="{'is-dark' : $root.showDarkMode}" href="https://docs.2fauth.app/resources/rapidoc.html" target="_blank">
|
||||
<span class="icon is-small">
|
||||
<font-awesome-icon :icon="['fas', 'code']" />
|
||||
</span>
|
||||
@ -51,7 +51,7 @@
|
||||
<h2 class="title is-5 has-text-grey-light">
|
||||
{{ $t('commons.environment') }}
|
||||
</h2>
|
||||
<div class="box has-background-black-bis is-family-monospace is-size-7">
|
||||
<div class="about-debug box is-family-monospace is-size-7">
|
||||
<button :aria-label="$t('commons.copy_to_clipboard')" class="button is-like-text is-pulled-right is-small is-text" v-clipboard="() => this.$refs.listInfos.innerText" v-clipboard:success="clipboardSuccessHandler">
|
||||
<font-awesome-icon :icon="['fas', 'copy']" />
|
||||
</button>
|
||||
@ -63,7 +63,7 @@
|
||||
<h2 class="title is-5 has-text-grey-light">
|
||||
{{ $t('settings.user_options') }}
|
||||
</h2>
|
||||
<div class="box has-background-black-bis is-family-monospace is-size-7">
|
||||
<div class="about-debug box is-family-monospace is-size-7">
|
||||
<button :aria-label="$t('commons.copy_to_clipboard')" class="button is-like-text is-pulled-right is-small is-text" v-clipboard="() => this.$refs.listUserOptions.innerText" v-clipboard:success="clipboardSuccessHandler">
|
||||
<font-awesome-icon :icon="['fas', 'copy']" />
|
||||
</button>
|
||||
@ -76,7 +76,7 @@
|
||||
<vue-footer :showButtons="true">
|
||||
<!-- close button -->
|
||||
<p class="control">
|
||||
<router-link :to="{ name: 'accounts', params: { toRefresh: true } }" role="button" :aria-label="$t('commons.close_the_x_page', {pagetitle: pagetitle})" class="button is-dark is-rounded">{{ $t('commons.close') }}</router-link>
|
||||
<router-link :to="{ name: 'accounts', params: { toRefresh: true } }" role="button" :aria-label="$t('commons.close_the_x_page', {pagetitle: pagetitle})" class="button is-rounded" :class="{'is-dark' : $root.showDarkMode}">{{ $t('commons.close') }}</router-link>
|
||||
</p>
|
||||
</vue-footer>
|
||||
</responsive-width-wrapper>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<div class="column is-one-third-tablet is-one-quarter-desktop is-one-quarter-widescreen is-one-quarter-fullhd">
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-full" v-for="group in groups" v-if="group.twofaccounts_count > 0" :key="group.id">
|
||||
<button class="button is-fullwidth is-dark has-text-light is-outlined" @click="setActiveGroup(group.id)">{{ group.name }}</button>
|
||||
<button class="button is-fullwidth" :class="{'is-dark has-text-light is-outlined':$root.showDarkMode}" @click="setActiveGroup(group.id)">{{ group.name }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns is-centered">
|
||||
@ -19,7 +19,7 @@
|
||||
<vue-footer :showButtons="true">
|
||||
<!-- Close Group switch button -->
|
||||
<p class="control">
|
||||
<button class="button is-dark is-rounded" @click="closeGroupSwitch()">{{ $t('commons.close') }}</button>
|
||||
<button class="button is-rounded" :class="{'is-dark' : $root.showDarkMode}" @click="closeGroupSwitch()">{{ $t('commons.close') }}</button>
|
||||
</p>
|
||||
</vue-footer>
|
||||
</div>
|
||||
@ -32,7 +32,7 @@
|
||||
<div class="column is-one-third-tablet is-one-quarter-desktop is-one-quarter-widescreen is-one-quarter-fullhd">
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-full" v-for="group in groups" :key="group.id">
|
||||
<button class="button is-fullwidth is-dark has-text-light is-outlined" :class="{ 'is-link' : moveAccountsTo === group.id}" @click="moveAccountsTo = group.id">
|
||||
<button class="button is-fullwidth" :class="{'is-link' : moveAccountsTo === group.id, 'is-dark has-text-light is-outlined':$root.showDarkMode}" @click="moveAccountsTo = group.id">
|
||||
<span v-if="group.id === 0" class="is-italic">
|
||||
{{ $t('groups.no_group') }}
|
||||
</span>
|
||||
@ -56,12 +56,12 @@
|
||||
</p>
|
||||
<!-- Cancel button -->
|
||||
<p class="control">
|
||||
<button class="button is-dark is-rounded" @click="showGroupSelector = false">{{ $t('commons.cancel') }}</button>
|
||||
<button class="button is-rounded" :class="{'is-dark' : $root.showDarkMode}" @click="showGroupSelector = false">{{ $t('commons.cancel') }}</button>
|
||||
</p>
|
||||
</vue-footer>
|
||||
</div>
|
||||
<!-- header -->
|
||||
<div class="header has-background-black-ter" v-if="this.showAccounts || this.showGroupSwitch">
|
||||
<div class="header" v-if="this.showAccounts || this.showGroupSwitch">
|
||||
<div class="columns is-gapless is-mobile is-centered">
|
||||
<div class="column is-three-quarters-mobile is-one-third-tablet is-one-quarter-desktop is-one-quarter-widescreen is-one-quarter-fullhd">
|
||||
<!-- search -->
|
||||
@ -79,19 +79,19 @@
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<!-- selected label -->
|
||||
<span class="mr-1">{{ selectedAccounts.length }} {{ $t('commons.selected') }}</span>
|
||||
<span class="has-text-grey mr-1">{{ selectedAccounts.length }} {{ $t('commons.selected') }}</span>
|
||||
<!-- deselect all -->
|
||||
<button @click="clearSelected" class="clear-selection delete mr-4" :style="{visibility: selectedAccounts.length > 0 ? 'visible' : 'hidden'}" :title="$t('commons.clear_selection')"></button>
|
||||
<!-- select all button -->
|
||||
<button @click="selectAll" class="button mr-5 has-line-height p-1 is-ghost has-background-black-ter has-text-grey" :title="$t('commons.select_all')">
|
||||
<button @click="selectAll" class="button mr-5 has-line-height p-1 is-ghost has-text-grey" :title="$t('commons.select_all')">
|
||||
<span>{{ $t('commons.all') }}</span>
|
||||
<font-awesome-icon class="ml-1" :icon="['fas', 'check-square']" />
|
||||
</button>
|
||||
<!-- sort asc/desc buttons -->
|
||||
<button @click="sortAsc" class="button has-line-height p-1 is-ghost has-background-black-ter has-text-grey" :title="$t('commons.sort_ascending')">
|
||||
<button @click="sortAsc" class="button has-line-height p-1 is-ghost has-text-grey" :title="$t('commons.sort_ascending')">
|
||||
<font-awesome-icon :icon="['fas', 'sort-alpha-down']" />
|
||||
</button>
|
||||
<button @click="sortDesc" class="button has-line-height p-1 is-ghost has-background-black-ter has-text-grey" :title="$t('commons.sort_descending')">
|
||||
<button @click="sortDesc" class="button has-line-height p-1 is-ghost has-text-grey" :title="$t('commons.sort_descending')">
|
||||
<font-awesome-icon :icon="['fas', 'sort-alpha-up']" />
|
||||
</button>
|
||||
</div>
|
||||
@ -101,13 +101,13 @@
|
||||
<div v-else class="has-text-centered">
|
||||
<div class="columns">
|
||||
<div class="column" v-if="!showGroupSwitch">
|
||||
<button :title="$t('groups.show_group_selector')" tabindex="1" class="button is-text is-like-text" @click.stop="toggleGroupSwitch">
|
||||
<button :title="$t('groups.show_group_selector')" tabindex="1" class="button is-text is-like-text" :class="{'has-text-grey' : !$root.showDarkMode}" @click.stop="toggleGroupSwitch">
|
||||
{{ activeGroupName }} ({{ filteredAccounts.length }})
|
||||
<font-awesome-icon :icon="['fas', 'caret-down']" />
|
||||
</button>
|
||||
</div>
|
||||
<div class="column" v-else>
|
||||
<button :title="$t('groups.hide_group_selector')" tabindex="1" class="button is-text is-like-text" @click.stop="toggleGroupSwitch">
|
||||
<button :title="$t('groups.hide_group_selector')" tabindex="1" class="button is-text is-like-text" :class="{'has-text-grey' : !$root.showDarkMode}" @click.stop="toggleGroupSwitch">
|
||||
{{ $t('groups.select_accounts_to_show') }}
|
||||
</button>
|
||||
</div>
|
||||
@ -131,12 +131,12 @@
|
||||
}" > -->
|
||||
<draggable v-model="filteredAccounts" @start="drag = true" @end="saveOrder" ghost-class="ghost" handle=".tfa-dots" animation="200" class="accounts">
|
||||
<transition-group class="columns is-multiline" :class="{ 'is-centered': $root.appSettings.displayMode === 'grid' }" type="transition" :name="!drag ? 'flip-list' : null">
|
||||
<div :class="[$root.appSettings.displayMode === 'grid' ? 'tfa-grid' : 'tfa-list']" class="column is-narrow has-text-white" v-for="account in filteredAccounts" :key="account.id">
|
||||
<div :class="[$root.appSettings.displayMode === 'grid' ? 'tfa-grid' : 'tfa-list']" class="column is-narrow" v-for="account in filteredAccounts" :key="account.id">
|
||||
<div class="tfa-container">
|
||||
<transition name="slideCheckbox">
|
||||
<div class="tfa-cell tfa-checkbox" v-if="editMode">
|
||||
<div class="field">
|
||||
<input class="is-checkradio is-small is-white" :id="'ckb_' + account.id" :value="account.id" type="checkbox" :name="'ckb_' + account.id" v-model="selectedAccounts">
|
||||
<input class="is-checkradio is-small" :class="$root.showDarkMode ? 'is-white':'is-info'" :id="'ckb_' + account.id" :value="account.id" type="checkbox" :name="'ckb_' + account.id" v-model="selectedAccounts">
|
||||
<label tabindex="0" :for="'ckb_' + account.id" v-on:keypress.space.prevent="selectAccount(account.id)"></label>
|
||||
</div>
|
||||
</div>
|
||||
@ -151,10 +151,10 @@
|
||||
<transition name="fadeInOut">
|
||||
<div class="tfa-cell tfa-edit has-text-grey" v-if="editMode">
|
||||
<!-- <div class="tags has-addons"> -->
|
||||
<router-link :to="{ name: 'editAccount', params: { twofaccountId: account.id }}" class="tag is-dark is-rounded mr-1">
|
||||
<router-link :to="{ name: 'editAccount', params: { twofaccountId: account.id }}" class="tag is-rounded mr-1" :class="$root.showDarkMode ? 'is-dark' : 'is-white'">
|
||||
{{ $t('commons.edit') }}
|
||||
</router-link>
|
||||
<router-link :to="{ name: 'showQRcode', params: { twofaccountId: account.id }}" class="tag is-dark is-rounded" :title="$t('twofaccounts.show_qrcode')">
|
||||
<router-link :to="{ name: 'showQRcode', params: { twofaccountId: account.id }}" class="tag is-rounded" :class="$root.showDarkMode ? 'is-dark' : 'is-white'" :title="$t('twofaccounts.show_qrcode')">
|
||||
<font-awesome-icon :icon="['fas', 'qrcode']" />
|
||||
</router-link>
|
||||
<!-- </div> -->
|
||||
@ -182,13 +182,13 @@
|
||||
</p>
|
||||
<!-- Manage button -->
|
||||
<p class="control" v-if="!editMode">
|
||||
<button class="button is-dark is-rounded" @click="setEditModeTo(true)">{{ $t('commons.manage') }}</button>
|
||||
<button class="button is-rounded" :class="{'is-dark' : $root.showDarkMode}" @click="setEditModeTo(true)">{{ $t('commons.manage') }}</button>
|
||||
</p>
|
||||
<!-- move button -->
|
||||
<p class="control" v-if="editMode">
|
||||
<button
|
||||
:disabled='selectedAccounts.length == 0' class="button is-outlined is-rounded"
|
||||
:class="selectedAccounts.length > 0 ? 'is-link' : 'is-dark'"
|
||||
:disabled='selectedAccounts.length == 0' class="button is-rounded"
|
||||
:class="[{'is-outlined': $root.showDarkMode||selectedAccounts.length == 0}, selectedAccounts.length == 0 ? 'is-dark': 'is-link']"
|
||||
@click="showGroupSelector = true"
|
||||
:title="$t('groups.move_selected_to_group')" >
|
||||
{{ $t('commons.move') }}
|
||||
@ -197,8 +197,8 @@
|
||||
<!-- delete button -->
|
||||
<p class="control" v-if="editMode">
|
||||
<button
|
||||
:disabled='selectedAccounts.length == 0' class="button is-outlined is-rounded"
|
||||
:class="selectedAccounts.length > 0 ? 'is-link' : 'is-dark'"
|
||||
:disabled='selectedAccounts.length == 0' class="button is-rounded"
|
||||
:class="[{'is-outlined': $root.showDarkMode||selectedAccounts.length == 0}, selectedAccounts.length == 0 ? 'is-dark': 'is-link']"
|
||||
@click="destroyAccounts" >
|
||||
{{ $t('commons.delete') }}
|
||||
</button>
|
||||
@ -206,8 +206,8 @@
|
||||
<!-- export button -->
|
||||
<p class="control" v-if="editMode">
|
||||
<button
|
||||
:disabled='selectedAccounts.length == 0' class="button is-outlined is-rounded"
|
||||
:class="selectedAccounts.length > 0 ? 'is-link' : 'is-dark'"
|
||||
:disabled='selectedAccounts.length == 0' class="button is-rounded"
|
||||
:class="[{'is-outlined': $root.showDarkMode||selectedAccounts.length == 0}, selectedAccounts.length == 0 ? 'is-dark': 'is-link']"
|
||||
@click="exportAccounts"
|
||||
:title="$t('twofaccounts.export_selected_to_json')" >
|
||||
{{ $t('commons.export') }}
|
||||
|
@ -5,13 +5,13 @@
|
||||
<section class="section">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-three-quarters">
|
||||
<div class="box has-text-centered has-background-black-ter is-shadowless">
|
||||
<div class="modal-slot box has-text-centered is-shadowless">
|
||||
<div v-if="errorText">
|
||||
<p class="block is-size-5">{{ $t('twofaccounts.stream.live_scan_cant_start') }}</p>
|
||||
<p class="has-text-light block">{{ $t('twofaccounts.stream.' + errorText + '.reason') }}</p>
|
||||
<p class="block" :class="{'has-text-light': $root.showDarkMode}">{{ $t('twofaccounts.stream.' + errorText + '.reason') }}</p>
|
||||
<p class="is-size-7">{{ $t('twofaccounts.stream.' + errorText + '.solution') }}</p>
|
||||
</div>
|
||||
<span v-else class="is-size-4 has-text-light">
|
||||
<span v-else class="is-size-4" :class="$root.showDarkMode ? 'has-text-light':'has-text-grey-dark'">
|
||||
<font-awesome-icon :icon="['fas', 'spinner']" size="2x" spin />
|
||||
</span>
|
||||
</div>
|
||||
|
@ -12,10 +12,10 @@
|
||||
</router-link>
|
||||
</div>
|
||||
<div v-if="groups.length > 0">
|
||||
<div v-for="group in groups" :key="group.id" class="group-item has-text-light is-size-5 is-size-6-mobile">
|
||||
<div v-for="group in groups" :key="group.id" class="group-item is-size-5 is-size-6-mobile">
|
||||
{{ group.name }}
|
||||
<!-- delete icon -->
|
||||
<button class="button tag is-dark is-pulled-right" @click="deleteGroup(group.id)" :title="$t('commons.delete')">
|
||||
<button class="button tag is-pulled-right" :class="$root.showDarkMode ? 'is-dark' : 'is-white'" @click="deleteGroup(group.id)" :title="$t('commons.delete')">
|
||||
{{ $t('commons.delete') }}
|
||||
</button>
|
||||
<!-- edit link -->
|
||||
@ -37,7 +37,7 @@
|
||||
<vue-footer :showButtons="true">
|
||||
<!-- close button -->
|
||||
<p class="control">
|
||||
<router-link :to="{ name: 'accounts', params: { toRefresh: true } }" class="button is-dark is-rounded">{{ $t('commons.close') }}</router-link>
|
||||
<router-link :to="{ name: 'accounts', params: { toRefresh: true } }" class="button is-rounded" :class="{'is-dark' : $root.showDarkMode}">{{ $t('commons.close') }}</router-link>
|
||||
</p>
|
||||
</vue-footer>
|
||||
</responsive-width-wrapper>
|
||||
|
@ -23,7 +23,7 @@
|
||||
</div>
|
||||
<!-- alternative methods -->
|
||||
<div class="column is-full">
|
||||
<div class="block has-text-light">{{ $t('twofaccounts.forms.alternative_methods') }}</div>
|
||||
<div class="block" :class="$root.showDarkMode ? 'has-text-light':'has-text-grey-dark'">{{ $t('twofaccounts.forms.alternative_methods') }}</div>
|
||||
<!-- upload a qr code -->
|
||||
<div class="block has-text-link" v-if="!$root.appSettings.useBasicQrcodeReader">
|
||||
<label role="button" tabindex="0" class="button is-link is-outlined is-rounded" ref="qrcodeInputLabel" @keyup.enter="$refs.qrcodeInputLabel.click()">
|
||||
@ -49,7 +49,7 @@
|
||||
<vue-footer :showButtons="true" >
|
||||
<!-- back button -->
|
||||
<p class="control" v-if="accountCount > 0">
|
||||
<router-link class="button is-dark is-rounded" :to="{ name: returnToView }" >
|
||||
<router-link class="button is-rounded" :class="{'is-dark' : $root.showDarkMode}" :to="{ name: returnToView }" >
|
||||
{{ $t('commons.back') }}
|
||||
</router-link>
|
||||
</p>
|
||||
|
@ -37,7 +37,7 @@
|
||||
<vue-footer :showButtons="true">
|
||||
<!-- Cancel button -->
|
||||
<p class="control">
|
||||
<button class="button is-dark is-rounded" @click.stop="exitSettings">
|
||||
<button class="button is-rounded" :class="{'is-dark' : $root.showDarkMode}" @click.stop="exitSettings">
|
||||
{{ $t('commons.close') }}
|
||||
</button>
|
||||
</p>
|
||||
|
@ -14,12 +14,12 @@
|
||||
</a>
|
||||
</div>
|
||||
<div v-if="tokens.length > 0">
|
||||
<div v-for="token in tokens" :key="token.id" class="group-item has-text-light is-size-5 is-size-6-mobile">
|
||||
<div v-for="token in tokens" :key="token.id" class="group-item is-size-5 is-size-6-mobile">
|
||||
<font-awesome-icon v-if="token.value" class="has-text-success" :icon="['fas', 'check']" /> {{ token.name }}
|
||||
<!-- revoke link -->
|
||||
<div class="tags is-pulled-right">
|
||||
<button v-if="token.value" class="button tag" v-clipboard="() => token.value" v-clipboard:success="clipboardSuccessHandler">{{ $t('commons.copy') }}</button>
|
||||
<button class="button tag is-dark " @click="revokeToken(token.id)" :title="$t('settings.revoke')">{{ $t('settings.revoke') }}</button>
|
||||
<button v-if="token.value" class="button tag" :class="{'is-link': !$root.showDarkMode}" v-clipboard="() => token.value" v-clipboard:success="clipboardSuccessHandler">{{ $t('commons.copy') }}</button>
|
||||
<button class="button tag" :class="$root.showDarkMode ? 'is-dark':'is-white'" @click="revokeToken(token.id)" :title="$t('settings.revoke')">{{ $t('settings.revoke') }}</button>
|
||||
</div>
|
||||
<!-- edit link -->
|
||||
<!-- <router-link :to="{ name: 'settings.oauth.editPAT' }" class="has-text-grey pl-1" :title="$t('commons.edit')">
|
||||
@ -47,7 +47,7 @@
|
||||
<vue-footer :showButtons="true">
|
||||
<!-- close button -->
|
||||
<p class="control">
|
||||
<router-link :to="{ name: 'accounts', params: { toRefresh: false } }" class="button is-dark is-rounded" tabindex="0">{{ $t('commons.close') }}</router-link>
|
||||
<router-link :to="{ name: 'accounts', params: { toRefresh: false } }" class="button is-rounded" :class="{'is-dark' : $root.showDarkMode}" tabindex="0">{{ $t('commons.close') }}</router-link>
|
||||
</p>
|
||||
</vue-footer>
|
||||
</form-wrapper>
|
||||
|
@ -20,6 +20,8 @@
|
||||
</div>
|
||||
<!-- display mode -->
|
||||
<form-toggle v-on:displayMode="saveSetting('displayMode', $event)" :choices="layouts" :form="form" fieldName="displayMode" :label="$t('settings.forms.display_mode.label')" :help="$t('settings.forms.display_mode.help')" />
|
||||
<!-- theme -->
|
||||
<form-toggle v-on:theme="saveSetting('theme', $event)" :choices="themes" :form="form" fieldName="theme" :label="$t('settings.forms.theme.label')" :help="$t('settings.forms.theme.help')" />
|
||||
<!-- show icon -->
|
||||
<form-checkbox v-on:showAccountsIcons="saveSetting('showAccountsIcons', $event)" :form="form" fieldName="showAccountsIcons" :label="$t('settings.forms.show_accounts_icons.label')" :help="$t('settings.forms.show_accounts_icons.help')" />
|
||||
<!-- Official icons -->
|
||||
@ -56,7 +58,7 @@
|
||||
<vue-footer :showButtons="true">
|
||||
<!-- Cancel button -->
|
||||
<p class="control">
|
||||
<button class="button is-dark is-rounded" @click.stop="exitSettings">
|
||||
<button class="button is-rounded" :class="{'is-dark' : $root.showDarkMode}" @click.stop="exitSettings">
|
||||
{{ $t('commons.close') }}
|
||||
</button>
|
||||
</p>
|
||||
@ -104,11 +106,17 @@
|
||||
rememberActiveGroup: true,
|
||||
getOfficialIcons: null,
|
||||
checkForUpdate: null,
|
||||
theme: 'dark',
|
||||
}),
|
||||
layouts: [
|
||||
{ text: this.$t('settings.forms.grid'), value: 'grid', icon: 'th' },
|
||||
{ text: this.$t('settings.forms.list'), value: 'list', icon: 'list' },
|
||||
],
|
||||
themes: [
|
||||
{ text: this.$t('settings.forms.light'), value: 'light', icon: 'sun' },
|
||||
{ text: this.$t('settings.forms.dark'), value: 'dark', icon: 'moon' },
|
||||
{ text: this.$t('settings.forms.automatic'), value: 'system', icon: 'desktop' },
|
||||
],
|
||||
kickUserAfters: [
|
||||
{ text: this.$t('settings.forms.never'), value: '0' },
|
||||
{ text: this.$t('settings.forms.on_otp_copy'), value: '-1' },
|
||||
@ -199,6 +207,10 @@
|
||||
}
|
||||
else {
|
||||
this.$root.appSettings[response.data.key] = response.data.value
|
||||
|
||||
if(settingName === 'theme') {
|
||||
this.setTheme(response.data.value)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
@ -15,10 +15,10 @@
|
||||
</div>
|
||||
<!-- credentials list -->
|
||||
<div v-if="credentials.length > 0" class="field">
|
||||
<div v-for="credential in credentials" :key="credential.id" class="group-item has-text-light is-size-5 is-size-6-mobile">
|
||||
<div v-for="credential in credentials" :key="credential.id" class="group-item is-size-5 is-size-6-mobile">
|
||||
{{ displayName(credential) }}
|
||||
<!-- revoke link -->
|
||||
<button class="button tag is-dark is-pulled-right" @click="revokeCredential(credential.id)" :title="$t('settings.revoke')">
|
||||
<button class="button tag is-pulled-right" :class="$root.showDarkMode ? 'is-dark':'is-white'" @click="revokeCredential(credential.id)" :title="$t('settings.revoke')">
|
||||
{{ $t('settings.revoke') }}
|
||||
</button>
|
||||
<!-- edit link -->
|
||||
@ -49,7 +49,7 @@
|
||||
<vue-footer :showButtons="true">
|
||||
<!-- close button -->
|
||||
<p class="control">
|
||||
<router-link :to="{ name: 'accounts', params: { toRefresh: false } }" class="button is-dark is-rounded">{{ $t('commons.close') }}</router-link>
|
||||
<router-link :to="{ name: 'accounts', params: { toRefresh: false } }" class="button is-rounded" :class="{'is-dark' : $root.showDarkMode}">{{ $t('commons.close') }}</router-link>
|
||||
</p>
|
||||
</vue-footer>
|
||||
</form-wrapper>
|
||||
|
@ -66,7 +66,7 @@
|
||||
<div class="field is-grouped">
|
||||
<!-- i'm lucky button -->
|
||||
<div class="control" v-if="$root.appSettings.getOfficialIcons">
|
||||
<v-button @click="fetchLogo" :color="'is-dark'" :nativeType="'button'" :isDisabled="form.service.length < 1">
|
||||
<v-button @click="fetchLogo" :color="$root.showDarkMode ? 'is-dark' : ''" :nativeType="'button'" :isDisabled="form.service.length < 1">
|
||||
<span class="icon is-small">
|
||||
<font-awesome-icon :icon="['fas', 'globe']" />
|
||||
</span>
|
||||
@ -75,7 +75,7 @@
|
||||
</div>
|
||||
<!-- upload button -->
|
||||
<div class="control">
|
||||
<div role="button" tabindex="0" class="file is-dark" @keyup.enter="$refs.iconInputLabel.click()">
|
||||
<div role="button" tabindex="0" class="file" :class="$root.showDarkMode ? 'is-dark' : 'is-white'" @keyup.enter="$refs.iconInputLabel.click()">
|
||||
<label class="file-label" ref="iconInputLabel">
|
||||
<input aria-hidden="true" tabindex="-1" class="file-input" type="file" accept="image/*" v-on:change="uploadIcon" ref="iconInput">
|
||||
<span class="file-cta">
|
||||
@ -85,7 +85,7 @@
|
||||
<span class="file-label">{{ $t('twofaccounts.forms.choose_image') }}</span>
|
||||
</span>
|
||||
</label>
|
||||
<span class="tag is-black is-large" v-if="tempIcon">
|
||||
<span class="tag is-large" :class="$root.showDarkMode ? 'is-dark' : 'is-white'" v-if="tempIcon">
|
||||
<img class="icon-preview" :src="$root.appConfig.subdirectory + '/storage/icons/' + tempIcon" :alt="$t('twofaccounts.icon_to_illustrate_the_account')">
|
||||
<button class="clear-selection delete is-small" @click.prevent="deleteIcon" :aria-label="$t('twofaccounts.remove_icon')"></button>
|
||||
</span>
|
||||
@ -149,7 +149,7 @@
|
||||
<div class="block">
|
||||
{{ $t('errors.data_of_qrcode_is_not_valid_URI') }}
|
||||
</div>
|
||||
<div class="block has-text-light mb-6" v-html="uri"></div>
|
||||
<div class="block mb-6" :class="$root.showDarkMode ? 'has-text-light':'has-text-grey-dark'" v-html="uri"></div>
|
||||
<!-- Copy to clipboard -->
|
||||
<div class="block has-text-link">
|
||||
<button class="button is-link is-outlined is-rounded" v-clipboard="() => uri" v-clipboard:success="clipboardSuccessHandler">
|
||||
|
@ -10,7 +10,7 @@
|
||||
<div class="field is-grouped">
|
||||
<!-- i'm lucky button -->
|
||||
<div class="control" v-if="$root.appSettings.getOfficialIcons">
|
||||
<v-button @click="fetchLogo" :color="'is-dark'" :nativeType="'button'" :isDisabled="form.service.length < 3">
|
||||
<v-button @click="fetchLogo" :color="$root.showDarkMode ? 'is-dark' : ''" :nativeType="'button'" :isDisabled="form.service.length < 3">
|
||||
<span class="icon is-small">
|
||||
<font-awesome-icon :icon="['fas', 'globe']" />
|
||||
</span>
|
||||
@ -19,7 +19,7 @@
|
||||
</div>
|
||||
<!-- upload button -->
|
||||
<div class="control">
|
||||
<div role="button" tabindex="0" class="file is-dark" @keyup.enter="$refs.iconInputLabel.click()">
|
||||
<div role="button" tabindex="0" class="file" :class="$root.showDarkMode ? 'is-dark' : 'is-white'" @keyup.enter="$refs.iconInputLabel.click()">
|
||||
<label class="file-label" ref="iconInputLabel">
|
||||
<input aria-hidden="true" tabindex="-1" class="file-input" type="file" accept="image/*" v-on:change="uploadIcon" ref="iconInput">
|
||||
<span class="file-cta">
|
||||
@ -29,7 +29,7 @@
|
||||
<span class="file-label">{{ $t('twofaccounts.forms.choose_image') }}</span>
|
||||
</span>
|
||||
</label>
|
||||
<span class="tag is-black is-large" v-if="tempIcon">
|
||||
<span class="tag is-large" :class="$root.showDarkMode ? 'is-dark' : 'is-white'" v-if="tempIcon">
|
||||
<img class="icon-preview" :src="$root.appConfig.subdirectory + '/storage/icons/' + tempIcon" :alt="$t('twofaccounts.icon_to_illustrate_the_account')">
|
||||
<button class="clear-selection delete is-small" @click.prevent="deleteIcon" :aria-label="$t('twofaccounts.remove_icon')"></button>
|
||||
</span>
|
||||
@ -50,14 +50,14 @@
|
||||
<input :id="this.inputId('text','secret')" class="input" type="text" v-model="form.secret" :disabled="secretIsLocked">
|
||||
</p>
|
||||
<p class="control" v-if="secretIsLocked">
|
||||
<button type="button" class="button is-dark field-lock" @click.stop="secretIsLocked = false" :title="$t('twofaccounts.forms.unlock.title')">
|
||||
<button type="button" class="button field-lock" :class="{'is-dark' : $root.showDarkMode}" @click.stop="secretIsLocked = false" :title="$t('twofaccounts.forms.unlock.title')">
|
||||
<span class="icon">
|
||||
<font-awesome-icon :icon="['fas', 'lock']" />
|
||||
</span>
|
||||
</button>
|
||||
</p>
|
||||
<p class="control" v-else>
|
||||
<button type="button" class="button is-dark field-unlock" @click.stop="secretIsLocked = true" :title="$t('twofaccounts.forms.lock.title')">
|
||||
<button type="button" class="button field-unlock" :class="{'is-dark' : $root.showDarkMode}" @click.stop="secretIsLocked = true" :title="$t('twofaccounts.forms.lock.title')">
|
||||
<span class="icon has-text-danger">
|
||||
<font-awesome-icon :icon="['fas', 'lock-open']" />
|
||||
</span>
|
||||
@ -89,14 +89,14 @@
|
||||
<input class="input" type="text" placeholder="" v-model="form.counter" :disabled="counterIsLocked" />
|
||||
</div>
|
||||
<div class="control" v-if="counterIsLocked">
|
||||
<button type="button" class="button is-dark field-lock" @click="counterIsLocked = false" :title="$t('twofaccounts.forms.unlock.title')">
|
||||
<button type="button" class="button field-lock" :class="{'is-dark' : $root.showDarkMode}" @click="counterIsLocked = false" :title="$t('twofaccounts.forms.unlock.title')">
|
||||
<span class="icon">
|
||||
<font-awesome-icon :icon="['fas', 'lock']" />
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="control" v-else>
|
||||
<button type="button" class="button is-dark field-unlock" @click="counterIsLocked = true" :title="$t('twofaccounts.forms.lock.title')">
|
||||
<button type="button" class="button field-unlock" :class="{'is-dark' : $root.showDarkMode}" @click="counterIsLocked = true" :title="$t('twofaccounts.forms.lock.title')">
|
||||
<span class="icon has-text-danger">
|
||||
<font-awesome-icon :icon="['fas', 'lock-open']" />
|
||||
</span>
|
||||
|
@ -39,43 +39,19 @@
|
||||
<p class="help">{{ $t('twofaccounts.import.supported_formats_for_file_upload') }}</p>
|
||||
</div>
|
||||
<!-- Supported migration resources -->
|
||||
<h5 class="title is-5 mb-3 has-text-grey-dark">{{ $t('twofaccounts.import.supported_migration_formats') }}</h5>
|
||||
<h5 class="title is-6 mb-3 has-text-grey-dark">{{ $t('twofaccounts.import.supported_migration_formats') }}</h5>
|
||||
<div class="field is-grouped is-grouped-multiline pt-0">
|
||||
<div class="control">
|
||||
<div v-for="(source, index) in supportedSources" :key="index" class="control">
|
||||
<div class="tags has-addons">
|
||||
<span class="tag is-dark">2FAuth</span>
|
||||
<span class="tag is-black">JSON</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control">
|
||||
<div class="tags has-addons">
|
||||
<span class="tag is-dark">Google Auth</span>
|
||||
<span class="tag is-black">{{ $t('twofaccounts.import.qr_code') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control">
|
||||
<div class="tags has-addons">
|
||||
<span class="tag is-dark">Aegis Auth</span>
|
||||
<span class="tag is-black">JSON</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control">
|
||||
<div class="tags has-addons">
|
||||
<span class="tag is-dark">Aegis Auth</span>
|
||||
<span class="tag is-black">{{ $t('twofaccounts.import.plain_text') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control">
|
||||
<div class="tags has-addons">
|
||||
<span class="tag is-dark">2FAS Auth</span>
|
||||
<span class="tag is-black">JSON</span>
|
||||
<span class="tag" :class="$root.showDarkMode ? 'is-dark' : 'is-white'">{{ source.app }}</span>
|
||||
<span class="tag" :class="$root.showDarkMode ? 'is-black' : 'has-background-grey-lighter has-text-black'">{{ source.format }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="is-size-7" v-html="$t('twofaccounts.import.do_not_set_password_or_encryption')"></span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div v-for="(account, index) in exportedAccounts" :key="account.name" class="group-item has-text-light is-size-5 is-size-6-mobile">
|
||||
<div v-for="(account, index) in exportedAccounts" :key="account.name" class="group-item is-size-5 is-size-6-mobile">
|
||||
<div class="is-flex is-justify-content-space-between">
|
||||
<!-- Account name -->
|
||||
<div v-if="account.id > -2 && account.imported !== 0" class="is-flex-grow-1 has-ellipsis is-clickable" @click="previewAccount(index)" :title="$t('twofaccounts.import.generate_a_test_password')">
|
||||
@ -86,7 +62,7 @@
|
||||
<!-- buttons -->
|
||||
<div v-if="account.imported === -1" class="tags is-flex-wrap-nowrap">
|
||||
<!-- discard button -->
|
||||
<button class="button tag is-dark has-text-grey-light" @click="discardAccount(index)" :title="$t('twofaccounts.import.discard_this_account')">
|
||||
<button class="button tag" :class="{'is-dark has-text-grey-light' : $root.showDarkMode}" @click="discardAccount(index)" :title="$t('twofaccounts.import.discard_this_account')">
|
||||
<font-awesome-icon :icon="['fas', 'trash']" />
|
||||
</button>
|
||||
<!-- import button -->
|
||||
@ -148,7 +124,7 @@
|
||||
</p>
|
||||
<!-- close button -->
|
||||
<p class="control">
|
||||
<router-link :to="{ name: 'accounts', params: { toRefresh: true } }" class="button is-dark is-rounded" v-html="importableCount > 0 ? $t('commons.cancel') : $t('commons.close')"></router-link>
|
||||
<router-link :to="{ name: 'accounts', params: { toRefresh: true } }" class="button is-rounded" :class="{'is-dark' : $root.showDarkMode}" v-html="importableCount > 0 ? $t('commons.cancel') : $t('commons.close')"></router-link>
|
||||
</p>
|
||||
</vue-footer>
|
||||
</responsive-width-wrapper>
|
||||
@ -184,6 +160,13 @@
|
||||
}),
|
||||
uploadForm: new Form(),
|
||||
ShowTwofaccountInModal : false,
|
||||
supportedSources: [
|
||||
{app: '2FAuth', format: 'JSON'},
|
||||
{app: 'Google Auth', format: this.$t('twofaccounts.import.qr_code')},
|
||||
{app: 'Aegis Auth', format: 'JSON'},
|
||||
{app: 'Aegis Auth', format: this.$t('twofaccounts.import.plain_text')},
|
||||
{app: '2FAS auth', format: 'JSON'},
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
</div>
|
||||
<div class="fullscreen-footer">
|
||||
<!-- Close button -->
|
||||
<button class="button is-dark is-rounded" @click.stop="$router.push({name: 'accounts', params: {initialEditMode: true}});">
|
||||
<button class="button is-rounded" :class="{'is-dark' : $root.showDarkMode}" @click.stop="$router.push({name: 'accounts', params: {initialEditMode: true}});">
|
||||
{{ $t('commons.close') }}
|
||||
</button>
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user