#1458 OptionsPage - Excluded domains list WIP

This commit is contained in:
Grzegorz Zając 2023-12-11 12:55:45 +01:00
parent 009123d4f0
commit 677c49eb70
22 changed files with 664 additions and 53 deletions

View File

@ -16,6 +16,7 @@
"save": "Save",
"version": "Version",
"yes": "Yes",
"add": "Add",
"cancel": "Cancel",
"shortcut": "Shortcut",
"neverShowAgain": "Never show again",
@ -38,10 +39,12 @@
"modalSafariResetHeader": "Browser Extension reset",
"modalSafariResetText": "You are attempting to reset the 2FAS Browser Extension. Are you sure?",
"noPairedDevices": "No paired devices found",
"noExcludedDomains": "No excluded domains found",
"deviceName": "Device name",
"pairingDate": "Pairing date",
"platform": "Platform",
"disconnect": "Disconnect",
"domain": "Domain",
"gotIt": "Got it",
"install": "Install",
"2faAuthenticator2FAS": "2FA Authenticator (2FAS)",

View File

@ -9,6 +9,12 @@
"optionsDonate": "Donate",
"optionsPairedHeader": "Paired devices:",
"optionsAddAnotherDevice": "Add another device",
"optionsExcludedDomainsHeader": "Auto submit excluded domains:",
"optionsRemoveFromExcluded": "Remove from excluded",
"optionsExcludeAnotherDomain": "Exclude another domain",
"optionsDomainModalHeader": "Exclude new domain",
"optionsDomainModalText": "With the form below, you can add your domain to exclusion list, ensuring it won't be subjected to the auto submit mechanism.",
"optionsDomainInputPlaceholder": "Type in domain to exclude...",
"optionsLogsLabel": "Approve 2FAS Browser Extension logs",
"optionsLogsDesc": "Help us improve our browser extension by approving anonymous logs from your browser regarding 2FAS Browser Extension errors only.",
"optionsContextMenuLabel": "Show 2FAS Browser Extension option in context menu",

View File

@ -58,6 +58,7 @@ const generateDefaultStorage = browserInfo => {
nativePush: (process.env.EXT_PLATFORM !== 'Safari'),
pinInfo: false,
extensionVersion: config.ExtensionVersion,
autoSubmitExcludedDomains: [],
attempt: attempt + 1
});
})

View File

@ -19,12 +19,12 @@
const hideConfirmModal = require('./hideConfirmModal');
const modalBackdropClick = e => {
const confirmModalBackdropClick = e => {
const elClassList = Array.from(e.target.classList);
if (elClassList.includes('js-twofas-options-modal')) {
if (elClassList.includes('js-twofas-confirm-modal')) {
hideConfirmModal();
}
};
module.exports = modalBackdropClick;
module.exports = confirmModalBackdropClick;

View File

@ -0,0 +1,30 @@
//
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
// Copyright © 2023 Two Factor Authentication Service, Inc.
// Contributed by Grzegorz Zając. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>
//
const hideDomainModal = require('./hideDomainModal');
const domainModalBackdropClick = e => {
const elClassList = Array.from(e.target.classList);
if (elClassList.includes('js-twofas-domain-modal')) {
hideDomainModal();
}
};
module.exports = domainModalBackdropClick;

View File

@ -45,7 +45,7 @@ const generateDevicesList = list => {
platform: null,
button: null,
svg: null
}
};
t.tr = createElement('tr');
t.tr.dataset.deviceId = device.id;

View File

@ -0,0 +1,77 @@
//
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
// Copyright © 2023 Two Factor Authentication Service, Inc.
// Contributed by Grzegorz Zając. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>
//
/* global alert */
const browser = require('webextension-polyfill');
const { createElement, createSVGElement, createTextElement } = require('../../partials/DOMElements');
const generateEmptyDomainRow = require('./generateEmptyDomainRow');
const S = require('../../selectors');
const disconnectSVG = require('../../images/page-icons/disconnect.svg');
const generateDomainsList = list => {
if (!list) {
list = [];
}
const tbody = document.querySelector(S.optionsPage.autoSubmit.list);
if (list.length === 0) {
generateEmptyDomainRow(tbody);
}
list.map(d => {
let t = {
tr: null,
td: [null, null],
domain: null,
button: null,
svg: null
};
t.tr = createElement('tr');
t.tr.dataset.deviceId = d.domain;
t.td[0] = createElement('td');
t.td[0].setAttribute('data-before-i18n', browser.i18n.getMessage('domain'));
t.domain = createTextElement('span', d.domain);
t.td[0].appendChild(t.domain);
t.tr.appendChild(t.td[0]);
t.td[1] = createElement('td');
t.td[1].setAttribute('data-before-i18n', browser.i18n.getMessage('optionsRemoveFromExcluded'));
t.button = createElement('button');
t.button.dataset.domain = d.domain;
t.button.addEventListener('click', () => { alert('elo'); });
t.svg = createSVGElement(disconnectSVG);
t.button.appendChild(t.svg);
t.td[1].appendChild(t.button);
t.tr.appendChild(t.td[1]);
tbody.appendChild(t.tr);
t = null;
return d;
});
};
module.exports = generateDomainsList;

View File

@ -25,7 +25,7 @@ const generateEmptyDeviceRow = tbody => {
tr: null,
td: null,
noDevice: null
}
};
t.tr = createElement('tr');
t.td = createElement('td');

