Second pass to re-design the dashboard

Related commit:
- 453f5450b6

The changes in this commit are mostly related
to the "Filter lists" pane.

An eye icon has been added, which purpose is
to view the content of a list. Clicking on the
name of the list will toggle the list's
checkbox.
This commit is contained in:
Raymond Hill 2020-04-06 14:00:19 -04:00
parent 8629ae2961
commit a45a21f337
No known key found for this signature in database
GPG key ID: 25E1490B761470C2
11 changed files with 154 additions and 133 deletions

View file

@ -15,46 +15,53 @@
<div class="body">
<div id="cloudWidget" class="hide" data-cloud-entry="tpFiltersPane"></div>
<ul id="options" class="root">
<li><button id="buttonUpdate" class="custom important disabled" data-i18n="3pUpdateNow"></button>
<button id="buttonPurgeAll" class="custom disabled" data-i18n="3pPurgeAll"></button>
<button id="buttonApply" class="custom important disabled" data-i18n="3pApplyChanges"></button>
<li><input type="checkbox" id="autoUpdate"><label data-i18n="3pAutoUpdatePrompt1" for="autoUpdate"></label>&ensp;
<li><input type="checkbox" id="parseCosmeticFilters"><label data-i18n="3pParseAllABPHideFiltersPrompt1" for="parseCosmeticFilters"></label><button class="whatisthis"></button>
<div class="whatisthis-expandable para" data-i18n="3pParseAllABPHideFiltersInfo"></div>
<li><input type="checkbox" id="ignoreGenericCosmeticFilters"><label data-i18n="3pIgnoreGenericCosmeticFilters" for="ignoreGenericCosmeticFilters"></label><button class="whatisthis"></button>
<div class="whatisthis-expandable para" data-i18n="3pIgnoreGenericCosmeticFiltersInfo"></div>
</ul>
<ul class="root">
<li><span id="listsOfBlockedHostsPrompt"></span>
<ul id="lists"></ul>
</ul>
<div id="actions" class="root">
<button id="buttonApply" class="custom important disabled iconifiable" type="button" data-i18n-title="3pApplyChanges"><span class="fa">&#xf00c;</span><span data-i18n="3pApplyChanges"></span></button>
<button id="buttonUpdate" class="custom important disabled iconifiable" type="button" data-i18n-title="3pUpdateNow"><span class="fa">&#xf021;</span><span data-i18n="3pUpdateNow"></span></button>
<button id="buttonPurgeAll" class="custom disabled iconifiable" type="button" data-i18n-title="3pPurgeAll"><span class="fa">&#xf017;</span><span data-i18n="3pPurgeAll"></span></button>
</div>
<div>
<div class="entry"><input type="checkbox" id="autoUpdate"><label data-i18n="3pAutoUpdatePrompt1" for="autoUpdate"></label></div>
<div class="entry"><input type="checkbox" id="parseCosmeticFilters"><label data-i18n="3pParseAllABPHideFiltersPrompt1" for="parseCosmeticFilters"></label><button class="whatisthis"></button>
<div class="whatisthis-expandable para" data-i18n="3pParseAllABPHideFiltersInfo"></div>
</div>
<div class="entry"><input type="checkbox" id="ignoreGenericCosmeticFilters"><label data-i18n="3pIgnoreGenericCosmeticFilters" for="ignoreGenericCosmeticFilters"></label><button class="whatisthis"></button>
<div class="whatisthis-expandable para" data-i18n="3pIgnoreGenericCosmeticFiltersInfo"></div>
</div>
</div>
<div class="root">
<div><span id="listsOfBlockedHostsPrompt"></span>
<div id="lists"></div>
</div>
</div>
</div>
<div id="templates" style="display: none;">
<ul>
<li class="groupEntry"><span class="geDetails"><span class="geName"></span> <span class="geCount dim"></span></span>
<ul class="listEntries"></ul>
</li>
<li class="listEntry">
<input type="checkbox"><!--
--><a class="content" type="text/plain" target="_blank" href=""></a>&#8203;<!--
--><a class="fa support" href="" target="_blank">&#xf015;</a>&#8203;<!--
--><a class="fa remove" href="">&#xf014;</a>&#8203;<!--
--><a class="fa mustread" href="" target="_blank">&#xf05a;</a>&#8203;<!--
--><span class="fa status unsecure" title="http">&#xf13e;</span>&#8203;<!--
--><span class="counts dim"></span>&#8203;<!--
--><span class="fa status obsolete" data-i18n-title="3pExternalListObsolete">&#xf071;</span>&#8203;<!--
--><span class="fa status cache">&#xf017;</span>&#8203;<!--
--><span class="fa status updating" data-i18n-title="3pUpdating">&#xf110;</span>&#8203;<!--
--><span class="fa status failed" data-i18n-title="3pNetworkError">&#xf127;</span>
</li>
<li class="listEntry toImport"><input type="checkbox" id="importLists"><label for="importLists" data-i18n="3pImport"></label><!--
--><a class="fa info towiki" href="https://github.com/gorhill/uBlock/wiki/Filter-lists-from-around-the-web" target="_blank">&#xf05a;</a><!--
--><textarea id="externalLists" dir="ltr" spellcheck="false" placeholder="3pExternalListsHint"></textarea>
</ul>
<div class="groupEntry">
<span class="geDetails"><span class="geName"></span> <span class="geCount dim"></span></span>
<div class="listEntries"></div>
</div>
<div class="entry listEntry">
<label><input type="checkbox"><span class="listname"></span></label><!--
--><a class="fa content" href="" type="text/plain" target="_blank" data-i18n-title="3pViewContent">&#xf06e;</a><!--
--><a class="fa support" href="" target="_blank">&#xf015;</a><!--
--><span class="fa remove" href="">&#xf014;</span><!--
--><a class="fa mustread" href="" target="_blank">&#xf05a;</a><!--
--><span class="fa status unsecure" title="http">&#xf13e;</span><!--
--><span class="fa status obsolete" data-i18n-title="3pExternalListObsolete">&#xf071;</span><!--
--><span class="fa status cache">&#xf017;</span><!--
--><span class="fa status updating" data-i18n-title="3pUpdating">&#xf110;</span><!--
--><span class="fa status failed" data-i18n-title="3pNetworkError">&#xf127;</span><!--
--><span class="counts dim"></span>
</div>
<div class="listEntry toImport"><input type="checkbox" id="importLists"><label for="importLists" data-i18n="3pImport"></label><!--
--><a class="fa info towiki" href="https://github.com/gorhill/uBlock/wiki/Filter-lists-from-around-the-web" target="_blank">&#xf05a;</a><!--
--><textarea id="externalLists" dir="ltr" spellcheck="false" placeholder="3pExternalListsHint"></textarea>
</div>
</div>
<script src="js/vapi.js"></script>
<script src="js/vapi-common.js"></script>

