mirror of
https://github.com/Bubka/2FAuth.git
synced 2025-03-30 09:56:05 +02:00
Fix some accessibility issues
This commit is contained in:
parent
4511df5764
commit
3fcc2b906b
@ -7,7 +7,7 @@
|
||||
<div v-if="this.$root.isTestingApp" class="demo has-background-warning has-text-centered is-size-7-mobile">
|
||||
{{ $t('commons.testing_do_not_post_sensitive_data') }}
|
||||
</div>
|
||||
<notifications id="vueNotification" width="100%" position="top" :duration="4000" :speed="0" :max="1" classes="notification is-radiusless" />
|
||||
<notifications id="vueNotification" role="alert" width="100%" position="top" :duration="4000" :speed="0" :max="1" classes="notification is-radiusless" />
|
||||
<main class="main-section">
|
||||
<router-view></router-view>
|
||||
</main>
|
||||
|
@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<p :id="'valError' + field[0].toUpperCase() + field.toLowerCase().slice(1)" class="help is-danger" v-if="form.errors.has(field)" v-html="form.errors.get(field)" />
|
||||
<div role="alert">
|
||||
<p :id="'valError' + field[0].toUpperCase() + field.toLowerCase().slice(1)" class="help is-danger" v-if="form.errors.has(field)" v-html="form.errors.get(field)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -5,7 +5,11 @@
|
||||
</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 tabindex="0" class="is-size-1 has-text-white is-clickable" :title="$t('commons.copy_to_clipboard')" v-clipboard="() => internal_password.replace(/ /g, '')" v-clipboard:success="clipboardSuccessHandler">{{ displayedOtp }}</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')">
|
||||
{{ displayedOtp }}
|
||||
</span>
|
||||
</p>
|
||||
<ul class="dots" v-show="isTimeBased(internal_otp_type)">
|
||||
<li v-for="n in 10" :key="n"></li>
|
||||
</ul>
|
||||
@ -70,8 +74,34 @@
|
||||
this.show()
|
||||
},
|
||||
|
||||
// created() {
|
||||
// },
|
||||
|
||||
methods: {
|
||||
|
||||
copyOTP (otp) {
|
||||
// see https://web.dev/async-clipboard/ for futur Clipboard API usage.
|
||||
// The API should allow to copy the password on each trip without user interaction.
|
||||
|
||||
// For now too many browsers don't support the clipboard-write permission
|
||||
// (see https://developer.mozilla.org/en-US/docs/Web/API/Permissions#browser_support)
|
||||
|
||||
const rawOTP = otp.replace(/ /g, '')
|
||||
const success = this.$clipboard(rawOTP)
|
||||
|
||||
if (success == true) {
|
||||
if(this.$root.appSettings.kickUserAfter == -1) {
|
||||
this.appLogout()
|
||||
}
|
||||
else if(this.$root.appSettings.closeOtpOnCopy) {
|
||||
this.$parent.isActive = false
|
||||
this.clearOTP()
|
||||
}
|
||||
|
||||
this.$notify({ type: 'is-success', text: this.$t('commons.copied_to_clipboard') })
|
||||
}
|
||||
},
|
||||
|
||||
isTimeBased: function(otp_type) {
|
||||
return (otp_type === 'totp' || otp_type === 'steamtotp')
|
||||
},
|
||||
@ -133,7 +163,7 @@
|
||||
else this.$router.push({ name: 'genericError', params: { err: this.$t('errors.not_a_supported_otp_type') } });
|
||||
|
||||
this.$parent.isActive = true
|
||||
this.$parent.$refs.closeModalButton.focus()
|
||||
this.focusOnOTP()
|
||||
}
|
||||
catch(error) {
|
||||
this.clearOTP()
|
||||
@ -181,7 +211,7 @@
|
||||
|
||||
await this.axios(request).then(response => {
|
||||
if(this.$root.appSettings.copyOtpOnDisplay) {
|
||||
this.copyAndNotify(response.data.password)
|
||||
this.copyOTP(response.data.password)
|
||||
}
|
||||
password = response.data
|
||||
})
|
||||
@ -319,35 +349,11 @@
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
clipboardSuccessHandler ({ value, event }) {
|
||||
|
||||
if(this.$root.appSettings.kickUserAfter == -1) {
|
||||
this.appLogout()
|
||||
}
|
||||
else if(this.$root.appSettings.closeOtpOnCopy) {
|
||||
this.$parent.isActive = false
|
||||
this.clearOTP()
|
||||
}
|
||||
|
||||
this.$notify({ type: 'is-success', text: this.$t('commons.copied_to_clipboard') })
|
||||
},
|
||||
|
||||
|
||||
clipboardErrorHandler ({ value, event }) {
|
||||
console.log('error', value)
|
||||
},
|
||||
|
||||
copyAndNotify (strToCopy) {
|
||||
// see https://web.dev/async-clipboard/ for futur Clipboard API usage.
|
||||
// The API should allow to copy the password on each trip without user interaction.
|
||||
|
||||
// For now too many browsers don't support the clipboard-write permission
|
||||
// (see https://developer.mozilla.org/en-US/docs/Web/API/Permissions#browser_support)
|
||||
|
||||
this.$clipboard(strToCopy)
|
||||
this.$notify({ type: 'is-success', text: this.$t('commons.copied_to_clipboard') })
|
||||
},
|
||||
focusOnOTP() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.otp.focus()
|
||||
})
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<responsive-width-wrapper>
|
||||
<h1 class="title has-text-grey-dark">{{ $t('commons.about') }}</h1>
|
||||
<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 />
|
||||
{{ $t('commons.2fauth_teaser')}}
|
||||
@ -13,25 +13,25 @@
|
||||
{{ $t('commons.resources') }}
|
||||
</h2>
|
||||
<div class="buttons">
|
||||
<a class="button is-dark" href="https://github.com/Bubka/2FAuth">
|
||||
<a class="button is-dark" 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/">
|
||||
<a class="button is-dark" 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/">
|
||||
<a class="button is-dark" 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">
|
||||
<a class="button is-dark" href="https://docs.2fauth.app/resources/rapidoc.html" target="_blank">
|
||||
<span class="icon is-small">
|
||||
<font-awesome-icon :icon="['fas', 'code']" />
|
||||
</span>
|
||||
@ -52,7 +52,7 @@
|
||||
{{ $t('commons.environment') }}
|
||||
</h2>
|
||||
<div class="box has-background-black-bis is-family-monospace is-size-7">
|
||||
<button class="button is-like-text is-pulled-right is-small is-text" v-clipboard="() => this.$refs.listInfos.innerText" v-clipboard:success="clipboardSuccessHandler">
|
||||
<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>
|
||||
<ul ref="listInfos">
|
||||
@ -64,7 +64,7 @@
|
||||
{{ $t('settings.user_options') }}
|
||||
</h2>
|
||||
<div class="box has-background-black-bis is-family-monospace is-size-7">
|
||||
<button class="button is-like-text is-pulled-right is-small is-text" v-clipboard="() => this.$refs.listUserOptions.innerText" v-clipboard:success="clipboardSuccessHandler">
|
||||
<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>
|
||||
<ul ref="listUserOptions">
|
||||
@ -76,7 +76,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 } }" role="button" :aria-label="$t('commons.close_the_x_page', {pagetitle: pagetitle})" class="button is-dark is-rounded">{{ $t('commons.close') }}</router-link>
|
||||
</p>
|
||||
</vue-footer>
|
||||
</responsive-width-wrapper>
|
||||
@ -86,6 +86,7 @@
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
pagetitle: this.$t('commons.about'),
|
||||
infos : null,
|
||||
options : null,
|
||||
showUserOptions: false,
|
||||
|
@ -56,12 +56,106 @@
|
||||
</p>
|
||||
<!-- Cancel button -->
|
||||
<p class="control">
|
||||
<a class="button is-dark is-rounded" @click="showGroupSelector = false">{{ $t('commons.cancel') }}</a>
|
||||
<button class="button is-dark is-rounded" @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="columns is-gapless is-mobile is-centered">
|
||||
<div v-if="editMode" class="column">
|
||||
<!-- toolbar -->
|
||||
<div class="toolbar has-text-centered">
|
||||
<div class="field is-grouped is-justify-content-center has-text-grey mb-2">
|
||||
<!-- selected label -->
|
||||
<p class="control mr-1">
|
||||
{{ selectedAccounts.length }} {{ $t('commons.selected') }}
|
||||
</p>
|
||||
<!-- deselect all -->
|
||||
<p class="control mr-4">
|
||||
<button @click="clearSelected" class="clear-selection delete" :style="{visibility: selectedAccounts.length > 0 ? 'visible' : 'hidden'}" :title="$t('commons.clear_selection')"></button>
|
||||
</p>
|
||||
<!-- select all button -->
|
||||
<p class="control mr-5">
|
||||
<button @click="selectAll" class="button has-line-height p-1 is-ghost has-background-black-ter has-text-grey" :title="$t('commons.select_all')">
|
||||
<span>{{ $t('commons.all') }}</span>
|
||||
<font-awesome-icon class="ml-1" :icon="['fas', 'check-square']" />
|
||||
</button>
|
||||
</p>
|
||||
<!-- sort asc/desc buttons -->
|
||||
<p class="control">
|
||||
<button @click="sortAsc" class="button has-line-height p-1 is-ghost has-background-black-ter has-text-grey" :title="$t('commons.sort_ascending')">
|
||||
<font-awesome-icon :icon="['fas', 'sort-alpha-down']" />
|
||||
</button>
|
||||
</p>
|
||||
<p class="control">
|
||||
<button @click="sortDesc" class="button has-line-height p-1 is-ghost has-background-black-ter has-text-grey" :title="$t('commons.sort_descending')">
|
||||
<font-awesome-icon :icon="['fas', 'sort-alpha-up']" />
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
<div class="field is-grouped is-justify-content-center pb-2">
|
||||
<!-- Change group button -->
|
||||
<div v-if="selectedAccounts.length > 0" class="control">
|
||||
<div tabindex="0" role="button" class="tag-button tag-button-link tags are-medium has-addons is-clickable" @click="showGroupSelector = true" @keyup.enter="showGroupSelector = true">
|
||||
<span class="tag is-dark mb-0">
|
||||
{{ $t('groups.change_group') }}
|
||||
</span>
|
||||
<span class="tag is-link mb-0">
|
||||
<font-awesome-icon :icon="['fas', 'layer-group']" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- delete selected button -->
|
||||
<div v-if="selectedAccounts.length > 0" class="control">
|
||||
<div tabindex="0" role="button" class="tag-button tag-button-danger tags are-medium has-addons is-clickable" @click="destroyAccounts" @keyup.enter="destroyAccounts">
|
||||
<span class="tag is-dark mb-0">
|
||||
{{ $t('commons.delete') }}
|
||||
</span>
|
||||
<span class="tag is-danger mb-0">
|
||||
<font-awesome-icon :icon="['fas', 'trash']" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="column is-three-quarters-mobile is-one-third-tablet is-one-quarter-desktop is-one-quarter-widescreen is-one-quarter-fullhd">
|
||||
<!-- search -->
|
||||
<div role="search" class="field">
|
||||
<div class="control has-icons-right">
|
||||
<input id="txtSearch" type="search" tabindex="1" :aria-label="$t('commons.search')" :title="$t('commons.search')" class="input is-rounded is-search" v-model="search">
|
||||
<span class="icon is-small is-right">
|
||||
<font-awesome-icon :icon="['fas', 'search']" v-if="!search" />
|
||||
<button tabindex="1" :title="$t('commons.clear_search')" class="clear-selection delete" v-if="search" @click="search = '' "></button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- group switch toggle -->
|
||||
<div 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">
|
||||
{{ 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">
|
||||
{{ $t('groups.select_accounts_to_show') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- modal -->
|
||||
<modal v-model="showTwofaccountInModal">
|
||||
<otp-displayer ref="OtpDisplayer"></otp-displayer>
|
||||
</modal>
|
||||
<!-- show accounts list -->
|
||||
<div class="container" v-if="this.showAccounts">
|
||||
<div class="container" v-if="this.showAccounts" :class="editMode ? 'is-edit-mode' : ''">
|
||||
<!-- accounts -->
|
||||
<!-- <vue-pull-refresh :on-refresh="onRefresh" :config="{
|
||||
errorLabel: 'error',
|
||||
@ -77,7 +171,7 @@
|
||||
<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">
|
||||
<label :for="'ckb_' + account.id"></label>
|
||||
<label tabindex="0" :for="'ckb_' + account.id" v-on:keypress.space.prevent="selectAccount(account.id)"></label>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
@ -135,94 +229,6 @@
|
||||
</p>
|
||||
</vue-footer>
|
||||
</div>
|
||||
<!-- header -->
|
||||
<div class="header has-background-black-ter" v-if="this.showAccounts || this.showGroupSwitch">
|
||||
<div class="columns is-gapless is-mobile is-centered">
|
||||
<div v-if="editMode" class="column">
|
||||
<!-- toolbar -->
|
||||
<div class="toolbar has-text-centered">
|
||||
<div class="field is-grouped is-justify-content-center">
|
||||
<div class="control">
|
||||
<div class="tags has-addons are-medium">
|
||||
<span class="tag is-dark has-background-black-ter has-text-grey">
|
||||
{{ selectedAccounts.length }} {{ $t('commons.selected') }}
|
||||
<button @click="clearSelected" :style="{visibility: selectedAccounts.length > 0 ? 'visible' : 'hidden'}" class="delete" :title="$t('commons.clear_selection')"></button>
|
||||
</span>
|
||||
<span role="button" @click="selectAll" class="tag is-dark is-clickable has-background-black-ter has-text-grey" :title="$t('commons.select_all')">
|
||||
{{ $t('commons.all') }}
|
||||
<font-awesome-icon class="ml-1" :icon="['fas', 'check-square']" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control">
|
||||
<div class="tags has-addons are-medium">
|
||||
<span role="button" @click="sortAsc" class="tag is-dark is-clickable has-background-black-ter has-text-grey" :title="$t('commons.sort_ascending')">
|
||||
<font-awesome-icon :icon="['fas', 'sort-alpha-down']" />
|
||||
</span>
|
||||
<span role="button" @click="sortDesc" class="tag is-dark is-clickable has-background-black-ter has-text-grey" :title="$t('commons.sort_descending')">
|
||||
<font-awesome-icon :icon="['fas', 'sort-alpha-up']" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field is-grouped is-justify-content-center pt-1">
|
||||
<div class="control">
|
||||
<div role="button" class="tags are-medium has-addons is-clickable" v-if="selectedAccounts.length > 0" @click="showGroupSelector = true">
|
||||
<span class="tag is-dark">
|
||||
{{ $t('groups.change_group') }}
|
||||
</span>
|
||||
<span class="tag is-link">
|
||||
<font-awesome-icon :icon="['fas', 'layer-group']" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control">
|
||||
<div role="button" class="tags are-medium has-addons is-clickable" v-if="selectedAccounts.length > 0" @click="destroyAccounts">
|
||||
<span class="tag is-dark">
|
||||
{{ $t('commons.delete') }}
|
||||
</span>
|
||||
<span class="tag is-danger">
|
||||
<font-awesome-icon :icon="['fas', 'trash']" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="column is-three-quarters-mobile is-one-third-tablet is-one-quarter-desktop is-one-quarter-widescreen is-one-quarter-fullhd">
|
||||
<!-- search -->
|
||||
<div class="field">
|
||||
<div class="control has-icons-right">
|
||||
<input id="txtSearch" type="search" tabindex="1" :aria-label="$t('commons.search')" :title="$t('commons.search')" class="input is-rounded is-search" v-model="search">
|
||||
<span class="icon is-small is-right">
|
||||
<font-awesome-icon :icon="['fas', 'search']" v-if="!search" />
|
||||
<a class="delete" v-if="search" @click="search = '' "></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- group switch toggle -->
|
||||
<div 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">
|
||||
{{ 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">
|
||||
{{ $t('groups.select_accounts_to_show') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- modal -->
|
||||
<modal v-model="showTwofaccountInModal">
|
||||
<otp-displayer ref="OtpDisplayer"></otp-displayer>
|
||||
</modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -353,7 +359,6 @@
|
||||
|
||||
// stop OTP generation on modal close
|
||||
this.$on('modalClose', function() {
|
||||
console.log('modalClose triggered')
|
||||
this.$refs.OtpDisplayer.clearOTP()
|
||||
});
|
||||
|
||||
@ -416,15 +421,7 @@
|
||||
showAccount(account) {
|
||||
// In Edit mode clicking an account do not show the otpDisplayer but select the account
|
||||
if(this.editMode) {
|
||||
|
||||
for (var i=0 ; i<this.selectedAccounts.length ; i++) {
|
||||
if ( this.selectedAccounts[i] === account.id ) {
|
||||
this.selectedAccounts.splice(i,1);
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.selectedAccounts.push(account.id)
|
||||
selectAccount(account.id)
|
||||
}
|
||||
else {
|
||||
this.$refs.OtpDisplayer.show(account.id)
|
||||
@ -432,6 +429,20 @@
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Select an account while in edit mode
|
||||
*/
|
||||
selectAccount(accountId) {
|
||||
for (var i=0 ; i<this.selectedAccounts.length ; i++) {
|
||||
if ( this.selectedAccounts[i] === accountId ) {
|
||||
this.selectedAccounts.splice(i,1);
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.selectedAccounts.push(accountId)
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a fresh OTP for the provided account
|
||||
*/
|
||||
|
@ -24,9 +24,9 @@
|
||||
</div>
|
||||
<div class="fullscreen-footer">
|
||||
<!-- Cancel button -->
|
||||
<label class="button is-large is-warning is-rounded" @click="exitStream()">
|
||||
<button class="button is-large is-warning is-rounded" @click="exitStream()">
|
||||
{{ $t('commons.cancel') }}
|
||||
</label>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -19,7 +19,7 @@
|
||||
{{ $t('commons.delete') }}
|
||||
</button>
|
||||
<!-- edit link -->
|
||||
<router-link :to="{ name: 'editGroup', params: { id: group.id, name: group.name }}" class="has-text-grey pl-1" :title="$t('commons.rename')">
|
||||
<router-link :to="{ name: 'editGroup', params: { id: group.id, name: group.name }}" class="has-text-grey px-1" :title="$t('commons.rename')">
|
||||
<font-awesome-icon :icon="['fas', 'pen-square']" />
|
||||
</router-link>
|
||||
<span class="is-family-primary is-size-6 is-size-7-mobile has-text-grey">{{ group.twofaccounts_count }} {{ $t('twofaccounts.accounts') }}</span>
|
||||
|
@ -11,14 +11,14 @@
|
||||
<div class="column is-full quick-uploader-button" >
|
||||
<div class="quick-uploader-centerer">
|
||||
<!-- upload a qr code (with basic file field and backend decoding) -->
|
||||
<label v-if="$root.appSettings.useBasicQrcodeReader" class="button is-link is-medium is-rounded is-focused" ref="qrcodeInputLabel">
|
||||
<input class="file-input" type="file" accept="image/*" v-on:change="submitQrCode" ref="qrcodeInput">
|
||||
<label role="button" tabindex="0" v-if="$root.appSettings.useBasicQrcodeReader" class="button is-link is-medium is-rounded is-focused" ref="qrcodeInputLabel" @keyup.enter="$refs.qrcodeInputLabel.click()">
|
||||
<input aria-hidden="true" tabindex="-1" class="file-input" type="file" accept="image/*" v-on:change="submitQrCode" ref="qrcodeInput">
|
||||
{{ $t('twofaccounts.forms.upload_qrcode') }}
|
||||
</label>
|
||||
<!-- scan button that launch camera stream -->
|
||||
<label v-else class="button is-link is-medium is-rounded is-focused" @click="capture()">
|
||||
<button v-else class="button is-link is-medium is-rounded is-focused is-double-focused" @click="capture()">
|
||||
{{ $t('twofaccounts.forms.scan_qrcode') }}
|
||||
</label>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- alternative methods -->
|
||||
@ -26,8 +26,8 @@
|
||||
<div class="block has-text-light">{{ $t('twofaccounts.forms.alternative_methods') }}</div>
|
||||
<!-- upload a qr code -->
|
||||
<div class="block has-text-link" v-if="!$root.appSettings.useBasicQrcodeReader">
|
||||
<label class="button is-link is-outlined is-rounded" ref="qrcodeInputLabel">
|
||||
<input class="file-input" type="file" accept="image/*" v-on:change="submitQrCode" ref="qrcodeInput">
|
||||
<label role="button" tabindex="0" class="button is-link is-outlined is-rounded" ref="qrcodeInputLabel" @keyup.enter="$refs.qrcodeInputLabel.click()">
|
||||
<input aria-hidden="true" tabindex="-1" class="file-input" type="file" accept="image/*" v-on:change="submitQrCode" ref="qrcodeInput">
|
||||
{{ $t('twofaccounts.forms.upload_qrcode') }}
|
||||
</label>
|
||||
</div>
|
||||
|
@ -29,9 +29,9 @@
|
||||
<p>{{ $t('auth.forms.dont_have_account_yet') }} <router-link id="lnkRegister" :to="{ name: 'register' }" class="is-link">{{ $t('auth.register') }}</router-link></p>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p>{{ $t('auth.forms.forgot_your_password') }} <router-link id="lnkResetPwd" :to="{ name: 'password.request' }" class="is-link">{{ $t('auth.forms.request_password_reset') }}</router-link></p>
|
||||
<p>{{ $t('auth.forms.forgot_your_password') }} <router-link id="lnkResetPwd" :to="{ name: 'password.request' }" class="is-link" :aria-label="$t('auth.forms.reset_your_password')">{{ $t('auth.forms.request_password_reset') }}</router-link></p>
|
||||
<p >{{ $t('auth.sign_in_using') }}
|
||||
<a id="lnkSignWithWebauthn" role="button" class="is-link" @keyup.enter="showWebauthn = true" @click="showWebauthn = true" tabindex="0">{{ $t('auth.webauthn.security_device') }}</a>
|
||||
<a id="lnkSignWithWebauthn" role="button" class="is-link" @keyup.enter="showWebauthn = true" @click="showWebauthn = true" tabindex="0" :aria-label="$t('auth.sign_in_using_security_device')">{{ $t('auth.webauthn.security_device') }}</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,7 +10,9 @@
|
||||
<div v-else>
|
||||
<div class="field">
|
||||
<input id="unique" name="unique" type="checkbox" class="is-checkradio is-info" v-model="unique" >
|
||||
<label for="unique" class="label">{{ $t('auth.webauthn.disable_all_other_devices') }}</label>
|
||||
<label tabindex="0" for="unique" class="label" ref="uniqueLabel" v-on:keypress.space.prevent="unique = true">
|
||||
{{ $t('auth.webauthn.disable_all_other_devices') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
|
@ -37,9 +37,9 @@
|
||||
<vue-footer :showButtons="true">
|
||||
<!-- Cancel button -->
|
||||
<p class="control">
|
||||
<a role="button" tabindex="0" class="button is-dark is-rounded" @click.stop="exitSettings">
|
||||
<button class="button is-dark is-rounded" @click.stop="exitSettings">
|
||||
{{ $t('commons.close') }}
|
||||
</a>
|
||||
</button>
|
||||
</p>
|
||||
</vue-footer>
|
||||
</div>
|
||||
|
@ -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">{{ $t('commons.close') }}</router-link>
|
||||
<router-link :to="{ name: 'accounts', params: { toRefresh: false } }" class="button is-dark is-rounded" tabindex="0">{{ $t('commons.close') }}</router-link>
|
||||
</p>
|
||||
</vue-footer>
|
||||
</form-wrapper>
|
||||
|
@ -56,9 +56,9 @@
|
||||
<vue-footer :showButtons="true">
|
||||
<!-- Cancel button -->
|
||||
<p class="control">
|
||||
<a class="button is-dark is-rounded" @click.stop="exitSettings">
|
||||
<button class="button is-dark is-rounded" @click.stop="exitSettings">
|
||||
{{ $t('commons.close') }}
|
||||
</a>
|
||||
</button>
|
||||
</p>
|
||||
</vue-footer>
|
||||
</div>
|
||||
|
@ -14,8 +14,8 @@
|
||||
</otp-displayer>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns is-mobile" v-if="form.errors.any()">
|
||||
<div class="column">
|
||||
<div class="columns is-mobile" role="alert">
|
||||
<div v-if="form.errors.any()" class="column">
|
||||
<p v-for="(field, index) in form.errors.errors" :key="index" class="help is-danger">
|
||||
<ul>
|
||||
<li v-for="(error, index) in field" :key="index">{{ error }}</li>
|
||||
@ -41,17 +41,19 @@
|
||||
<form-wrapper :title="$t('twofaccounts.forms.new_account')" v-if="showAdvancedForm">
|
||||
<form @submit.prevent="createAccount" @keydown="form.onKeydown($event)">
|
||||
<!-- qcode fileupload -->
|
||||
<div class="field">
|
||||
<div class="file is-black is-small">
|
||||
<label class="file-label" :title="$t('twofaccounts.forms.use_qrcode.title')">
|
||||
<input class="file-input" type="file" accept="image/*" v-on:change="uploadQrcode" ref="qrcodeInput">
|
||||
<span class="file-cta">
|
||||
<span class="file-icon">
|
||||
<font-awesome-icon :icon="['fas', 'qrcode']" size="lg" />
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<div role="button" tabindex="0" class="file is-black is-small" @keyup.enter="$refs.qrcodeInputLabel.click()">
|
||||
<label class="file-label" :title="$t('twofaccounts.forms.use_qrcode.title')" ref="qrcodeInputLabel">
|
||||
<input aria-hidden="true" tabindex="-1" class="file-input" type="file" accept="image/*" v-on:change="uploadQrcode" ref="qrcodeInput">
|
||||
<span class="file-cta">
|
||||
<span class="file-icon">
|
||||
<font-awesome-icon :icon="['fas', 'qrcode']" size="lg" />
|
||||
</span>
|
||||
<span class="file-label">{{ $t('twofaccounts.forms.prefill_using_qrcode') }}</span>
|
||||
</span>
|
||||
<span class="file-label">{{ $t('twofaccounts.forms.prefill_using_qrcode') }}</span>
|
||||
</span>
|
||||
</label>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<field-error :form="form" field="qrcode" class="help-for-file" />
|
||||
@ -73,9 +75,9 @@
|
||||
</div>
|
||||
<!-- upload button -->
|
||||
<div class="control">
|
||||
<div class="file is-dark">
|
||||
<label class="file-label">
|
||||
<input class="file-input" type="file" accept="image/*" v-on:change="uploadIcon" ref="iconInput">
|
||||
<div role="button" tabindex="0" class="file is-dark" @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">
|
||||
<span class="file-icon">
|
||||
<font-awesome-icon :icon="['fas', 'upload']" />
|
||||
@ -85,7 +87,7 @@
|
||||
</label>
|
||||
<span class="tag is-black is-large" v-if="tempIcon">
|
||||
<img class="icon-preview" :src="'/storage/icons/' + tempIcon" :alt="$t('twofaccounts.icon_to_illustrate_the_account')">
|
||||
<button class="delete is-small" @click.prevent="deleteIcon" :aria-label="$t('twofaccounts.remove_icon')"></button>
|
||||
<button class="clear-selection delete is-small" @click.prevent="deleteIcon" :aria-label="$t('twofaccounts.remove_icon')"></button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -19,9 +19,9 @@
|
||||
</div>
|
||||
<!-- upload button -->
|
||||
<div class="control">
|
||||
<div class="file is-dark">
|
||||
<label class="file-label">
|
||||
<input class="file-input" type="file" accept="image/*" v-on:change="uploadIcon" ref="iconInput">
|
||||
<div role="button" tabindex="0" class="file is-dark" @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">
|
||||
<span class="file-icon">
|
||||
<font-awesome-icon :icon="['fas', 'upload']" />
|
||||
@ -31,7 +31,7 @@
|
||||
</label>
|
||||
<span class="tag is-black is-large" v-if="tempIcon">
|
||||
<img class="icon-preview" :src="'/storage/icons/' + tempIcon" :alt="$t('twofaccounts.icon_to_illustrate_the_account')">
|
||||
<button class="delete is-small" @click.prevent="deleteIcon" :aria-label="$t('twofaccounts.remove_icon')"></button>
|
||||
<button class="clear-selection delete is-small" @click.prevent="deleteIcon" :aria-label="$t('twofaccounts.remove_icon')"></button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -57,18 +57,18 @@
|
||||
<input :id="this.inputId('text','secret')" class="input" type="text" v-model="form.secret" :disabled="secretIsLocked">
|
||||
</p>
|
||||
<p class="control" v-if="secretIsLocked">
|
||||
<a class="button is-dark field-lock" @click="secretIsLocked = false" :title="$t('twofaccounts.forms.unlock.title')">
|
||||
<button type="button" class="button is-dark field-lock" @click.stop="secretIsLocked = false" :title="$t('twofaccounts.forms.unlock.title')">
|
||||
<span class="icon">
|
||||
<font-awesome-icon :icon="['fas', 'lock']" />
|
||||
</span>
|
||||
</a>
|
||||
</button>
|
||||
</p>
|
||||
<p class="control" v-else>
|
||||
<a class="button is-dark field-unlock" @click="secretIsLocked = true" :title="$t('twofaccounts.forms.lock.title')">
|
||||
<button type="button" class="button is-dark field-unlock" @click.stop="secretIsLocked = true" :title="$t('twofaccounts.forms.lock.title')">
|
||||
<span class="icon has-text-danger">
|
||||
<font-awesome-icon :icon="['fas', 'lock-open']" />
|
||||
</span>
|
||||
</a>
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
@ -96,18 +96,18 @@
|
||||
<input class="input" type="text" placeholder="" v-model="form.counter" :disabled="counterIsLocked" />
|
||||
</div>
|
||||
<div class="control" v-if="counterIsLocked">
|
||||
<a class="button is-dark field-lock" @click="counterIsLocked = false" :title="$t('twofaccounts.forms.unlock.title')">
|
||||
<button type="button" class="button is-dark field-lock" @click="counterIsLocked = false" :title="$t('twofaccounts.forms.unlock.title')">
|
||||
<span class="icon">
|
||||
<font-awesome-icon :icon="['fas', 'lock']" />
|
||||
</span>
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
<div class="control" v-else>
|
||||
<a class="button is-dark field-unlock" @click="counterIsLocked = true" :title="$t('twofaccounts.forms.lock.title')">
|
||||
<button type="button" class="button is-dark field-unlock" @click="counterIsLocked = true" :title="$t('twofaccounts.forms.lock.title')">
|
||||
<span class="icon has-text-danger">
|
||||
<font-awesome-icon :icon="['fas', 'lock-open']" />
|
||||
</span>
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<field-error :form="form" field="counter" />
|
||||
|
@ -8,9 +8,9 @@
|
||||
</div>
|
||||
<div class="fullscreen-footer">
|
||||
<!-- Close button -->
|
||||
<label class="button is-dark is-rounded" @click.stop="$router.push({name: 'accounts', params: {initialEditMode: true}});">
|
||||
<button class="button is-dark is-rounded" @click.stop="$router.push({name: 'accounts', params: {initialEditMode: true}});">
|
||||
{{ $t('commons.close') }}
|
||||
</label>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -22,6 +22,7 @@
|
||||
'sign_out' => 'Sign out',
|
||||
'sign_in' => 'Sign in',
|
||||
'sign_in_using' => 'Sign in using',
|
||||
'sign_in_using_security_device' => 'Sign in using a security device',
|
||||
'login_and_password' => 'login & password',
|
||||
'register' => 'Register',
|
||||
'welcome_back_x' => 'Welcome back {0}',
|
||||
@ -89,6 +90,7 @@
|
||||
'authentication_failed' => 'Authentication failed',
|
||||
'forgot_your_password' => 'Forgot your password?',
|
||||
'request_password_reset' => 'Reset it',
|
||||
'reset_your_password' => 'Reset your password',
|
||||
'reset_password' => 'Reset password',
|
||||
'disabled_in_demo' => 'Feature disabled in Demo mode',
|
||||
'new_password' => 'New password',
|
||||
|
@ -27,6 +27,7 @@
|
||||
'save' => 'Save',
|
||||
'close' => 'Close',
|
||||
'clear' => 'Clear',
|
||||
'clear_search' => 'Clear search',
|
||||
'demo_do_not_post_sensitive_data' => 'This is a demo app, do not post any sensitive data',
|
||||
'testing_do_not_post_sensitive_data' => 'This is a testing app, do not post any sensitive data',
|
||||
'selected' => 'selected',
|
||||
@ -67,4 +68,5 @@
|
||||
'image_of_qrcode_to_scan' => 'Image of a QR code to scan',
|
||||
'file' => 'File',
|
||||
'or' => 'OR',
|
||||
'close_the_x_page' => 'Close the {pagetitle} page',
|
||||
];
|
172
resources/sass/app.scss
vendored
172
resources/sass/app.scss
vendored
@ -35,6 +35,7 @@ a:hover {
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
@supports (padding-top: env(safe-area-inset-top)) {
|
||||
@ -51,6 +52,19 @@ a:hover {
|
||||
}
|
||||
}
|
||||
|
||||
.modal-otp {
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.otp:focus-visible {
|
||||
outline-offset: 3px;
|
||||
outline: 2px dotted $dark;
|
||||
border-radius: $radius-large;
|
||||
}
|
||||
.otp:focus:not(:focus-visible) {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.group-item {
|
||||
border-bottom: 1px solid hsl(0, 0%, 21%);
|
||||
padding: 0.75rem;
|
||||
@ -65,7 +79,7 @@ a:hover {
|
||||
}
|
||||
|
||||
.accounts {
|
||||
margin-top: 74px;
|
||||
margin-top: 75px;
|
||||
}
|
||||
|
||||
.groups {
|
||||
@ -82,7 +96,7 @@ a:hover {
|
||||
|
||||
@media screen and (min-width: 769px) {
|
||||
.accounts {
|
||||
margin-top: 98px;
|
||||
margin-top: 99px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -205,16 +219,19 @@ a:hover {
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
.tfa-content:focus, .tfa-content:focus-visible
|
||||
.tfa-content:focus-visible
|
||||
{
|
||||
outline: 2px solid $grey;
|
||||
outline: 1px solid $grey;
|
||||
border: none;
|
||||
outline-offset: 7px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.tfa-content:focus:not(:focus-visible) {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.tfa-list .tfa-content {
|
||||
padding-right: 1rem;
|
||||
.is-edit-mode .tfa-list .tfa-content {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.tfa-dots {
|
||||
@ -377,6 +394,14 @@ figure.no-icon {
|
||||
color: hsl(0, 0%, 21%);
|
||||
}
|
||||
|
||||
.button.has-line-height {
|
||||
height: inherit !important;
|
||||
}
|
||||
.button.has-line-height span {
|
||||
display: inline-block;
|
||||
line-height: 1rem;
|
||||
}
|
||||
|
||||
.button.is-dark.field-lock, .button.is-dark.field-unlock {
|
||||
color: hsl(0, 0%, 48%);
|
||||
}
|
||||
@ -409,14 +434,17 @@ figure.no-icon {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.button:focus, .button:focus-visible, .button.is-focused {
|
||||
.button:focus-visible, .button.is-focused,
|
||||
.file[role=button]:focus-visible {
|
||||
border-color: transparent;
|
||||
outline-offset: 3px;
|
||||
outline-style: solid;
|
||||
outline-width: 2px;
|
||||
}
|
||||
a:focus, a:focus-visible {
|
||||
outline-offset: 2px;
|
||||
.button:focus:not(:focus-visible),
|
||||
.file[role=button]:focus:not(:focus-visible)
|
||||
{
|
||||
outline: none;
|
||||
}
|
||||
.button:focus:not(:active), .button.is-focused:not(:active),
|
||||
.button.is-white:focus:not(:active), .button.is-white.is-focused:not(:active),
|
||||
@ -434,62 +462,120 @@ a:focus, a:focus-visible {
|
||||
{
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.button.is-white:focus, .button.is-white:focus-visible, .button.is-white.is-focused
|
||||
{
|
||||
outline: 2px solid $white;
|
||||
outline-color: $white;
|
||||
}
|
||||
.button.is-light:focus, .button.is-light:focus-visible, .button.is-light.is-focused
|
||||
{
|
||||
outline: 2px solid $grey-lightest;
|
||||
outline-color: $grey-lightest;
|
||||
}
|
||||
.button.is-dark:focus, .button.is-dark:focus-visible, .button.is-dark.is-focused
|
||||
.button.is-dark:focus, .button.is-dark:focus-visible, .button.is-dark.is-focused,
|
||||
.file[role=button].is-dark:focus, .file[role=button].is-dark:focus-visible
|
||||
{
|
||||
outline: 2px solid $dark;
|
||||
outline-color: $dark;
|
||||
}
|
||||
.button.is-black:focus, .button.is-black:focus-visible, .button.is-black.is-focused
|
||||
.button.is-black:focus, .button.is-black:focus-visible, .button.is-black.is-focused,
|
||||
.file[role=button].is-black:focus, .file[role=button].is-black:focus-visible
|
||||
{
|
||||
outline: 2px solid $black;
|
||||
outline-color: $black;
|
||||
}
|
||||
.button.is-text:focus, .button.is-text:focus-visible, .button.is-text.is-focused
|
||||
{
|
||||
outline: 2px solid $text;
|
||||
outline-color: $text;
|
||||
}
|
||||
.button.is-ghost:focus, .button.is-ghost:focus-visible, .button.is-ghost.is-focused
|
||||
{
|
||||
outline: 2px solid $text;
|
||||
outline-color: $text;
|
||||
}
|
||||
.button.is-primary:focus, .button.is-primary:focus-visible, .button.is-primary.is-focused
|
||||
{
|
||||
outline: 2px solid $primary;
|
||||
outline-color: $primary;
|
||||
}
|
||||
.button.is-link:focus, .button.is-link:focus-visible, .button.is-link.is-focused
|
||||
{
|
||||
outline: 2px solid $link;
|
||||
outline-color: $link;
|
||||
}
|
||||
.button.is-info:focus, .button.is-info:focus-visible, .button.is-info.is-focused
|
||||
{
|
||||
outline: 2px solid $info;
|
||||
outline-color: $info;
|
||||
}
|
||||
.button.is-success:focus, .button.is-success:focus-visible, .button.is-success.is-focused
|
||||
{
|
||||
outline: 2px solid $success;
|
||||
outline-color: $success;
|
||||
}
|
||||
.button.is-warning:focus, .button.is-warning:focus-visible, .button.is-warning.is-focused
|
||||
{
|
||||
outline: 2px solid $warning;
|
||||
outline-color: $warning;
|
||||
}
|
||||
.button.is-danger:focus, .button.is-danger:focus-visible, .button.is-danger.is-focused
|
||||
{
|
||||
outline: 2px solid $danger;
|
||||
outline-color: $danger;
|
||||
}
|
||||
|
||||
a:focus, a:focus-visible
|
||||
button.is-double-focused:focus-visible
|
||||
{
|
||||
outline-style: double !important;
|
||||
outline-width: 6px !important;
|
||||
}
|
||||
button.is-double-focused:focus:not(:focus-visible)
|
||||
{
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.file[role=button]:focus-visible {
|
||||
border-radius: $radius;
|
||||
}
|
||||
.file[role=button].is-small:focus-visible {
|
||||
border-radius: $radius-small;
|
||||
}
|
||||
|
||||
.tag-button:focus-visible
|
||||
{
|
||||
border-color: transparent;
|
||||
border-radius: 3px;
|
||||
outline-width: 1px;
|
||||
outline-style: solid;
|
||||
outline-offset: 3px;
|
||||
}
|
||||
.tag-button:focus:not(:focus-visible)
|
||||
{
|
||||
outline: none;
|
||||
}
|
||||
.tag-button-link:focus-visible
|
||||
{
|
||||
outline-color: $link;
|
||||
}
|
||||
.tag-button-danger:focus-visible
|
||||
{
|
||||
outline-color: $danger;
|
||||
}
|
||||
|
||||
.clear-selection
|
||||
{
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.clear-selection:focus-visible
|
||||
{
|
||||
border-color: transparent;
|
||||
outline-offset: 1px;
|
||||
outline: 2px solid $text;
|
||||
}
|
||||
.clear-selection:focus:not(:focus-visible)
|
||||
{
|
||||
outline: none;
|
||||
}
|
||||
|
||||
a:focus-visible
|
||||
{
|
||||
outline-offset: 2px;
|
||||
border-radius: 3px;
|
||||
outline: 1px dashed $link;
|
||||
}
|
||||
|
||||
a:focus:not(:focus-visible)
|
||||
{
|
||||
outline: none;
|
||||
}
|
||||
a.has-text-black-bis:focus, a.has-text-black-bis:focus-visible {
|
||||
outline-color: $black-bis;
|
||||
}
|
||||
@ -518,19 +604,36 @@ a.has-text-white-bis:focus, a.has-text-white-bis:focus-visible {
|
||||
outline-color: $white-bis;
|
||||
}
|
||||
|
||||
.tabs a:focus, .tabs a:focus-visible {
|
||||
a.tag.is-dark.is-rounded:focus-visible
|
||||
{
|
||||
outline-offset: 1px;
|
||||
outline: 1px solid $grey;
|
||||
}
|
||||
a.tag.is-dark.is-rounded:focus:not(:focus-visible)
|
||||
{
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.tabs a:focus-visible {
|
||||
outline-offset: -4px;
|
||||
}
|
||||
.tabs a:focus:not(:focus-visible)
|
||||
{
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.control.has-icons-right > span.icon:focus-visible,
|
||||
.control.has-icons-left > span.icon:focus-visible,
|
||||
.control.has-icons-right > span.icon:focus,
|
||||
.control.has-icons-left > span.icon:focus
|
||||
.control.has-icons-left > span.icon:focus-visible
|
||||
{
|
||||
outline: none;
|
||||
border: 1px solid $input-focus-border-color;
|
||||
box-shadow: $input-focus-box-shadow-size $input-focus-box-shadow-color;
|
||||
}
|
||||
.control.has-icons-right > span.icon:focus:not(:focus-visible),
|
||||
.control.has-icons-left > span.icon:focus:not(:focus-visible)
|
||||
{
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.is-checkradio[type="checkbox"] + label:focus,
|
||||
.is-checkradio[type="checkbox"] + label:focus-visible
|
||||
@ -634,10 +737,6 @@ footer .field.is-grouped {
|
||||
}
|
||||
}
|
||||
|
||||
.notification .notification-title {
|
||||
// Style for title line
|
||||
}
|
||||
|
||||
.notification .notification-content {
|
||||
text-align: center;
|
||||
}
|
||||
@ -773,7 +872,6 @@ footer .field.is-grouped {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
|
||||
.fadeInOut-enter-active {
|
||||
animation: fadeIn 500ms
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user