View File

@ -0,0 +1,43 @@
//
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
// Copyright © 2023 Two Factor Authentication Service, Inc.
// Contributed by Grzegorz Zając. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>
//
const browser = require('webextension-polyfill');
const { createElement, createTextElement } = require('../../partials/DOMElements');
const generateEmptyDomainRow = tbody => {
let t = {
tr: null,
td: null,
noExcludedDomains: null
};
t.tr = createElement('tr');
t.td = createElement('td');
t.td.setAttribute('colspan', '2');
t.noExcludedDomains = createTextElement('p', browser.i18n.getMessage('noExcludedDomains'));
t.td.appendChild(t.noExcludedDomains);
t.tr.appendChild(t.td);
tbody.appendChild(t.tr);
t = null;
};
module.exports = generateEmptyDomainRow;

View File

@ -20,9 +20,9 @@
const S = require('../../selectors');
const hideConfirmModal = () => {
const modalEl = document.querySelector(S.optionsPage.modal.element);
const headerEl = document.querySelector(S.optionsPage.modal.header);
const textEl = document.querySelector(S.optionsPage.modal.text);
const modalEl = document.querySelector(S.optionsPage.confirmModal.element);
const headerEl = document.querySelector(S.optionsPage.confirmModal.header);
const textEl = document.querySelector(S.optionsPage.confirmModal.text);
modalEl.classList.add('hidden');

View File

@ -0,0 +1,29 @@
//
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
// Copyright © 2023 Two Factor Authentication Service, Inc.
// Contributed by Grzegorz Zając. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>
//
const S = require('../../selectors');
const hideDomainModal = () => {
// @TODO: Clear input
const modalEl = document.querySelector(S.optionsPage.domainModal.element);
modalEl.classList.add('hidden');
};
module.exports = hideDomainModal;

View File

@ -17,7 +17,9 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>
//
exports.extNameUpdate = require('../../partials/extNameUpdate');
exports.confirmModalBackdropClick = require('./confirmModalBackdropClick');
exports.domainModalBackdropClick = require('./domainModalBackdropClick');
exports.generateDomainsList = require('./generateDomainsList');
exports.generateDevicesList = require('./generateDevicesList');
exports.generateEmptyDeviceRow = require('./generateEmptyDeviceRow');
exports.generateEmptyShortcutBox = require('./generateEmptyShortcutBox');
@ -32,8 +34,9 @@ exports.handlePinInfo = require('./handlePinInfo');
exports.handlePinInfoNext = require('./handlePinInfoNext');
exports.handlePinInfoPrev = require('./handlePinInfoPrev');
exports.handlePushChange = require('./handlePushChange');
exports.hideDomainModal = require('./hideDomainModal');
exports.hideConfirmModal = require('./hideConfirmModal');
exports.modalBackdropClick = require('./modalBackdropClick');
exports.confirmModalBackdropClick = require('./confirmModalBackdropClick');
exports.removeDevice = require('./removeDevice');
exports.removeDeviceFromDOM = require('./removeDeviceFromDOM');
exports.sendTestNotification = require('./sendTestNotification');
@ -46,9 +49,10 @@ exports.setPinInfoBtns = require('./setPinInfoBtns');
exports.setHamburger = require('./setHamburger');
exports.setLoggingToggle = require('./setLoggingToggle');
exports.setMenuLinks = require('./setMenuLinks');
exports.setModalListeners = require('./setModalListeners');
exports.setModalsListeners = require('./setModalsListeners');
exports.setPinInfo = require('./setPinInfo');
exports.setPushRadio = require('./setPushRadio');
exports.setShortcutBox = require('./setShortcutBox');
exports.showDomainModal = require('./showDomainModal');
exports.showConfirmModal = require('./showConfirmModal');
exports.showIntegrityError = require('./showIntegrityError');

View File

@ -0,0 +1,56 @@
//
// This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
// Copyright © 2023 Two Factor Authentication Service, Inc.
// Contributed by Grzegorz Zając. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>
//
const S = require('../../selectors');
const hideConfirmModal = require('./hideConfirmModal');
const hideDomainModal = require('./hideDomainModal');
const confirmModalBackdropClick = require('./confirmModalBackdropClick');
const domainModalBackdropClick = require('./domainModalBackdropClick');
const showDomainModal = require('./showDomainModal');
const setModalsListeners = () => {
const confirmModalCancel = document.querySelectorAll(S.optionsPage.confirmModal.cancel);
Array.from(confirmModalCancel).forEach(el => el.addEventListener('click', hideConfirmModal));
const domainModalCancel = document.querySelectorAll(S.optionsPage.domainModal.cancel);
Array.from(domainModalCancel).forEach(el => el.addEventListener('click', hideDomainModal));
const excludeDomainAdd = document.querySelectorAll(S.optionsPage.autoSubmit.add);
Array.from(excludeDomainAdd).forEach(el => el.addEventListener('click', showDomainModal));
const confirmModal = document.querySelector(S.optionsPage.confirmModal.element);
confirmModal.addEventListener('click', confirmModalBackdropClick);
const domainModal = document.querySelector(S.optionsPage.domainModal.element);
domainModal.addEventListener('click', domainModalBackdropClick);
window.addEventListener('keydown', e => {
if (e.code === 'Escape') {
if (!confirmModal.classList.contains('hidden')) {
return hideConfirmModal();
}
if (!domainModal.classList.contains('hidden')) {
return hideDomainModal();
}
}
})
};
module.exports = setModalsListeners;

View File

@ -20,9 +20,9 @@
const S = require('../../selectors');
const showConfirmModal = (header, text, func = null) => {
const modalEl = document.querySelector(S.optionsPage.modal.element);
const headerEl = document.querySelector(S.optionsPage.modal.header);
const textEl = document.querySelector(S.optionsPage.modal.text);
const modalEl = document.querySelector(S.optionsPage.confirmModal.element);
const headerEl = document.querySelector(S.optionsPage.confirmModal.header);
const textEl = document.querySelector(S.optionsPage.confirmModal.text);
headerEl.textContent = header;
textEl.textContent = text;
@ -30,7 +30,7 @@ const showConfirmModal = (header, text, func = null) => {
modalEl.classList.remove('hidden');
if (typeof func === 'function') {
const confirmEl = document.querySelector(S.optionsPage.modal.confirm);
const confirmEl = document.querySelector(S.optionsPage.confirmModal.confirm);
const newConfirmEl = confirmEl.cloneNode(true);
confirmEl.parentNode.replaceChild(newConfirmEl, confirmEl);

View File

@ -18,21 +18,22 @@
//
const S = require('../../selectors');
const hideConfirmModal = require('./hideConfirmModal');
const modalBackdropClick = require('./modalBackdropClick');
const setModalListeners = () => {
const confirmModalCancel = document.querySelectorAll(S.optionsPage.modal.cancel);
Array.from(confirmModalCancel).forEach(el => el.addEventListener('click', hideConfirmModal));
const showDomainModal = () => {
const modalEl = document.querySelector(S.optionsPage.domainModal.element);
const confirmModal = document.querySelector(S.optionsPage.modal.element);
confirmModal.addEventListener('click', modalBackdropClick);
modalEl.classList.remove('hidden');
window.addEventListener('keydown', e => {
if (e.code === 'Escape') {
return hideConfirmModal();
}
})
if (typeof func === 'function') {
const confirmEl = document.querySelector(S.optionsPage.domainModal.confirm);
const newConfirmEl = confirmEl.cloneNode(true);
confirmEl.parentNode.replaceChild(newConfirmEl, confirmEl);
newConfirmEl.addEventListener('click', () => {
// func();
modalEl.classList.add('hidden');
});
}
};
module.exports = setModalListeners;
module.exports = showDomainModal;

View File

@ -123,6 +123,34 @@
</div>
</div>
<div class="twofas-options-page-content-auto-submit-excluded-domain-list">
<div class="twofas-options-page-content-auto-submit-excluded-domain-list-header">
<h2 data-i18n="optionsExcludedDomainsHeader">Auto submit excluded domains:</h2>
<!-- @TODO: Add tooltip -->
</div>
<div class="twofas-options-page-content-auto-submit-excluded-domain-list-list">
<table>
<thead>
<tr>
<th data-i18n="domain">Domain</th>
<th data-i18n="optionsRemoveFromExcluded">Remove from excluded</th>
</tr>
</thead>
<tbody class="js-twofas-auto-submit-excluded-domain-list"></tbody>
</table>
<a class="twofas-options-page-content-auto-submit-excluded-domain-list-exclude js-twofas-auto-submit-excluded-domain-add" href="#">
<span class="twofas-options-page-content-auto-submit-excluded-domain-list-exclude-icon">
<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Shape" d="M11.4919 1.42856H10.4919V2.42856V10.4898H2.43066H1.43066V11.4898V14.5102V15.5102H2.43066H10.4919V23.5714V24.5714H11.4919H14.5123H15.5123V23.5714V15.5102H23.5735H24.5735V14.5102V11.4898V10.4898H23.5735H15.5123V2.42856V1.42856H14.5123H11.4919Z" fill="white" stroke="white"/>
</svg>
</span>
<span data-i18n="optionsExcludeAnotherDomain" class="twofas-options-page-content-auto-submit-excluded-domain-list-exclude-text">Exclude another domain</span>
</a>
</div>
</div>
<%= require.context('html-loader!../views/optionsViews', false, OPTIONS_VIEW_REGEXP)(OPTIONS_VIEW_FILENAME).default %>
<div class="twofas-options-page-content-social">
@ -154,6 +182,7 @@
<p><span data-i18n="version">Version</span>&nbsp&nbsp;<span class="twofas-ext-version"></span></p>
</div>
</div>
<div data-twofas-content="intro" class="twofas-options-page-content-container js-twofas-options-content">
<h1 class="twofas-intro-header" data-i18n="optionsIntroHeader">2FAS Extension Settings</h1>
@ -177,7 +206,8 @@
<%= require.context('html-loader!../views/pinInfoViews', false, PININFO_VIEW_REGEXP)(PININFO_VIEW_FILENAME).default %>
</section>
<%= require('html-loader!../views/optionsPageModal.html').default %>
<%= require('html-loader!../views/optionsPageConfirmModal.html').default %>
<%= require('html-loader!../views/optionsPageDomainModal.html').default %>
<div class="twofas-be-notifications"></div>
</body>

View File

@ -25,7 +25,7 @@ const TwoFasNotification = require('../notification');
const SDK = require('../sdk');
const extPageOnMessage = require('../partials/extPageOnMessage');
const { delay, storeLog, handleTargetBlank, hidePreloader, storageValidation } = require('../partials');
const { generateDevicesList, setLoggingToggle, setContextMenuToggle, setPushRadio, setPinInfo, setExtName, setExtNameUpdateForm, setModalListeners, setAdvanced, setMenuLinks, setPinInfoBtns, setShortcutBox, setHamburger, setExtVersion, generateShortcutBox, generateShortcutLink, showIntegrityError } = require('./functions');
const { generateDevicesList, setLoggingToggle, setContextMenuToggle, setPushRadio, setPinInfo, setExtName, setExtNameUpdateForm, setModalsListeners, setAdvanced, setMenuLinks, setPinInfoBtns, setShortcutBox, setHamburger, setExtVersion, generateShortcutBox, generateShortcutLink, showIntegrityError, generateDomainsList } = require('./functions');
const init = async storage => {
i18n();
@ -48,10 +48,11 @@ const init = async storage => {
return new SDK().getAllPairedDevices(storage.extensionID)
.then(generateDevicesList)
.then(() => generateDomainsList(storage.autoSubmitExcludedDomains))
.then(setPinInfo)
.then(() => setExtName(storage.browserInfo.name))
.then(() => setExtNameUpdateForm(storage))
.then(setModalListeners)
.then(setModalsListeners)
.then(setAdvanced)
.then(setMenuLinks)
.then(setPinInfoBtns)
@ -74,7 +75,7 @@ const optionsPageError = async err => {
};
window.onload = () => {
loadFromLocalStorage(['extensionID', 'keys', 'browserInfo', 'attempt'])
loadFromLocalStorage(['extensionID', 'keys', 'browserInfo', 'attempt', 'autoSubmitExcludedDomains'])
.then(data => init(data))
.catch(err => optionsPageError(err));
};

View File

@ -114,7 +114,7 @@
table {
border-collapse: collapse;
border: 0;
margin-bottom: 34px;
margin-bottom: 20px;
width: 100%;
@media all and (max-width: 660px) {
@ -336,6 +336,232 @@
}
}
&-auto-submit-excluded-domain-list {
margin-top: 34px;
table {
border-collapse: collapse;
border: 0;
margin-bottom: 20px;
width: 100%;
@media all and (max-width: 660px) {
display: block;
margin-bottom: 16px;
}
thead {
@media all and (max-width: 660px) {
display: none;
}
tr {
th {
background-color: $settings-table-header-bg;
color: $settings-table-header-color;
font-size: 16px;
font-weight: 600;
height: 50px;
line-height: 20px;
text-align: left;
@media (prefers-color-scheme: dark) {
background-color: $settings-table-header-bg-dark;
}
&:first-child {
border-top-left-radius: 10px;
}
&:last-child {
border-top-right-radius: 10px;
width: 240px;
text-align: center;
}
}
}
}
tbody {
@media all and (max-width: 660px) {
display: block;
}
tr {
@media all and (max-width: 660px) {
display: block;
margin-bottom: 10px;
}
&:last-of-type {
td {
border-bottom: 0;
&:first-of-type {
border-bottom-left-radius: 10px;
@media all and (max-width: 660px) {
border-bottom-left-radius: 0;
}
}
&:last-of-type {
border-bottom-right-radius: 10px;
}
&:first-of-type:last-of-type {
@media all and (max-width: 660px) {
border-bottom-left-radius: 10px;
}
}
}
}
td {
background-color: $settings-table-body-bg;
border-bottom: 1px solid $settings-table-border-color;
color: $color;
font-size: 14px;
font-weight: 400;
padding-bottom: 16px;
padding-top: 16px;
text-align: left;
@media (prefers-color-scheme: dark) {
background-color: $settings-table-body-bg-dark;
color: $color-2;
}
@media all and (max-width: 660px) {
border: 0;
display: flex;
flex-direction: row;
line-height: 21px;
padding: 0 10px;
&::before {
content: attr(data-before-i18n) ': ';
font-weight: 700;
margin-right: 5px;
text-align: left;
}
&:nth-of-type(1) {
border-radius: 10px 10px 0 0;
padding-top: 10px;
&:last-of-type {
padding: 10px;
}
}
&:nth-of-type(4) {
border-radius: 0 0 10px 10px;
padding-bottom: 10px;
}
}
}
}
}
th,
td {
padding-left: 22px;
padding-right: 22px;
&:nth-last-of-type(1),
&:nth-last-of-type(2) {
@media all and (max-width: 660px) {
padding-left: 10px;
padding-right: 10px;
}
}
}
td {
&:last-of-type {
text-align: center;
}
p {
color: $color;
font-size: 14px;
font-weight: 400;
line-height: 17px;
@media (prefers-color-scheme: dark) {
color: $color-2;
}
}
button {
border: 0;
background-color: transparent;
cursor: pointer;
padding: 0;
height: 21px;
width: 19px;
&:hover {
svg {
stroke: color.adjust($theme-color, $lightness: -10%);
}
}
svg {
stroke: $theme-color;
transition: .2s stroke ease-in-out;
}
}
}
}
&-exclude {
align-items: center;
display: inline-flex;
flex-direction: row;
&:hover {
.twofas-options-page-content-paired-devices-exclude-icon {
background-color: color.adjust($theme-color, $lightness: -10%);
}
.twofas-options-page-content-paired-devices-exclude-text {
color: color.adjust($theme-color, $lightness: -10%);
}
}
&-icon {
align-items: center;
background-color: $theme-color;
border-radius: 50%;
color: $add-icon-color;
display: flex;
height: 37px;
justify-content: center;
margin-right: 11px;
text-align: center;
transition: background-color .2s ease-in-out;
width: 37px;
svg {
display: inline-block;
height: 12px;
width: 12px;
}
}
&-text {
color: $theme-color;
font-size: 13px;
font-weight: 700;
letter-spacing: .8125px;
text-transform: uppercase;
transition: color .2s ease-in-out;
}
}
}
&-advanced {
margin-bottom: 20px;
margin-top: 40px;

View File

@ -20,7 +20,8 @@
@use "sass:color";
@import "src/global-styles/variables";
.twofas-options-modal {
.twofas-confirm-modal,
.twofas-domain-modal {
// VARIABLES
$modal-backdrop-color: rgba(#4f4f4f, .5);
$modal-backdrop-color-dark: rgba($color, .5);
@ -64,7 +65,8 @@
top: 0;
&:hover {
.twofas-options-modal-close-bg {
.twofas-confirm-modal-close-bg,
.twofas-domain-modal-close-bg {
fill: color.adjust($modal-close-bg, $lightness: -5%);
@media (prefers-color-scheme: dark) {
@ -72,7 +74,8 @@
}
}
.twofas-options-modal-close-x {
.twofas-confirm-modal-close-x,
.twofas-domain-modal-close-x {
fill: color.adjust($modal-close-x-color, $lightness: -10%);
}
}
@ -126,6 +129,47 @@
}
}
form {
display: flex;
flex-direction: column;
padding: 0 24px;
}
input {
background-color: $input-bg;
border: 0;
border-radius: 10px;
color: $input-color;
display: block;
flex-grow: 1;
font-size: 16px;
font-weight: 400;
height: 51px;
margin: 16px 0 0;
padding: 0 0 0 17px;
@media (prefers-color-scheme: dark) {
background-color: $bg-dark;
color: $input-color-dark;
}
@media all and (max-width: 660px) {
padding: 0 10px;
}
&::-webkit-input-placeholder { /* stylelint-disable-line */
color: $desc-color;
}
&::-moz-placeholder { /* stylelint-disable-line */
color: $desc-color;
}
&:-ms-input-placeholder { /* stylelint-disable-line */
color: $desc-color;
}
}
h2,
p {
margin: 0 auto;

View File

@ -35,12 +35,17 @@ const selectors = {
}
},
optionsPage: {
modal: {
element: '.js-twofas-options-modal',
cancel: '.js-twofas-options-modal-cancel',
confirm: '.js-twofas-options-modal-confirm',
header: '.js-twofas-options-modal-header',
text: '.js-twofas-options-modal-text'
confirmModal: {
element: '.js-twofas-confirm-modal',
cancel: '.js-twofas-confirm-modal-cancel',
confirm: '.js-twofas-confirm-modal-confirm',
header: '.js-twofas-confirm-modal-header',
text: '.js-twofas-confirm-modal-text'
},
domainModal: {
element: '.js-twofas-domain-modal',
cancel: '.js-twofas-domain-modal-cancel',
confirm: '.js-twofas-domain-modal-confirm'
},
shortcut: {
edit: '.js-twofas-shortcut-edit',
@ -68,6 +73,11 @@ const selectors = {
element: '.js-twofas-options-menu-hamburger',
content: '.js-twofas-options-menu-content'
},
autoSubmit: {
list: '.js-twofas-auto-submit-excluded-domain-list',
exclude: '.js-twofas-auto-submit-excluded-domain-exclude',
add: '.js-twofas-auto-submit-excluded-domain-add'
},
menuLink: '.js-twofas-menu-link',
extVersion: 'span.twofas-ext-version',
contextMenuInput: 'input#twofas-context-menu',

View File

@ -19,22 +19,22 @@
-->
<div class="twofas-options-modal hidden js-twofas-options-modal">
<div class="twofas-options-modal-body">
<button class="twofas-options-modal-close js-twofas-options-modal-cancel">
<div class="twofas-confirm-modal hidden js-twofas-confirm-modal">
<div class="twofas-confirm-modal-body">
<button class="twofas-confirm-modal-close js-twofas-confirm-modal-cancel">
<svg width="56" height="56" viewBox="0 0 56 56" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect class="twofas-options-modal-close-bg" width="56" height="56" />
<rect class="twofas-options-modal-close-x" x="16" y="18.1213" width="3" height="30" rx="1.5" transform="rotate(-45 16 18.1213)" />
<rect class="twofas-options-modal-close-x" x="37.2134" y="16" width="3" height="30" rx="1.5" transform="rotate(45 37.2134 16)" />
<rect class="twofas-confirm-modal-close-bg" width="56" height="56" />
<rect class="twofas-confirm-modal-close-x" x="16" y="18.1213" width="3" height="30" rx="1.5" transform="rotate(-45 16 18.1213)" />
<rect class="twofas-confirm-modal-close-x" x="37.2134" y="16" width="3" height="30" rx="1.5" transform="rotate(45 37.2134 16)" />
</svg>
</button>
<h2 class="js-twofas-options-modal-header"></h2>
<p class="js-twofas-options-modal-text"></p>
<h2 class="js-twofas-confirm-modal-header"></h2>
<p class="js-twofas-confirm-modal-text"></p>
<div class="twofas-options-modal-body-buttons">
<button data-i18n="yes" class="btn btn-clear js-twofas-options-modal-confirm">Yes</button>
<button data-i18n="cancel" class="btn btn-theme js-twofas-options-modal-cancel">Cancel</button>
<div class="twofas-confirm-modal-body-buttons">
<button data-i18n="yes" class="btn btn-clear js-twofas-confirm-modal-confirm">Yes</button>
<button data-i18n="cancel" class="btn btn-theme js-twofas-confirm-modal-cancel">Cancel</button>
</div>
</div>
</div>

View File

@ -0,0 +1,50 @@
<!--
This file is part of the 2FAS Browser Extension (https://github.com/twofas/2fas-browser-extension)
Copyright © 2023 Two Factor Authentication Service, Inc.
Contributed by Grzegorz Zając. All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>
-->
<div class="twofas-domain-modal hidden js-twofas-domain-modal">
<div class="twofas-domain-modal-body">
<button class="twofas-domain-modal-close js-twofas-domain-modal-cancel">
<svg width="56" height="56" viewBox="0 0 56 56" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect class="twofas-domain-modal-close-bg" width="56" height="56" />
<rect class="twofas-domain-modal-close-x" x="16" y="18.1213" width="3" height="30" rx="1.5" transform="rotate(-45 16 18.1213)" />
<rect class="twofas-domain-modal-close-x" x="37.2134" y="16" width="3" height="30" rx="1.5" transform="rotate(45 37.2134 16)" />
</svg>
</button>
<h2 data-i18n="optionsDomainModalHeader">Exclude new domain</h2>
<p data-i18n="optionsDomainModalText">With the form below, you can add your domain to exclusion list, ensuring it won't be subjected to the auto submit mechanism.</p>
<form action="#">
<input
data-i18n="optionsDomainInputPlaceholder"
class="js-twofas-domain-input"
type="text"
name="domain"
placeholder="Type in domain to exclude..."
/>
<div class="twofas-domain-modal-body-buttons">
<button type="submit" data-i18n="add" class="btn btn-clear js-twofas-domain-modal-confirm">Add</button>
<button data-i18n="cancel" class="btn btn-theme js-twofas-domain-modal-cancel">Cancel</button>
</div>
</form>
</div>
</div>