Auto merge of #13187 - GuillaumeGomez:settings-menu, r=Alexendoo

Add settings menu on clippy lints page

It looks like this (when the menu is expanded):

![Screenshot from 2024-08-06 21-36-41](https://github.com/user-attachments/assets/c464aef3-b21e-48cc-8e3a-c32a134f995e)

Follow-up of https://github.com/rust-lang/rust-clippy/pull/13178.

Someone pointed out that they should be able to disable the shortcuts on this page like it's the case for rustdoc and docs.rs. So here we go.

The first commit moves the style into its own file: it's much better for a web browser because it can then cache it.

The second one actually adds the new settings menu you can see above.

r? `@Alexendoo`

changelog: Add settings menu on clippy lints page
This commit is contained in:
bors 2024-08-11 18:42:37 +00:00
commit c7c8724897
4 changed files with 471 additions and 406 deletions

1
.github/deploy.sh vendored
View file

@ -10,6 +10,7 @@ mkdir out/master/
cp util/gh-pages/index.html out/master
cp util/gh-pages/script.js out/master
cp util/gh-pages/lints.json out/master
cp util/gh-pages/style.css out/master
if [[ -n $TAG_NAME ]]; then
echo "Save the doc for the current tag ($TAG_NAME) and point stable/ to it"

View file

@ -23,378 +23,25 @@ Otherwise, have a great day =^.^=
<link id="styleHighlight" rel="stylesheet" href="https://rust-lang.github.io/mdBook/highlight.css">
<link id="styleNight" rel="stylesheet" href="https://rust-lang.github.io/mdBook/tomorrow-night.css" disabled="true">
<link id="styleAyu" rel="stylesheet" href="https://rust-lang.github.io/mdBook/ayu-highlight.css" disabled="true">
<style>
blockquote { font-size: 1em; }
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; }
.dropdown-menu {
color: var(--fg);
background: var(--theme-popup-bg);
border: 1px solid var(--theme-popup-border);
}
.dropdown-menu .divider {
background-color: var(--theme-popup-border);
}
.dropdown-menu .checkbox {
display: block;
white-space: nowrap;
margin: 0;
}
.dropdown-menu .checkbox label {
padding: 3px 20px;
width: 100%;
}
.dropdown-menu .checkbox input {
position: relative;
margin: 0 0.5rem 0;
padding: 0;
}
.dropdown-menu .checkbox:hover {
background-color: var(--theme-hover);
}
div.panel div.panel-body button {
background: var(--searchbar-bg);
color: var(--searchbar-fg);
border-color: var(--theme-popup-border);
}
div.panel div.panel-body button:hover {
box-shadow: 0 0 3px var(--searchbar-shadow-color);
}
div.panel div.panel-body button.open {
filter: brightness(90%);
}
.dropdown-toggle .badge {
background-color: #777;
}
.panel-heading { cursor: pointer; }
.panel-title { display: flex; flex-wrap: wrap;}
.panel-title .label { display: inline-block; }
.panel-title-name { flex: 1; min-width: 400px;}
.panel-title-name span { vertical-align: bottom; }
.panel .panel-title-name .anchor { display: none; }
.panel:hover .panel-title-name .anchor { display: inline;}
.search-control {
margin-top: 15px;
}
@media (min-width: 992px) {
.search-control {
margin-top: 0;
}
}
@media (min-width: 405px) {
#upper-filters {
display: flex;
flex-wrap: wrap;
}
}
@media (max-width: 430px) {
/* Turn the version filter list to the left */
#version-filter-selector {
right: 0;
left: auto;
}
}
@media (max-width: 412px) {
#upper-filters,
.panel-body .search-control {
padding-right: 8px;
padding-left: 8px;
}
}
.label {
padding-top: 0.3em;
padding-bottom: 0.3em;
}
.label-lint-group {
min-width: 8em;
}
.label-lint-level {
min-width: 4em;
}
.label-lint-level-allow {
background-color: #5cb85c;
}
.label-lint-level-warn {
background-color: #f0ad4e;
}
.label-lint-level-deny {
background-color: #d9534f;
}
.label-lint-level-none {
background-color: #777777;
opacity: 0.5;
}
.label-group-deprecated {
opacity: 0.5;
}
.label-doc-folding {
color: #000;
background-color: #fff;
border: 1px solid var(--theme-popup-border);
}
.label-doc-folding:hover {
background-color: #e6e6e6;
}
.lint-doc-md > h3 {
border-top: 1px solid var(--theme-popup-border);
padding: 10px 15px;
margin: 0 -15px;
font-size: 18px;
}
.lint-doc-md > h3:first-child {
border-top: none;
padding-top: 0px;
}
@media (max-width:749px) {
.lint-additional-info-container {
display: flex;
flex-flow: column;
}
.lint-additional-info-item + .lint-additional-info-item {
border-top: 1px solid var(--theme-popup-border);
}
}
@media (min-width:750px) {
.lint-additional-info-container {
display: flex;
flex-flow: row;
}
.lint-additional-info-item + .lint-additional-info-item {
border-left: 1px solid var(--theme-popup-border);
}
}
.lint-additional-info-item {
display: inline-flex;
min-width: 200px;
flex-grow: 1;
padding: 9px 5px 5px 15px;
}
.label-applicability {
background-color: #777777;
margin: auto 5px;
}
.label-version {
background-color: #777777;
margin: auto 5px;
font-family: monospace;
}
details {
border-radius: 4px;
padding: .5em .5em 0;
}
code {
white-space: pre !important;
}
summary {
font-weight: bold;
margin: -.5em -.5em 0;
padding: .5em;
display: revert;
}
details[open] {
padding: .5em;
}
</style>
<style>
/* Expanding the mdBoom theme*/
.light {
--inline-code-bg: #f6f7f6;
}
.rust {
--inline-code-bg: #f6f7f6;
}
.coal {
--inline-code-bg: #1d1f21;
}
.navy {
--inline-code-bg: #1d1f21;
}
.ayu {
--inline-code-bg: #191f26;
}
.theme-dropdown {
position: absolute;
margin: 0.7em;
z-index: 10;
}
/* Applying the mdBook theme */
.theme-icon {
text-align: center;
width: 2em;
height: 2em;
line-height: 2em;
border: solid 1px var(--icons);
border-radius: 5px;
user-select: none;
cursor: pointer;
}
.theme-icon:hover {
background: var(--theme-hover);
}
.theme-choice {
display: none;
list-style: none;
border: 1px solid var(--theme-popup-border);
border-radius: 5px;
color: var(--fg);
background: var(--theme-popup-bg);
padding: 0 0;
overflow: hidden;
}
.theme-dropdown.open .theme-choice {
display: block;
}
.theme-choice > li {
padding: 5px 10px;
font-size: 0.8em;
user-select: none;
cursor: pointer;
}
.theme-choice > li:hover {
background: var(--theme-hover);
}
.alert {
color: var(--fg);
background: var(--theme-hover);
border: 1px solid var(--theme-popup-border);
}
.page-header {
border-color: var(--theme-popup-border);
}
.panel-default > .panel-heading {
background: var(--theme-hover);
color: var(--fg);
border: 1px solid var(--theme-popup-border);
}
.panel-default > .panel-heading:hover {
filter: brightness(90%);
}
.list-group-item {
background: 0%;
border: 1px solid var(--theme-popup-border);
}
.panel, pre, hr {
background: var(--bg);
border: 1px solid var(--theme-popup-border);
}
#version-filter-selector .checkbox {
display: flex;
}
#version-filter {
min-width: available;
}
#version-filter li label {
padding-right: 0;
width: 35%;
}
.version-filter-input {
height: 60%;
width: 30%;
text-align: center;
border: none;
border-bottom: 1px solid #000000;
}
#filter-label, .filter-clear {
background: var(--searchbar-bg);
color: var(--searchbar-fg);
border-color: var(--theme-popup-border);
filter: brightness(95%);
}
#filter-label:hover, .filter-clear:hover {
filter: brightness(90%);
}
.filter-input {
background: var(--searchbar-bg);
color: var(--searchbar-fg);
border-color: var(--theme-popup-border);
}
.filter-input::-webkit-input-placeholder,
.filter-input::-moz-placeholder {
color: var(--searchbar-fg);
opacity: 30%;
}
.expansion-group {
margin-top: 15px;
padding: 0px 8px;
display: flex;
flex-wrap: nowrap;
}
@media (min-width: 992px) {
.expansion-group {
margin-top: 0;
padding: 0px 15px;
}
}
.expansion-control {
width: 50%;
}
:not(pre) > code {
color: var(--inline-code-color);
background-color: var(--inline-code-bg);
}
html {
scrollbar-color: var(--scrollbar) var(--bg);
}
body {
background: var(--bg);
color: var(--fg);
}
</style>
<link rel="stylesheet" href="style.css">
</head>
<body ng-app="clippy" ng-controller="lintList">
<div theme-dropdown class="theme-dropdown">
<div id="theme-icon" class="theme-icon">&#128396;</div>
<ul id="theme-menu" class="theme-choice">
<li id="{{id}}" ng-repeat="(id, name) in themes" ng-click="selectTheme(id)">{{name}}</li>
</ul>
<div id="settings-dropdown">
<div class="settings-icon" tabindex="-1"></div>
<div class="settings-menu" tabindex="-1">
<div class="setting-radio-name">Theme</div>
<select id="theme-choice" onchange="setTheme(this.value, true)">
<option value="ayu">Ayu</option>
<option value="coal">Coal</option>
<option value="light">Light</option>
<option value="navy">Navy</option>
<option value="rust">Rust</option>
</select>
<label>
<input type="checkbox" id="disable-shortcuts" onchange="changeSetting(this)">
<span>Disable keyboard shortcuts</span>
</label>
</div>
</div>
<div class="container">