View file

@ -459,6 +459,10 @@
"message":"Out of date.",
"description":"used as a tooltip for the out-of-date icon beside a list"
},
"3pViewContent":{
"message":"view content",
"description":"used as a tooltip for eye icon beside a list"
},
"3pLastUpdate":{
"message":"Last update: {{ago}}.\nClick to force an update.",
"description":"used as a tooltip for the clock icon beside a list"

View file

@ -1,32 +1,34 @@
@keyframes spin {
0% { transform: rotate(0deg); -webkit-transform: rotate(0deg); }
100% { transform: rotate(360deg); -webkit-transform: rotate(360deg); }
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
ul {
list-style-type: none;
padding-left: 1em;
padding-right: 0;
}
body[dir="rtl"] ul {
padding-left: 0;
padding-right: 1em;
}
ul.root {
body {
border: 0;
font: 14px/21px sans-serif;
margin: 0;
padding: 0;
}
.root {
background-color: white;
overflow: auto;
padding: 0.5em 0;
}
.entry {
align-items: center;
display: flex;
margin: 0.5em 0;
}
#actions {
position: sticky;
top: 0;
z-index: 10;
}
#options li {
margin-bottom: 0.5em;
}
#listsOfBlockedHostsPrompt {
cursor: pointer;
}
#listsOfBlockedHostsPrompt:before {
color: #888;
content: '\2212 ';
}
body.hideUnused #listsOfBlockedHostsPrompt:before {
content: '+ ';
}
#lists {
margin: 0.5em 0 0 0;
padding: 0;
@ -36,16 +38,25 @@ body.hideUnused #listsOfBlockedHostsPrompt:before {
padding: 0;
list-style-type: none;
}
#listsOfBlockedHostsPrompt::before,
.groupEntry:not([data-groupkey="user"]) .geDetails::before {
color: #888;
content: '\2212';
font-family: monospace;
font-size: large;
margin-inline-end: 0.25em;
-webkit-margin-end: 0.25em;
}
body.hideUnused #listsOfBlockedHostsPrompt::before,
.groupEntry.hideUnused:not([data-groupkey="user"]) .geDetails::before {
content: '+';
}
.groupEntry {
margin: 0.5em 0;
}
.groupEntry .geDetails {
cursor: pointer;
}
.groupEntry:not([data-groupkey="user"]) .geDetails:before {
color: #888;
content: '\2212 ';
}
.groupEntry.hideUnused:not([data-groupkey="user"]) .geDetails:before {
content: '+ ';
}
.groupEntry .geName {
pointer-events: none;
}
@ -57,9 +68,12 @@ body.hideUnused #listsOfBlockedHostsPrompt:before {
margin: 0.25em 0 0 0;
padding-left: 1em;
}
.listEntries {
margin-inline-start: 0.7em;
-webkit-margin-start: 0.7em;
}
.listEntry {
margin: 0 auto 0 auto;
padding: 0.2em 0;
margin: 0.5em 0;
white-space: nowrap;
}
.groupEntry:not([data-groupkey="user"]) .listEntry.unused {
@ -69,115 +83,113 @@ body.hideUnused #listsOfBlockedHostsPrompt:before {
margin-right: 0.5em;
unicode-bidi: embed;
}
.listEntry.toRemove > input[type="checkbox"] {
.listEntry input[type="checkbox"] {
margin-right: 0.5em;
}
.listEntry.toRemove input[type="checkbox"] {
visibility: hidden;
}
.listEntry.toRemove > a.content {
.listEntry.toRemove .listname {
text-decoration: line-through;
}
.listEntry > .fa {
.listEntry .fa {
color: inherit;
display: none;
font-size: 110%;
opacity: 0.5;
vertical-align: baseline;
}
.listEntry > a.towiki {
.listEntry .content {
display: inline-block;
}
.listEntry > a.fa:hover {
.listEntry a.towiki {
display: inline-block;
}
.listEntry a.fa:hover {
opacity: 1;
}
.listEntry.support > a.support {
display: inline-block;
}
.listEntry > a.remove,
.listEntry > a.remove:visited {
.listEntry .remove {
color: darkred;
cursor: pointer;
}
.listEntry.external > a.remove {
.listEntry.external .remove {
display: inline-block;
}
.listEntry.mustread > a.mustread {
.listEntry.mustread a.mustread {
display: inline-block;
}
.listEntry.mustread > a.mustread:hover {
.listEntry.mustread a.mustread:hover {
color: mediumblue;
}
.listEntry > .counts {
.listEntry .counts {
display: none;
font-size: smaller;
}
.listEntry > input[type="checkbox"]:checked ~ .counts {
.listEntry.checked .counts {
display: inline;
}
.dim {
opacity: 0.6;
}
#buttonApply {
display: initial;
position: fixed;
right: 1em;
z-index: 10;
}
body[dir=rtl] #buttonApply {
right: auto;
left: 1em;
}
#buttonApply.disabled {
display: none;
}
.listEntry span.status {
.listEntry .status {
color: #444;
cursor: default;
display: none;
}
.listEntry span.status:hover {
.listEntry .status:hover {
opacity: 1;
}
.listEntry span.unsecure {
.listEntry .unsecure {
color: darkred;
}
.listEntry.unsecure > input[type="checkbox"]:checked ~ span.unsecure {
.listEntry.checked.unsecure .unsecure {
display: inline-block;
}
.listEntry span.failed {
.listEntry .failed {
color: darkred;
}
.listEntry.failed span.failed {
.listEntry.failed .failed {
display: inline-block;
}
.listEntry span.cache {
.listEntry .cache {
cursor: pointer;
}
.listEntry.cached:not(.obsolete) > input[type="checkbox"]:checked ~ span.cache {
.listEntry.checked.cached:not(.obsolete) .cache {
display: inline-block;
}
.listEntry span.obsolete {
.listEntry .obsolete {
color: hsl(36, 100%, 40%);
}
body:not(.updating) .listEntry.obsolete > input[type="checkbox"]:checked ~ span.obsolete {
body:not(.updating) .listEntry.checked.obsolete .obsolete {
display: inline-block;
}
.listEntry span.updating {
.listEntry .updating {
transform-origin: 50% 46%;
}
body.updating .listEntry.obsolete > input[type="checkbox"]:checked ~ span.updating {
body.updating .listEntry.checked.obsolete .updating {
animation: spin 2s linear infinite;
display: inline-block;
}
.listEntry.toImport > input[type="checkbox"] ~ textarea {
.listEntry.toImport input[type="checkbox"] ~ textarea {
border: 1px solid #ccc;
box-sizing: border-box;
display: block;
font-size: smaller;
height: 6em;
margin-left: 2em;
resize: vertical;
visibility: hidden;
white-space: pre;
width: calc(100% - 4em);
width: 100%;
}
.listEntry.toImport > input[type="checkbox"]:checked ~ textarea {
.listEntry.toImport input[type="checkbox"]:checked ~ textarea {
visibility: visible;
}
@media (pointer: coarse) {
#dashboard-nav {
font: 16px/24px sans-serif;
}
}

View file

@ -72,7 +72,6 @@ body[dir="rtl"] button.custom.iconifiable > .fa {
@media (max-width: 640px) {
button.custom.iconifiable > .fa {
font-size: 150%;
padding: 0;
}
button.custom.iconifiable > [data-i18n] {

View file

@ -1,7 +1,7 @@
body {
background-color: #fff;
box-sizing: border-box;
color: #000;
color: #20123a;
margin: 0;
padding: 0;
}

View file

@ -33,16 +33,16 @@ html, body {
.tabButton {
border: 0;
border-bottom: 3px solid #f9f9fb;
color: #20123a;
cursor: pointer;
padding: 0.5em 1.5em;
padding: 0.5em 1.4em 0.3em 1.4em;
text-decoration: none;
white-space: nowrap;
}
.tabButton:focus {
outline: 0;
}
.tabButton:active,.tabButton:visited {
.tabButton:active,
.tabButton:visited {
color: #20123a;
}
.tabButton.selected {

View file

@ -18,9 +18,6 @@ body {
#diff .tools > * {
margin-bottom: 0.5em;
}
#diff .tools .fa {
font-size: large;
}
#diff .ruleActions {
border: 0;
box-sizing: border-box;

View file

@ -10,22 +10,20 @@ hr {
margin: 1.5em 0;
}
.body {
color: #20123a;
margin-top: 1em;
}
.entries {
margin: 0.5em 0;
}
.section {
font-size: large;
font-weight: bold;
margin-top: 0.75em;
}
.synopsis {
font-size: smaller;
font-size: 90%;
}
.entry {
align-items: baseline;
align-items: center;
display: flex;
margin: 0.5em 0;
}

View file

@ -10,9 +10,3 @@ body {
text-align: left;
width: 100%;
}
.codeMirrorContainer .cm-builtin {
color: #00F;
}
.codeMirrorContainer .cm-comment.cm-builtin {
color: #88F;
}

View file

@ -86,15 +86,17 @@ const renderFilterLists = function(soft) {
li = listEntryTemplate.clone().nodeAt(0);
}
const on = entry.off !== true;
li.classList.toggle('checked', on);
let elem;
if ( li.getAttribute('data-listkey') !== listKey ) {
li.setAttribute('data-listkey', listKey);
elem = li.querySelector('input[type="checkbox"]');
elem.checked = on;
elem = li.querySelector('a:nth-of-type(1)');
elem = li.querySelector('.listname');
elem.textContent = listNameFromListKey(listKey);
elem = li.querySelector('a.content');
elem.setAttribute('href', 'asset-viewer.html?url=' + encodeURI(listKey));
elem.setAttribute('type', 'text/html');
elem.textContent = listNameFromListKey(listKey);
li.classList.remove('toRemove');
if ( entry.supportName ) {
li.classList.add('support');
@ -321,7 +323,7 @@ const renderWidgets = function() {
);
uDom('#buttonUpdate').toggleClass(
'disabled',
document.querySelector('body:not(.updating) #lists .listEntry.obsolete:not(.toRemove) > input[type="checkbox"]:checked') === null
document.querySelector('body:not(.updating) #lists .listEntry.obsolete:not(.toRemove) input[type="checkbox"]:checked') === null
);
};
@ -377,20 +379,28 @@ const hashFromCurrentFromSettings = function() {
/******************************************************************************/
const onListsetChanged = function(ev) {
const input = ev.target;
const li = input.closest('.listEntry');
li.classList.toggle('checked', input.checked);
onFilteringSettingsChanged();
};
/******************************************************************************/
const onFilteringSettingsChanged = function() {
renderWidgets();
};
/******************************************************************************/
const onRemoveExternalList = function(ev) {
const onRemoveExternalList = function() {
const liEntry = uDom(this).ancestors('[data-listkey]');
const listKey = liEntry.attr('data-listkey');
if ( listKey ) {
liEntry.toggleClass('toRemove');
renderWidgets();
}
ev.preventDefault();
};
/******************************************************************************/
@ -539,7 +549,7 @@ const toggleHideUnusedLists = function(which) {
groupSelector = '.groupEntry[data-groupkey="' + which + '"] ';
uDom(groupSelector).toggleClass('hideUnused', mustHide);
}
uDom(groupSelector + '.listEntry > input[type="checkbox"]:not(:checked)')
uDom(groupSelector + '.listEntry input[type="checkbox"]:not(:checked)')
.ancestors('.listEntry[data-listkey]')
.toggleClass('unused', mustHide);
vAPI.localStorage.setItem(
@ -549,7 +559,7 @@ const toggleHideUnusedLists = function(which) {
};
const revealHiddenUsedLists = function() {
uDom('#lists .listEntry.unused > input[type="checkbox"]:checked')
uDom('#lists .listEntry.unused input[type="checkbox"]:checked')
.ancestors('.listEntry[data-listkey]')
.removeClass('unused');
};
@ -659,8 +669,8 @@ uDom('#buttonUpdate').on('click', ( ) => { buttonUpdateHandler(); });
uDom('#buttonPurgeAll').on('click', ev => {
buttonPurgeAllHandler(ev.ctrlKey && ev.shiftKey);
});
uDom('#lists').on('change', '.listEntry > input', onFilteringSettingsChanged);
uDom('#lists').on('click', '.listEntry > a.remove', onRemoveExternalList);
uDom('#lists').on('change', '.listEntry input', onListsetChanged);
uDom('#lists').on('click', '.listEntry .remove', onRemoveExternalList);
uDom('#lists').on('click', 'span.cache', onPurgeClicked);
uDom('#externalLists').on('input', onFilteringSettingsChanged);

View file

@ -52,13 +52,13 @@ CodeMirror.defineMode("ubo-whitelist-directives", function() {
}
if ( reComment.test(line) ) {
return whitelistDefaultSet.has(directiveFromLine(line))
? 'builtin comment'
? 'keyword comment'
: 'comment';
}
if ( line.indexOf('/') === -1 ) {
if ( reBadHostname.test(line) ) { return 'error'; }
if ( whitelistDefaultSet.has(line.trim()) ) {
return 'builtin';
return 'keyword';
}
return null;
}