Merge pull request #758 from keepassxreboot/feature/dark_theme

Add dark theme
This commit is contained in:
Sami Vänttinen 2020-01-28 11:28:38 +02:00 committed by GitHub
commit b01ab1e835
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 383 additions and 23 deletions

View file

@ -643,6 +643,26 @@
"message": "never",
"description": "Radio button text."
},
"optionsThemeSelectionHeader": {
"message": "Color theme",
"description": "Theme selection header text."
},
"optionsThemeSelection": {
"message": "Select color theme",
"description": "Theme selection title text."
},
"optionsThemeSystem": {
"message": "System",
"description": "System theme text."
},
"optionsThemeDark": {
"message": "Dark",
"description": "Dark theme text."
},
"optionsThemeLight": {
"message": "Light",
"description": "Light theme text."
},
"optionsKeyboardShortcutsHeader": {
"message": "Keyboard shortcuts",
"description": "Keyboard shortcut header text."

View file

@ -230,12 +230,16 @@ kpxcEvent.onUsernameFieldDetected = function(tab, detected) {
kpxcEvent.passwordGetFilled = async function() {
return page.passwordFilled;
}
};
kpxcEvent.passwordSetFilled = function(tab, state) {
page.passwordFilled = state;
return Promise.resolve();
}
};
kpxcEvent.getColorTheme = async function(tab) {
return page.settings.colorTheme;
};
// All methods named in this object have to be declared BEFORE this!
kpxcEvent.messageHandlers = {
@ -247,6 +251,7 @@ kpxcEvent.messageHandlers = {
'enable_automatic_reconnect': keepass.enableAutomaticReconnect,
'disable_automatic_reconnect': keepass.disableAutomaticReconnect,
'generate_password': keepass.generatePassword,
'get_color_theme': kpxcEvent.getColorTheme,
'get_connected_database': kpxcEvent.onGetConnectedDatabase,
'get_database_hash': keepass.getDatabaseHash,
'get_database_groups': keepass.getDatabaseGroups,

View file

@ -16,7 +16,8 @@ const defaultSettings = {
saveDomainOnlyNewCreds: false,
autoReconnect: false,
defaultGroup: '',
defaultGroupAlwaysAsk: false
defaultGroupAlwaysAsk: false,
colorTheme: 'system'
};
var page = {};
@ -82,6 +83,9 @@ page.initSettings = async function() {
if (!('defaultGroupAlwaysAsk' in page.settings)) {
page.settings.defaultGroupAlwaysAsk = defaultSettings.defaultGroupAlwaysAsk;
}
if (!('colorTheme' in page.settings)) {
page.settings.colorTheme = defaultSettings.colorTheme;
}
await browser.storage.local.set({ 'settings': page.settings });
return page.settings;

View file

@ -38,6 +38,7 @@ kpxcAutocomplete.showList = function(inputField) {
const div = kpxcUI.createElement('div', 'kpxcAutocomplete-items', { 'id': 'kpxcAutocomplete-list' });
kpxcAutocomplete.updatePosition(inputField, div);
div.style.zIndex = '2147483646';
initColorTheme(div);
document.body.append(div);
for (const c of kpxcAutocomplete.elements) {

View file

@ -116,6 +116,8 @@ kpxcBanner.create = async function(credentials = {}) {
bannerInfo.appendMultiple(icon, infoText, usernameText, usernameSpan);
bannerButtons.appendMultiple(newButton, updateButton, separator, ignoreCheckbox, checkboxLabel, dismissButton);
banner.appendMultiple(bannerInfo, bannerButtons);
initColorTheme(banner);
document.body.appendChild(banner);
};
@ -365,6 +367,7 @@ kpxcBanner.createCredentialDialog = async function() {
usernameNew.append(kpxcUI.createElement('span', 'strong'));
usernameExists.append(kpxcUI.createElement('span', 'strong'));
dialog.appendMultiple(databaseText, usernameNew, usernameExists, chooseCreds, list);
initColorTheme(dialog);
document.body.appendChild(dialog);
};

View file

@ -219,6 +219,7 @@ kpxcPasswordDialog.showDialog = function(field, icon) {
}
kpxcPasswordDialog.createDialog();
initColorTheme(kpxcPasswordDialog.dialog);
kpxcPasswordDialog.openDialog();
// Adjust the dialog location

View file

@ -155,6 +155,17 @@ const DOMRectToArray = function(domRect) {
return [ domRect.bottom, domRect.height, domRect.left, domRect.right, domRect.top, domRect.width, domRect.x, domRect.y ];
};
const initColorTheme = function(elem) {
const colorTheme = kpxc.settings['colorTheme'];
if (colorTheme === undefined || colorTheme === 'system') {
elem.removeAttribute('data-color-theme');
} else {
elem.setAttribute('data-color-theme', colorTheme);
}
};
// Enables dragging
document.addEventListener('mousemove', function(e) {
if (kpxcPasswordDialog.selected === kpxcPasswordDialog.titleBar) {

View file

@ -5,12 +5,12 @@
.kpxcAutocomplete-items div {
padding: 5px;
cursor: pointer;
background-color: #fff;
background-color: var(--background-color);
border-bottom: 1px solid #d4d4d4;
border-left: 1px solid #d4d4d4;
border-right: 1px solid #d4d4d4;
width: auto;
color: #000;
color: var(--text-color);
font-size: .9em !important;
}
@ -27,5 +27,18 @@
.kpxcAutocomplete-active {
background-color: #6cac4d !important;
color: #ffffff !important;
border: 0px !important;
}
@media (prefers-color-scheme: dark) {
.kpxcAutocomplete-items {
background: var(--background-color);
color: var(--text-color);
}
.kpxc-pwgen-input {
background-color: var(--input-background-color) !important;
border: var(--input-border);
border-color: var(--input-border-color);
color: var(--text-color) !important;
}
}

View file

@ -1,11 +1,11 @@
div.kpxc-banner {
animation-duration: 0.2s;
animation-name: slidein;
background-color: #ffffff;
background-color: var(--background-color);
border-bottom: 1px solid #38383d !important;
box-shadow: 0 4px 6px 0 hsla(0, 0%, 0%, 0.2) !important;
box-sizing: border-box !important;
color: #000000 !important;
color: var(--text-color) !important;
font-family: sans-serif !important;
font-size: 1em !important;
height: auto !important;
@ -89,8 +89,9 @@ div.kpxc-banner-dialog {
width: 680px;
max-height: 600px;
max-width: 460px;
background-color: white;
border: 1px solid #ccc;
background-color: var(--background-color);
color: var(--text-color);
border: var(--container-border);
border-radius: 0 0 4px 4px;
box-shadow: 0 4px 6px 0 hsla(0, 0%, 0%, 0.2);
padding: 8px;
@ -114,7 +115,7 @@ div.kpxc-banner-dialog .list-group {
div.kpxc-banner-dialog .list-group-item {
border: 1px solid #ddd !important;
color: #000 !important;
color: var(--text-color) !important;
display: block !important;
padding: 5px 10px;
position: relative !important;
@ -133,6 +134,23 @@ div.kpxc-banner-dialog .list-group-item:last-child {
}
div.kpxc-banner-dialog .list-group-item:hover {
cursor: pointer !important;;
cursor: pointer !important;
background-color: #eee !important;
}
@media (prefers-color-scheme: dark) {
div.kpxc-banner, div.kpxc-banner-dialog {
background-color: var(--input-background-color) !important;
color: var(--text-color) !important;
}
div.kpxc-banner-dialog .list-group-item:hover {
background-color: var(--table-hover-color) !important;
color: #000;
}
div.kpxc-banner-dialog .list-group-item {
background-color: var(--input-background-color) !important;
color: var(--text-color) !important;
}
}

View file

@ -0,0 +1,54 @@
:root {
--background-color: #fff;
--container-border: 1px solid #ccc;
--input-active-border-color: #2b4d1a;
--input-background-color: #fff;
--input-border: 1px solid #2b4d1a;
--input-border-color: #292a2a;
--link-color: #6cac4d;
--link-hover-color: #3a8233;
--table-hover-color: #f9f9f9;
--text-color: #000;
}
@media (prefers-color-scheme: dark) {
:root {
--background-color: #3b3d3c;
--container-border: 1px solid #000;
--input-active-border-color: #2b4d1a;
--input-background-color: #2f2f2f;
--input-border: 1px solid #2b4d1a;
--input-border-color: #292a2a;
--link-color: #8c8c8b;
--link-hover-color: #3a8233;
--table-hover-color: #474948;
--text-color: #cbcfcb;
}
}
/* Same colors for manual switching */
[data-color-theme='dark'] {
--background-color: #3b3d3c;
--container-border: 1px solid #000;
--input-active-border-color: #2b4d1a;
--input-background-color: #2f2f2f;
--input-border: 1px solid #2b4d1a;
--input-border-color: #292a2a;
--link-color: #8c8c8b;
--link-hover-color: #3a8233;
--table-hover-color: #474948;
--text-color: #cbcfcb;
}
[data-color-theme='light'] {
--background-color: #fff;
--container-border: 1px solid #ccc;
--input-active-border-color: #2b4d1a;
--input-background-color: #fff;
--input-border: 1px solid #2b4d1a;
--input-border-color: #292a2a;
--link-color: #6cac4d;
--link-hover-color: #3a8233;
--table-hover-color: #f9f9f9;
--text-color: #000;
}

View file

@ -1,8 +1,9 @@
.kpxc-pwgen-dialog {
background-color: white;
background-color: var(--background-color);
border: 1px solid #ccc;
border-radius: 4px;
box-shadow: 0 4px 6px 0 hsla(0, 0%, 0%, 0.2);
color: var(--text-color);
font-family: 'Lato', sans-serif !important;
min-height: 80px;
padding: .1em .2em .1em .2em;
@ -56,7 +57,7 @@
.kpxc-pwgen-input {
background: none !important;
border-radius: 4px !important;
color: #000 !important;
color: var(--text-color) !important;
font-size: 12px !important;
font-weight: normal !important;
height: auto !important;
@ -70,7 +71,7 @@
}
.kpxc #kpxc-pwgen-error {
color: #000;
color: var(--text-color);
font-size: 12px !important;
font-style: normal !important;
font-weight: normal !important;
@ -92,3 +93,21 @@
background: url('moz-extension://__MSG_@@extension_id__/icons/key.svg') right no-repeat;
background-size: contain;
}
@media (prefers-color-scheme: dark) {
.kpxc-pwgen-dialog {
background: var(--background-color) !important;
color: var(--text-color) !important;
}
.kpxc-pwgen-input {
background-color: var(--input-background-color) !important;
border: var(--input-border);
border-color: var(--input-border-color);
color: var(--text-color) !important;
}
.kpxc #kpxc-pwgen-error {
color: var(--text-color) !important;
}
}

View file

@ -65,6 +65,7 @@
"css/autocomplete.css",
"css/banner.css",
"css/button.css",
"css/colors.css",
"css/define.css",
"css/notification.css",
"css/pwgen.css",
@ -128,7 +129,7 @@
"applications": {
"gecko": {
"id": "keepassxc-browser@keepassxc.org",
"strict_min_version": "52.0"
"strict_min_version": "67.0"
}
},
"default_locale": "en"

File diff suppressed because one or more lines are too long

View file

@ -7,6 +7,11 @@ table td {
width: 100%;
}
input {
background-color: var(--input-background-color);
border: 1px solid #292a2a;
}
input:invalid {
border: 2px solid red;
}
@ -16,6 +21,7 @@ input:invalid {
margin: 0 auto;
max-width: 1000px;
}
.container > hr {
margin: 30px 0;
}
@ -25,59 +31,72 @@ input:invalid {
font-family: 'Lato',sans-serif;
background-color: #6cac4d;
border: 0px;
box-shadow: 0 2px 6px 0;
box-shadow: 0 0px 2px 0;
display: inline-block;
float: none;
width: 100%;
}
.navbar-default .navbar-brand {
color: #ffffff;
}
.navbar-default .navbar-brand:hover,
.navbar-default .navbar-brand:focus {
color: #ffffff;
}
.navbar-default .navbar-text {
color: #ffffff;
}
.navbar-default .navbar-nav > li > a {
color: #ffffff;
text-align: center;
}
.navbar-default .navbar-nav > li > a:hover,
.navbar-default .navbar-nav > li > a:focus {
color: #ffffff;
background-color: #5f9f40;
}
.navbar-default .navbar-nav > .active > a,
.navbar-default .navbar-nav > .active > a:hover,
.navbar-default .navbar-nav > .active > a:focus {
color: #ffffff;
background-color: #3a8233;
}
.navbar-default .navbar-nav > .open > a,
.navbar-default .navbar-nav > .open > a:hover,
.navbar-default .navbar-nav > .open > a:focus {
color: #ffffff;
background-color: #3a8233;
}
.navbar-default .navbar-toggle {
border-color: #3a8233;
}
.navbar-default .navbar-toggle:hover,
.navbar-default .navbar-toggle:focus {
background-color: #3a8233;
}
.navbar-default .navbar-toggle .icon-bar {
background-color: #ffffff;
}
.navbar-default .navbar-collapse,
.navbar-default .navbar-form {
border-color: #ffffff;
}
.navbar-default .navbar-link {
color: #ffffff;
}
.navbar-default .navbar-link:hover {
color: #ffffff;
}
@ -167,3 +186,69 @@ td.created {
.panel-group .panel-default .panel-heading {
background-color: #fff !important;
}
@media (prefers-color-scheme: dark), (prefers-color-scheme: light) {
a {
color: var(--link-color);
text-decoration: none;
}
a:hover {
color: var(--link-hover-color);
text-decoration: none;
}
.bg-danger {
color: #000;
}
body, pre {
background: var(--background-color);
color: var(--text-color);
}
input, input[type="checkbox"] {
background-color: var(--input-background-color);
border-color: var(--input-border-color);
}
input:active {
border-color: var(--input-active-border-color);
}
.modal-content {
background: var(--background-color);
color: var(--text-color);
}
.navbar-default {
box-shadow: 0 0px 2px 0;
}
select {
background-color: var(--input-background-color);
color: var(--text-color);
}
select option {
background-color: var(--input-background-color);
color: var(--text-color);
}
select hover {
background: var(--background-color);
color: var(--text-color);
}
.table > caption {
color: var(--text-color);
}
.table-striped > tbody > tr:nth-of-type(odd) {
background-color: var(--table-hover-color);
}
.table-striped > tbody > tr:hover {
background-color: var(--table-hover-color);
}
}

View file

@ -3,6 +3,7 @@
<head>
<title data-i18n="optionsTitle"></title>
<meta charset="UTF-8">
<link rel="stylesheet" href="../css/colors.css" />
<link rel="stylesheet" href="bootstrap.min.css" />
<link rel="stylesheet" href="options.css" />
<script src="../browser-polyfill.min.js"></script>
@ -30,6 +31,13 @@
<div class="tab" id="tab-general-settings">
<h2 data-i18n="optionsGeneralSettingsTab"></h2>
<hr />
<h3 data-i18n="optionsThemeSelectionHeader"></h3>
<select id="colorTheme" data-i18n="[title]optionsThemeSelection">
<option value="system" data-i18n="optionsThemeSystem"></option>
<option value="dark" data-i18n="optionsThemeDark"></option>
<option value="light" data-i18n="optionsThemeLight"></option>
</select>
<hr />
<h3 data-i18n="optionsKeyboardShortcutsHeader"></h3>
<p>
<span data-i18n="contextMenuFillUsernameAndPassword"></span>: <span id="fill_username_password-shortcut">error</span><br />

View file

@ -17,6 +17,7 @@ $(async function() {
options.initCustomCredentialFields();
options.initSitePreferences();
options.initAbout();
options.initTheme();
} catch (err) {
console.log('Error loading options page: ' + err);
}
@ -76,6 +77,18 @@ options.saveKeyRing = async function() {
};
options.initGeneralSettings = function() {
if (options.settings['colorTheme'] === undefined) {
$('#tab-general-settings select#colorTheme').val('system');
} else {
$('#tab-general-settings select#colorTheme').val(options.settings['colorTheme']);
}
$('#tab-general-settings select:first').change(function() {
options.settings['colorTheme'] = $(this).val();
options.saveSettings();
location.reload();
});
$('#tab-general-settings input[type=checkbox]').each(function() {
$(this).attr('checked', options.settings[$(this).attr('name')]);
if ($(this).attr('name') === 'defaultGroupAlwaysAsk' && $(this).attr('checked')) {
@ -523,6 +536,14 @@ options.initAbout = function() {
}
};
options.initTheme = function() {
if (options.settings['colorTheme'] === undefined) {
document.body.removeAttribute('data-color-theme');
} else {
document.body.setAttribute('data-color-theme', options.settings['colorTheme']);
}
};
options.createWarning = function(elem, text) {
const banner = document.createElement('div');
banner.classList.add('alert', 'alert-dismissible', 'alert-danger', 'fade', 'in');

View file

@ -6,8 +6,8 @@ body {
margin: 0 auto;
width: 680px;
max-height: 315px;
background-color: white;
border: 1px solid #ccc;
background-color: var(--background-color);
border: var(--container-border);
border-radius: 4px;
box-shadow: 0 4px 6px 0 hsla(0, 0%, 0%, 0.2);
}
@ -50,4 +50,31 @@ body {
box-shadow: 0 4px 6px 0 hsla(0, 0%, 0%, 0.2);
margin: 20px auto;
width: 680px;
}
}
@media (prefers-color-scheme: dark) {
.bg-danger {
color: #000;
}
body {
background: var(--input-background-color) !important;
color: var(--text-color);
}
input {
background-color: var(--input-background-color);
border: var(--input-border);
border-color: var(--input-border-color);
}
input:active {
border-color: var(--input-active-border-color);
}
.conf-container {
background: var(--background-color);
border: var(--container-border);
color: var(--text-color);
}
}

View file

@ -2,6 +2,7 @@
<head>
<title data-i18n="popupTitle"></title>
<meta charset="UTF-8">
<link rel="stylesheet" href="../css/colors.css" />
<link rel="stylesheet" href="shortcuts.css" />
<link rel="stylesheet" href="../options/bootstrap.min.css" />
<script src="../browser-polyfill.min.js"></script>

View file

@ -1,18 +1,21 @@
body {
font-family: sans-serif;
overflow-x: hidden;
background-color: #eee;
background-color: var(--background-color) !important;
color: var(--text-color) !important;
font-size: 15px;
padding: 8px;
min-width: 440px;
max-width: 460px;
width: auto;
}
.container {
min-width: 440px;
max-width: 460px;
width: auto;
}
.loader {
animation: spin 2s linear infinite;
border: 4px solid #f3f3f3;
@ -23,19 +26,24 @@ body {
margin-right: 1em;
width: 1.4em;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.list-group {
font-size: .9em !important;
}
.list-group-item {
padding: 5px 10px !important;
}
.list-group-item:hover {
cursor: pointer;
cursor: pointer
}
.settings {
padding-bottom: 10px;
margin-bottom: 10px;
@ -43,29 +51,36 @@ body {
font-size: 90%;
text-align: left;
}
.settings label {
display: block;
}
.settings label input {
vertical-align: middle;
}
.settings .description {
margin-top: 3px;
font-size: 80%;
color: #787878;
}
#list {
padding-left: 0px;
}
#child {
border-top: 0px;
}
.small {
margin-top: 3px;
margin-left: 12px;
font-size: 80%;
color: #787878;
}
#update-available {
padding-top: 10px;
margin-top: 10px;
@ -74,14 +89,17 @@ body {
text-align: left;
display: none;
}
#update-available a:hover,
#update-available a:active {
text-decoration: underline;
}
#lock-database-button {
float: right;
height: 30px;
}
#login-filter {
outline: none;
border-radius: 4px;
@ -90,3 +108,30 @@ body {
padding: 2px 10px;
width: 100%;
}
@media (prefers-color-scheme: dark), (prefers-color-scheme: light) {
body {
background: var(--background-color) !important;
color: var(--text-color) !important;
}
input, input[type="checkbox"] {
background-color: var(--input-background-color) !important;
border: var(--input-border);
border-color: var(--input-border-color);
}
.list-group-item {
background-color: var(--input-background-color) !important;
color: var(--text-color) !important;
}
.list-group-item:hover {
background-color: var(--table-hover-color) !important;
}
span.bg-success {
background-color: var(--table-hover-color) !important;
color: var(--text-color) !important;
}
}

View file

@ -3,6 +3,7 @@
<head>
<title data-i18n="popupTitle"></title>
<meta charset="UTF-8">
<link rel="stylesheet" href="../css/colors.css" />
<link rel="stylesheet" href="popup.css" />
<link rel="stylesheet" href="../options/bootstrap.min.css" />
<script src="../browser-polyfill.min.js"></script>

View file

@ -51,6 +51,8 @@ const sendMessageToTab = async function(message) {
};
$(async () => {
await initColorTheme();
$('#connect-button').click(async () => {
await browser.runtime.sendMessage({
action: 'associate'

View file

@ -27,6 +27,19 @@ async function initSettings() {
}
async function initColorTheme() {
const colorTheme = await browser.runtime.sendMessage({
action: 'get_color_theme'
});
if (colorTheme === undefined || colorTheme === 'system') {
document.body.removeAttribute('data-color-theme');
} else {
document.body.setAttribute('data-color-theme', colorTheme);
}
};
$(async () => {
await initSettings();
updateAvailableResponse(await browser.runtime.sendMessage({

View file

@ -3,6 +3,7 @@
<head>
<title data-i18n="popupTitle"></title>
<meta charset="UTF-8">
<link rel="stylesheet" href="../css/colors.css" />
<link rel="stylesheet" href="popup.css" />
<link rel="stylesheet" href="../options/bootstrap.min.css" />
<script src="../browser-polyfill.min.js"></script>

View file

@ -7,6 +7,8 @@ const getLoginData = async () => {
};
$(async () => {
await initColorTheme();
const data = await getLoginData();
const ll = document.getElementById('login-list');
for (let i = 0; i < data.logins.length; ++i) {

View file

@ -3,6 +3,7 @@
<head>
<title data-i18n="popupTitle"></title>
<meta charset="UTF-8">
<link rel="stylesheet" href="../css/colors.css" />
<link rel="stylesheet" href="popup.css" />
<link rel="stylesheet" href="../options/bootstrap.min.css" />
<script src="../browser-polyfill.min.js"></script>

View file

@ -1,6 +1,8 @@
'use strict';
$(async () => {
await initColorTheme();
const global = await browser.runtime.getBackgroundPage();
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
if (tabs.length === 0) {

View file

@ -3,6 +3,7 @@
<head>
<title data-i18n="popupTitle"></title>
<meta charset="UTF-8">
<link rel="stylesheet" href="../css/colors.css" />
<link rel="stylesheet" href="popup.css" />
<link rel="stylesheet" href="../options/bootstrap.min.css" />
<script src="../browser-polyfill.min.js"></script>