View file

@ -50,24 +50,6 @@
);
};
})
.directive('themeDropdown', function ($document) {
return {
restrict: 'A',
link: function ($scope, $element, $attr) {
$element.bind('click', function () {
$element.toggleClass('open');
$element.addClass('open-recent');
});
$document.bind('click', function () {
if (!$element.hasClass('open-recent')) {
$element.removeClass('open');
}
$element.removeClass('open-recent');
})
}
}
})
.directive('filterDropdown', function ($document) {
return {
restrict: 'A',
@ -127,15 +109,6 @@
...GROUPS_FILTER_DEFAULT
};
const THEMES_DEFAULT = {
light: "Light",
rust: "Rust",
coal: "Coal",
navy: "Navy",
ayu: "Ayu"
};
$scope.themes = THEMES_DEFAULT;
$scope.versionFilters = {
"≥": {enabled: false, minorVersion: null },
"≤": {enabled: false, minorVersion: null },
@ -321,10 +294,6 @@
$location.path($scope.search);
}
$scope.selectTheme = function (theme) {
setTheme(theme, true);
}
$scope.toggleLevels = function (value) {
const levels = $scope.levels;
for (const key in levels) {
@ -537,6 +506,16 @@ function getQueryVariable(variable) {
}
}
function storeValue(settingName, value) {
try {
localStorage.setItem(`clippy-lint-list-${settingName}`, value);
} catch (e) { }
}
function loadValue(settingName) {
return localStorage.getItem(`clippy-lint-list-${settingName}`);
}
function setTheme(theme, store) {
let enableHighlight = false;
let enableNight = false;
@ -569,14 +548,14 @@ function setTheme(theme, store) {
document.getElementById("styleAyu").disabled = !enableAyu;
if (store) {
try {
localStorage.setItem('clippy-lint-list-theme', theme);
} catch (e) { }
storeValue("theme", theme);
} else {
document.getElementById(`theme-choice`).value = theme;
}
}
function handleShortcut(ev) {
if (ev.ctrlKey || ev.altKey || ev.metaKey) {
if (ev.ctrlKey || ev.altKey || ev.metaKey || disableShortcuts) {
return;
}
@ -601,11 +580,51 @@ function handleShortcut(ev) {
document.addEventListener("keypress", handleShortcut);
document.addEventListener("keydown", handleShortcut);
function changeSetting(elem) {
if (elem.id === "disable-shortcuts") {
disableShortcuts = elem.checked;
storeValue(elem.id, elem.checked);
}
}
function onEachLazy(lazyArray, func) {
const arr = Array.prototype.slice.call(lazyArray);
for (const el of arr) {
func(el);
}
}
function handleBlur(event) {
const parent = document.getElementById("settings-dropdown");
if (!parent.contains(document.activeElement) &&
!parent.contains(event.relatedTarget)
) {
parent.classList.remove("open");
}
}
function generateSettings() {
const settings = document.getElementById("settings-dropdown");
const settingsButton = settings.querySelector(".settings-icon")
settingsButton.onclick = () => settings.classList.toggle("open");
settingsButton.onblur = handleBlur;
const settingsMenu = settings.querySelector(".settings-menu");
settingsMenu.onblur = handleBlur;
onEachLazy(
settingsMenu.querySelectorAll("input"),
el => el.onblur = handleBlur,
);
}
generateSettings();
// loading the theme after the initial load
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)");
const theme = localStorage.getItem('clippy-lint-list-theme');
const theme = loadValue('theme');
if (prefersDark.matches && !theme) {
setTheme("coal", false);
} else {
setTheme(theme, false);
}
let disableShortcuts = loadValue('disable-shortcuts') === "true";
document.getElementById("disable-shortcuts").checked = disableShortcuts;

398
util/gh-pages/style.css Normal file
View file

@ -0,0 +1,398 @@
blockquote { font-size: 1em; }
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none !important;
}
.dropdown-menu {
color: var(--fg);
background: var(--theme-popup-bg);
border: 1px solid var(--theme-popup-border);
}
.dropdown-menu .divider {
background-color: var(--theme-popup-border);
}
.dropdown-menu .checkbox {
display: block;
white-space: nowrap;
margin: 0;
}
.dropdown-menu .checkbox label {
padding: 3px 20px;
width: 100%;
}
.dropdown-menu .checkbox input {
position: relative;
margin: 0 0.5rem 0;
padding: 0;
}
.dropdown-menu .checkbox:hover {
background-color: var(--theme-hover);
}
div.panel div.panel-body button {
background: var(--searchbar-bg);
color: var(--searchbar-fg);
border-color: var(--theme-popup-border);
}
div.panel div.panel-body button:hover {
box-shadow: 0 0 3px var(--searchbar-shadow-color);
}
div.panel div.panel-body button.open {
filter: brightness(90%);
}
.dropdown-toggle .badge {
background-color: #777;
}
.panel-heading { cursor: pointer; }
.panel-title { display: flex; flex-wrap: wrap;}
.panel-title .label { display: inline-block; }
.panel-title-name { flex: 1; min-width: 400px;}
.panel-title-name span { vertical-align: bottom; }
.panel .panel-title-name .anchor { display: none; }
.panel:hover .panel-title-name .anchor { display: inline;}
.search-control {
margin-top: 15px;
}
@media (min-width: 992px) {
.search-control {
margin-top: 0;
}
}
@media (min-width: 405px) {
#upper-filters {
display: flex;
flex-wrap: wrap;
}
}
@media (max-width: 430px) {
/* Turn the version filter list to the left */
#version-filter-selector {
right: 0;
left: auto;
}
}
@media (max-width: 412px) {
#upper-filters,
.panel-body .search-control {
padding-right: 8px;
padding-left: 8px;
}
}
.label {
padding-top: 0.3em;
padding-bottom: 0.3em;
}
.label-lint-group {
min-width: 8em;
}
.label-lint-level {
min-width: 4em;
}
.label-lint-level-allow {
background-color: #5cb85c;
}
.label-lint-level-warn {
background-color: #f0ad4e;
}
.label-lint-level-deny {
background-color: #d9534f;
}
.label-lint-level-none {
background-color: #777777;
opacity: 0.5;
}
.label-group-deprecated {
opacity: 0.5;
}
.label-doc-folding {
color: #000;
background-color: #fff;
border: 1px solid var(--theme-popup-border);
}
.label-doc-folding:hover {
background-color: #e6e6e6;
}
.lint-doc-md > h3 {
border-top: 1px solid var(--theme-popup-border);
padding: 10px 15px;
margin: 0 -15px;
font-size: 18px;
}
.lint-doc-md > h3:first-child {
border-top: none;
padding-top: 0px;
}
@media (max-width:749px) {
.lint-additional-info-container {
display: flex;
flex-flow: column;
}
.lint-additional-info-item + .lint-additional-info-item {
border-top: 1px solid var(--theme-popup-border);
}
}
@media (min-width:750px) {
.lint-additional-info-container {
display: flex;
flex-flow: row;
}
.lint-additional-info-item + .lint-additional-info-item {
border-left: 1px solid var(--theme-popup-border);
}
}
.lint-additional-info-item {
display: inline-flex;
min-width: 200px;
flex-grow: 1;
padding: 9px 5px 5px 15px;
}
.label-applicability {
background-color: #777777;
margin: auto 5px;
}
.label-version {
background-color: #777777;
margin: auto 5px;
font-family: monospace;
}
details {
border-radius: 4px;
padding: .5em .5em 0;
}
code {
white-space: pre !important;
}
summary {
font-weight: bold;
margin: -.5em -.5em 0;
padding: .5em;
display: revert;
}
details[open] {
padding: .5em;
}
/* Expanding the mdBook theme*/
.light {
--inline-code-bg: #f6f7f6;
}
.rust {
--inline-code-bg: #f6f7f6;
}
.coal {
--inline-code-bg: #1d1f21;
}
.navy {
--inline-code-bg: #1d1f21;
}
.ayu {
--inline-code-bg: #191f26;
}
#settings-dropdown {
position: absolute;
margin: 0.7em;
z-index: 10;
display: flex;
}
/* Applying the mdBook theme */
.settings-icon {
text-align: center;
width: 2em;
height: 2em;
line-height: 2em;
border: solid 1px var(--icons);
border-radius: 5px;
user-select: none;
cursor: pointer;
background: var(--theme-hover);
}
.settings-menu {
display: none;
list-style: none;
border: 1px solid var(--theme-popup-border);
border-radius: 5px;
color: var(--fg);
background: var(--theme-popup-bg);
overflow: hidden;
padding: 9px;
width: 207px;
position: absolute;
top: 28px;
}
.settings-icon::before {
/* Wheel <https://www.svgrepo.com/svg/384069/settings-cog-gear> */
content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \
enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\
<path d="M10.25,6c0-0.1243286-0.0261841-0.241333-0.0366211-0.362915l1.6077881-1.5545654l\
-1.25-2.1650391 c0,0-1.2674561,0.3625488-2.1323853,0.6099854c-0.2034912-0.1431885-0.421875\
-0.2639771-0.6494751-0.3701782L7.25,0h-2.5 c0,0-0.3214111,1.2857666-0.5393066,2.1572876\
C3.9830933,2.2634888,3.7647095,2.3842773,3.5612183,2.5274658L1.428833,1.9174805 \
l-1.25,2.1650391c0,0,0.9641113,0.9321899,1.6077881,1.5545654C1.7761841,5.758667,\
1.75,5.8756714,1.75,6 s0.0261841,0.241333,0.0366211,0.362915L0.178833,7.9174805l1.25,\
2.1650391l2.1323853-0.6099854 c0.2034912,0.1432495,0.421875,0.2639771,0.6494751,0.3701782\
L4.75,12h2.5l0.5393066-2.1572876 c0.2276001-0.1062012,0.4459839-0.2269287,0.6494751\
-0.3701782l2.1323853,0.6099854l1.25-2.1650391L10.2133789,6.362915 C10.2238159,6.241333,\
10.25,6.1243286,10.25,6z M6,7.5C5.1715698,7.5,4.5,6.8284302,4.5,6S5.1715698,4.5,6,4.5S7.5\
,5.1715698,7.5,6 S6.8284302,7.5,6,7.5z" fill="black"/></svg>');
width: 18px;
height: 18px;
display: block;
filter: invert(0.7);
padding-left: 4px;
padding-top: 3px;
}
.settings-menu * {
font-weight: normal;
}
.settings-menu label {
cursor: pointer;
}
#settings-dropdown.open .settings-menu {
display: block;
}
#theme-choice {
margin-bottom: 10px;
background: var(--searchbar-bg);
color: var(--searchbar-fg);
border-color: var(--theme-popup-border);
border-radius: 5px;
cursor: pointer;
width: 100%;
border-width: 1px;
padding: 5px;
}
.alert {
color: var(--fg);
background: var(--theme-hover);
border: 1px solid var(--theme-popup-border);
}
.page-header {
border-color: var(--theme-popup-border);
}
.panel-default > .panel-heading {
background: var(--theme-hover);
color: var(--fg);
border: 1px solid var(--theme-popup-border);
}
.panel-default > .panel-heading:hover {
filter: brightness(90%);
}
.list-group-item {
background: 0%;
border: 1px solid var(--theme-popup-border);
}
.panel, pre, hr {
background: var(--bg);
border: 1px solid var(--theme-popup-border);
}
#version-filter-selector .checkbox {
display: flex;
}
#version-filter {
min-width: available;
}
#version-filter li label {
padding-right: 0;
width: 35%;
}
.version-filter-input {
height: 60%;
width: 30%;
text-align: center;
border: none;
border-bottom: 1px solid #000000;
}
#filter-label, .filter-clear {
background: var(--searchbar-bg);
color: var(--searchbar-fg);
border-color: var(--theme-popup-border);
filter: brightness(95%);
}
#filter-label:hover, .filter-clear:hover {
filter: brightness(90%);
}
.filter-input {
background: var(--searchbar-bg);
color: var(--searchbar-fg);
border-color: var(--theme-popup-border);
}
.filter-input::-webkit-input-placeholder,
.filter-input::-moz-placeholder {
color: var(--searchbar-fg);
opacity: 30%;
}
.expansion-group {
margin-top: 15px;
padding: 0px 8px;
display: flex;
flex-wrap: nowrap;
}
@media (min-width: 992px) {
.expansion-group {
margin-top: 0;
padding: 0px 15px;
}
}
.expansion-control {
width: 50%;
}
:not(pre) > code {
color: var(--inline-code-color);
background-color: var(--inline-code-bg);
}
html {
scrollbar-color: var(--scrollbar) var(--bg);
}
body {
background: var(--bg);
color: var(--fg);
}