Support 'System' theme setting (#91)

This commit is contained in:
Alex Ling 2020-07-19 10:43:55 +00:00
parent 6acfa02314
commit 87b72fbd30
7 changed files with 126 additions and 72 deletions

View File

@ -30,18 +30,18 @@
cursor: pointer; cursor: pointer;
} }
.uk-list li { .uk-list li:not(.nopointer) {
cursor: pointer; cursor: pointer;
} }
.reader-bg {
background-color: black;
}
#scan-status { #scan-status {
cursor: auto; cursor: auto;
} }
.reader-bg {
background-color: black;
}
.break-word { .break-word {
word-wrap: break-word; word-wrap: break-word;
} }

View File

@ -1,13 +1,14 @@
var scanning = false; let scanning = false;
function scan() {
const scan = () => {
scanning = true; scanning = true;
$('#scan-status > div').removeAttr('hidden'); $('#scan-status > div').removeAttr('hidden');
$('#scan-status > span').attr('hidden', ''); $('#scan-status > span').attr('hidden', '');
var color = $('#scan').css('color'); const color = $('#scan').css('color');
$('#scan').css('color', 'gray'); $('#scan').css('color', 'gray');
$.post(base_url + 'api/admin/scan', function (data) { $.post(base_url + 'api/admin/scan', (data) => {
var ms = data.milliseconds; const ms = data.milliseconds;
var titles = data.titles; const titles = data.titles;
$('#scan-status > span').text('Scanned ' + titles + ' titles in ' + ms + 'ms'); $('#scan-status > span').text('Scanned ' + titles + ' titles in ' + ms + 'ms');
$('#scan-status > span').removeAttr('hidden'); $('#scan-status > span').removeAttr('hidden');
$('#scan').css('color', color); $('#scan').css('color', color);
@ -15,11 +16,25 @@ function scan() {
scanning = false; scanning = false;
}); });
} }
$(function() {
$('li').click(function() { String.prototype.capitalize = function() {
url = $(this).attr('data-url'); return this.charAt(0).toUpperCase() + this.slice(1);
}
$(() => {
$('li').click((e) => {
const url = $(e.currentTarget).attr('data-url');
if (url) { if (url) {
$(location).attr('href', url); $(location).attr('href', url);
} }
}); });
const setting = loadThemeSetting();
$('#theme-select').val(setting.capitalize());
$('#theme-select').change((e) => {
const newSetting = $(e.currentTarget).val().toLowerCase();
saveThemeSetting(newSetting);
setTheme();
});
}); });

View File

@ -32,32 +32,34 @@ const download = () => {
const chapters = globalChapters.filter(c => ids.indexOf(c.id) >= 0); const chapters = globalChapters.filter(c => ids.indexOf(c.id) >= 0);
console.log(ids); console.log(ids);
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: base_url + 'api/admin/mangadex/download', url: base_url + 'api/admin/mangadex/download',
data: JSON.stringify({chapters: chapters}), data: JSON.stringify({
contentType: "application/json", chapters: chapters
dataType: 'json' }),
}) contentType: "application/json",
.done(data => { dataType: 'json'
console.log(data); })
if (data.error) { .done(data => {
alert('danger', `Failed to add chapters to the download queue. Error: ${data.error}`); console.log(data);
return; if (data.error) {
} alert('danger', `Failed to add chapters to the download queue. Error: ${data.error}`);
const successCount = parseInt(data.success); return;
const failCount = parseInt(data.fail); }
UIkit.modal.confirm(`${successCount} of ${successCount + failCount} chapters added to the download queue. Proceed to the download manager?`).then(() => { const successCount = parseInt(data.success);
window.location.href = base_url + 'admin/downloads'; const failCount = parseInt(data.fail);
UIkit.modal.confirm(`${successCount} of ${successCount + failCount} chapters added to the download queue. Proceed to the download manager?`).then(() => {
window.location.href = base_url + 'admin/downloads';
});
styleModal();
})
.fail((jqXHR, status) => {
alert('danger', `Failed to add chapters to the download queue. Error: [${jqXHR.status}] ${jqXHR.statusText}`);
})
.always(() => {
$('#download-spinner').attr('hidden', '');
$('#download-btn').removeAttr('hidden');
}); });
styleModal();
})
.fail((jqXHR, status) => {
alert('danger', `Failed to add chapters to the download queue. Error: [${jqXHR.status}] ${jqXHR.statusText}`);
})
.always(() => {
$('#download-spinner').attr('hidden', '');
$('#download-btn').removeAttr('hidden');
});
}); });
styleModal(); styleModal();
}; };
@ -66,8 +68,7 @@ const toggleSpinner = () => {
if (attr) { if (attr) {
$('#spinner').removeAttr('hidden'); $('#spinner').removeAttr('hidden');
$('#search-btn').attr('hidden', ''); $('#search-btn').attr('hidden', '');
} } else {
else {
$('#search-btn').removeAttr('hidden'); $('#search-btn').removeAttr('hidden');
$('#spinner').attr('hidden', ''); $('#spinner').attr('hidden', '');
} }
@ -98,8 +99,7 @@ const search = () => {
const path = new URL(input).pathname; const path = new URL(input).pathname;
const match = /\/title\/([0-9]+)/.exec(path); const match = /\/title\/([0-9]+)/.exec(path);
int_id = parseInt(match[1]); int_id = parseInt(match[1]);
} } catch (e) {
catch(e) {
int_id = parseInt(input); int_id = parseInt(input);
} }
@ -139,8 +139,12 @@ const search = () => {
const comp = (a, b) => { const comp = (a, b) => {
var ai; var ai;
var bi; var bi;
try {ai = parseFloat(a);} catch(e) {} try {
try {bi = parseFloat(b);} catch(e) {} ai = parseFloat(a);
} catch (e) {}
try {
bi = parseFloat(b);
} catch (e) {}
if (typeof ai === 'undefined') return -1; if (typeof ai === 'undefined') return -1;
if (typeof bi === 'undefined') return 1; if (typeof bi === 'undefined') return 1;
if (ai < bi) return 1; if (ai < bi) return 1;
@ -176,8 +180,7 @@ const parseRange = str => {
if (!matches) { if (!matches) {
alert('danger', `Failed to parse filter input ${str}`); alert('danger', `Failed to parse filter input ${str}`);
return [null, null]; return [null, null];
} } else if (typeof matches[1] !== 'undefined' && typeof matches[2] !== 'undefined') {
else if (typeof matches[1] !== 'undefined' && typeof matches[2] !== 'undefined') {
// e.g., <= 30 // e.g., <= 30
num = parseInt(matches[2]); num = parseInt(matches[2]);
if (isNaN(num)) { if (isNaN(num)) {
@ -194,8 +197,7 @@ const parseRange = str => {
case '>=': case '>=':
return [num, null]; return [num, null];
} }
} } else if (typeof matches[3] !== 'undefined') {
else if (typeof matches[3] !== 'undefined') {
// a single number // a single number
num = parseInt(matches[3]); num = parseInt(matches[3]);
if (isNaN(num)) { if (isNaN(num)) {
@ -203,8 +205,7 @@ const parseRange = str => {
return [null, null]; return [null, null];
} }
return [num, num]; return [num, num];
} } else if (typeof matches[4] !== 'undefined' && typeof matches[5] !== 'undefined') {
else if (typeof matches[4] !== 'undefined' && typeof matches[5] !== 'undefined') {
// e.g., 10 - 23 // e.g., 10 - 23
num = parseInt(matches[4]); num = parseInt(matches[4]);
const n2 = parseInt(matches[5]); const n2 = parseInt(matches[5]);
@ -213,8 +214,7 @@ const parseRange = str => {
return [null, null]; return [null, null];
} }
return [num, n2]; return [num, n2];
} } else {
else {
// empty or space only // empty or space only
return [null, null]; return [null, null];
} }
@ -280,7 +280,7 @@ const buildTable = () => {
const group_str = Object.entries(chp.groups).map(([k, v]) => { const group_str = Object.entries(chp.groups).map(([k, v]) => {
return `<a href="${baseURL }/group/${v}">${k}</a>`; return `<a href="${baseURL }/group/${v}">${k}</a>`;
}).join(' | '); }).join(' | ');
const dark = getTheme() === 'dark' ? 'dark' : ''; const dark = loadTheme() === 'dark' ? 'dark' : '';
return `<tr class="ui-widget-content ${dark}"> return `<tr class="ui-widget-content ${dark}">
<td><a href="${baseURL}/chapter/${chp.id}">${chp.id}</a></td> <td><a href="${baseURL}/chapter/${chp.id}">${chp.id}</a></td>
<td>${chp.title}</td> <td>${chp.title}</td>
@ -302,7 +302,7 @@ const buildTable = () => {
}; };
const unescapeHTML = (str) => { const unescapeHTML = (str) => {
var elt = document.createElement("span"); var elt = document.createElement("span");
elt.innerHTML = str; elt.innerHTML = str;
return elt.innerText; return elt.innerText;
}; };

View File

@ -1,22 +1,44 @@
const getTheme = () => { // https://flaviocopes.com/javascript-detect-dark-mode/
var theme = localStorage.getItem('theme'); const preferDarkMode = () => {
if (!theme) theme = 'light'; return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
return theme;
}; };
const saveTheme = theme => { const validThemeSetting = (theme) => {
localStorage.setItem('theme', theme); return ['dark', 'light', 'system'].indexOf(theme) >= 0;
}; };
// dark / light / system
const loadThemeSetting = () => {
let str = localStorage.getItem('theme');
if (!str || !validThemeSetting(str)) str = 'light';
return str;
};
// dark / light
const loadTheme = () => {
let setting = loadThemeSetting();
if (setting === 'system') {
setting = preferDarkMode() ? 'dark' : 'light';
}
return setting;
};
const saveThemeSetting = setting => {
if (!validThemeSetting(setting)) setting = 'light';
localStorage.setItem('theme', setting);
};
// when toggled, Auto will be changed to light or dark
const toggleTheme = () => { const toggleTheme = () => {
const theme = getTheme(); const theme = loadTheme();
const newTheme = theme === 'dark' ? 'light' : 'dark'; const newTheme = theme === 'dark' ? 'light' : 'dark';
saveThemeSetting(newTheme);
setTheme(newTheme); setTheme(newTheme);
saveTheme(newTheme);
}; };
const setTheme = themeStr => { const setTheme = (theme) => {
if (themeStr === 'dark') { if (!theme) theme = loadTheme();
if (theme === 'dark') {
$('html').css('background', 'rgb(20, 20, 20)'); $('html').css('background', 'rgb(20, 20, 20)');
$('body').addClass('uk-light'); $('body').addClass('uk-light');
$('.uk-card').addClass('uk-card-secondary'); $('.uk-card').addClass('uk-card-secondary');
@ -32,7 +54,7 @@ const setTheme = themeStr => {
}; };
const styleModal = () => { const styleModal = () => {
const color = getTheme() === 'dark' ? '#222' : ''; const color = loadTheme() === 'dark' ? '#222' : '';
$('.uk-modal-header').css('background', color); $('.uk-modal-header').css('background', color);
$('.uk-modal-body').css('background', color); $('.uk-modal-body').css('background', color);
$('.uk-modal-footer').css('background', color); $('.uk-modal-footer').css('background', color);
@ -40,9 +62,18 @@ const styleModal = () => {
// do it before document is ready to prevent the initial flash of white on // do it before document is ready to prevent the initial flash of white on
// most pages // most pages
setTheme(getTheme()); setTheme();
$(() => { $(() => {
// hack for the reader page // hack for the reader page
setTheme(getTheme()); setTheme();
// on system dark mode setting change
if (window.matchMedia) {
window.matchMedia('(prefers-color-scheme: dark)')
.addEventListener('change', event => {
if (loadThemeSetting() === 'system')
setTheme(event.matches ? 'dark' : 'light');
});
}
}); });

View File

@ -7,6 +7,14 @@
<span hidden></span> <span hidden></span>
</span> </span>
</li> </li>
<li class="nopointer">
<span>Theme</span>
<select id="theme-select" class="uk-select uk-align-right uk-width-1-3@m uk-width-1-2">
<option>Dark</option>
<option>Light</option>
<option>System</option>
</select>
</li>
<li data-url="<%= base_url %>admin/downloads">Download Manager</li> <li data-url="<%= base_url %>admin/downloads">Download Manager</li>
</ul> </ul>

View File

@ -56,7 +56,7 @@
</div> </div>
</div> </div>
<script> <script>
setTheme(getTheme()); setTheme();
const base_url = "<%= base_url %>"; const base_url = "<%= base_url %>";
</script> </script>
<script src="https://cdn.jsdelivr.net/npm/uikit@3.3.1/dist/js/uikit.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/uikit@3.3.1/dist/js/uikit.min.js"></script>

View File

@ -27,7 +27,7 @@
</div> </div>
</div> </div>
<script> <script>
setTheme(getTheme()); setTheme();
</script> </script>
<script src="https://cdn.jsdelivr.net/npm/uikit@3.3.1/dist/js/uikit.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/uikit@3.3.1/dist/js/uikit.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/uikit@3.3.1/dist/js/uikit-icons.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/uikit@3.3.1/dist/js/uikit-icons.min.js"></script>