fix: cheatsheet page performance

This commit is contained in:
rszyma 2023-05-20 11:08:09 +02:00 committed by Fini Jastrow
parent cec9c1e6e2
commit 156981d8f2
5 changed files with 11893 additions and 48017 deletions

View file

@ -1,4 +1,3 @@
p {
line-height: 1.75em;
}
@ -20,33 +19,40 @@ input.nerd-font-input {
margin: 0pt auto;
}
.nerd-font-button, .nerd-font-input {
.nerd-font-button,
.nerd-font-input {
cursor: pointer;
border-width: 2px;
font-size: 21px;
border-style: solid;
border-color: #f8f8f8;
color: #f8f8f8;
&input {
cursor: inherit;
border-radius: unset;
}
&.primary {
background: #1E5D8A;
}
&.secondary {
background: #BA45AE;
}
&.tertiary {
background: #565346;
border-color: #0fbfcf;
color: #0fbfcf;
}
&.tertiary--inverse {
background: #0fbfcf;
border-color: #565346;
color: #565346;
}
&.download {
background: #0C640C;
}
@ -113,10 +119,6 @@ a.nerd-font-button:before {
display: flex;
flex-flow: row wrap;
margin-bottom: 60px;
visibility: hidden; /* don't show any by default */
&.has-results {
visibility: visible;
}
}
#glyphCheatSheet .column {
@ -132,10 +134,6 @@ a.nerd-font-button:before {
padding-right: 10px;
border-radius: 5px;
margin: 10px 5px;
display: none; /* don't show any by default */
}
#glyphCheatSheet .column.is-visible {
display: block;
}
@ -296,7 +294,8 @@ a.nerd-font-button:before {
width: 2.5em
}
.fa-stack-1x,.fa-stack-2x {
.fa-stack-1x,
.fa-stack-2x {
left: 0;
position: absolute;
text-align: center;
@ -327,13 +326,33 @@ a.nerd-font-button:before {
/* color scheme */
.nf1 { color: #E2DB74 }
.nf2 { color: #49a7e9 }
.nf3 { color: #66FF99 }
.nf4 { color: #Ff66CC }
.nf5 { color: #00ffff }
.nf6 { color: #f09f17 }
.nf7 { color: #DD1B16 }
.nf1 {
color: #E2DB74
}
.nf2 {
color: #49a7e9
}
.nf3 {
color: #66FF99
}
.nf4 {
color: #Ff66CC
}
.nf5 {
color: #00ffff
}
.nf6 {
color: #f09f17
}
.nf7 {
color: #DD1B16
}
/* Example Usage */
@ -367,9 +386,7 @@ a.nerd-font-button:before {
/* features section */
.feature-sections {
}
.feature-sections {}
.feature-section {
background: #ffffff55;
@ -381,30 +398,38 @@ a.nerd-font-button:before {
text-align: center;
}
.feature-section h2, .feature-section h3, .feature-section h4 {
.feature-section h2,
.feature-section h3,
.feature-section h4 {
font-weight: bold;
}
.feature-section h2, .feature-section h3 {
.feature-section h2,
.feature-section h3 {
text-align: left;
}
.feature-section h2, .feature-section h3, .feature-section h4:not(.nerd-font-button) {
.feature-section h2,
.feature-section h3,
.feature-section h4:not(.nerd-font-button) {
padding: 10px 0px;
margin: 0px;
color: #1c1c1c;
text-shadow: -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, 1px 1px 0 #fff;
}
.feature-section h3, .feature-section h4 {
.feature-section h3,
.feature-section h4 {
font-size: 20px;
padding-top: 0px;
font-size: 20px;
padding-top: 0px;
}
.feature-section h4 img {
max-height: 100px;
}
.feature-section div p {
text-align: left;
}
@ -464,11 +489,24 @@ a.nerd-font-button:before {
transition: .5s;
padding: 5px 40px;
}
#forkongithub a::before, #forkongithub a::after {
content:""; width:100%; display:block; position:absolute;
top:1px; left:0; height:1px; background:#fff;
#forkongithub a::before,
#forkongithub a::after {
content: "";
width: 100%;
display: block;
position: absolute;
top: 1px;
left: 0;
height: 1px;
background: #fff;
}
#forkongithub a::after { bottom:1px; top:auto; }
#forkongithub a::after {
bottom: 1px;
top: auto;
}
@media screen and (min-width:800px) {
#forkongithub {
position: fixed;
@ -480,6 +518,7 @@ a.nerd-font-button:before {
height: 209px;
z-index: 99;
}
#forkongithub a {
width: 200px;
position: absolute;
@ -551,9 +590,11 @@ a.nerd-font-button:before {
padding-right: 10px;
padding-top: 5px;
}
img {
vertical-align: top !important;
}
.font-preview {
text-decoration: none;
background-size: contain;
@ -561,20 +602,24 @@ a.nerd-font-button:before {
background-repeat: no-repeat;
background-position-x: 34px;
}
.font-preview:before {
content: "";
font-size: 32px;
font-family: 'NerdFontsSymbols Nerd Font';
}
}
.nerd-font-buttons-wrapper {
display: flex;
flex-wrap: wrap;
}
.button-empty-spacer {
height: 42px;
width: 100%;
}
.nerd-font-button {
border-width: 2px;
border-style: solid;
@ -615,19 +660,30 @@ a.nerd-font-button:before {
without decrease font size
*/
@media only screen and (max-width: 326px) {
nav { font-size: 9px; }
nav {
font-size: 9px;
}
}
/* tiny size (phones) */
@media only screen and (max-width: 380px) {
nav ul li { min-width:initial; line-height:20px; }
li.p-downloads a:after { content: ''; }
nav ul li {
min-width: initial;
line-height: 20px;
}
li.p-downloads a:after {
content: '';
}
.section:first-of-type {
padding-top: 70px;
}
#features .sectioninner2 {
font-size: .7em;
}
#main .nerd-font-cheat-sheet .column {
width: 102px;
height: 98px;
@ -641,15 +697,23 @@ a.nerd-font-button:before {
/* mid size (tablets, landscapes) */
@media only screen and (max-width: 679px) {
nav { font-size:10px; }
li.p-downloads a:after { content: ''; }
nav {
font-size: 10px;
}
li.p-downloads a:after {
content: '';
}
nav ul li {
min-width: 50px;
line-height: 40px;
}
.section:first-of-type {
padding-top: 70px;
}
#features .sectioninner2 {
font-size: .7em;
}
@ -657,12 +721,25 @@ a.nerd-font-button:before {
/* anything not desktop */
@media only screen and (max-width: 767px) {
.container h1 { font-size: 30px; }
.container h2 { font-size: 24px; }
.container h3 { font-size: 20px; }
.container h4 { font-size: 18px; }
.container h1 {
font-size: 30px;
}
.section { padding:130px 0; }
.container h2 {
font-size: 24px;
}
.container h3 {
font-size: 20px;
}
.container h4 {
font-size: 18px;
}
.section {
padding: 130px 0;
}
.section-page-wrapper .sectiondivider,
.sectiondivider {
@ -694,17 +771,11 @@ a.nerd-font-button:before {
-moz-column-count: 2;
column-count: 2;
}
.sectioninner3 {
line-height: 21px;
font-size: 11px;
}
/* gitter adjust sidecar on mobile */
.gitter-open-chat-button {
bottom: 116px;
padding: 1em 1em;
transform: rotate(-90deg);
right: -28px;
}
}
/* util */

File diff suppressed because it is too large Load diff

View file

@ -17,5 +17,9 @@
</div>
{% include analytics.html %}
{% include scripts.html %}
<script
src="https://cdn.jsdelivr.net/npm/minisearch@6.1.0/dist/umd/index.min.js"></script>
<script
src="cheat-sheet.js"></script>
</body>
</html>

267
cheat-sheet.js Normal file
View file

@ -0,0 +1,267 @@
document.addEventListener('DOMContentLoaded', function () {
const elementGlyphSearch = document.getElementById('glyphSearch');
const elementGlyphCheatSheet = document.getElementById('glyphCheatSheet');
const maxSearchResults = 250;
// Storage for not-yet-rendered search results. More results will are rendered when scrolled to the bottom.
let remainingSearchResults = [];
// Index all glyphs/icons
let miniSearch = new MiniSearch({
fields: ['id', 'code'], // fields to index for full-text search
storeFields: ['id', 'code', 'isRemoved'], // fields to return with search results
})
miniSearch.addAll(Object.entries(glyphs).map(
([key, value]) => {
return {
id: key,
code: value,
}
}
));
elementGlyphCheatSheet.onscroll = function () {
const threshold = 10;
if ((elementGlyphCheatSheet.offsetHeight + elementGlyphCheatSheet.scrollTop + threshold) >= elementGlyphCheatSheet.scrollHeight) {
console.log("load more search results");
loadMoreSearchResults();
}
};
// search via typing in input (debounced)
elementGlyphSearch && elementGlyphSearch.addEventListener(
'input',
debounce(function (e) {
gtag('event', 'search-via-input', {
event_category: 'glyph-search',
event_label: 'Cheat Sheet : ' + (e.target && e.target.value),
value: e.target && e.target.value
});
searchGlyphs();
}, 500)
);
// Credit David Walsh (https://davidwalsh.name/javascript-debounce-function)
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
let timeout;
return function executedFunction() {
let context = this;
let args = arguments;
let later = function () {
timeout = null;
if (!immediate) func.apply(context, args);
};
let callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
function addSearchResultItemToFragment(fragment, iconClassName, codepoint) {
let parentDiv = document.createElement("div");
parentDiv.setAttribute("class", "column");
let index = iconClassName.indexOf('-');
let namespace = iconClassName.substring(0, index);
let iconClassNameBeforeDeprecation = iconClassName;
if (namespace === "nfold") {
let rest = iconClassName.substring(index + 1);
iconClassNameBeforeDeprecation = `nf-${rest}`;
let span1 = document.createElement("span");
span1.setAttribute("class", "corner-red");
parentDiv.appendChild(span1);
let span2 = document.createElement("span");
span2.setAttribute("class", "corner-text");
span2.textContent = "removed";
parentDiv.appendChild(span2);
}
let innerDiv1 = document.createElement("div");
innerDiv1.setAttribute("class", `center ${namespace} ${iconClassName}`);
parentDiv.appendChild(innerDiv1);
let innerDiv2 = document.createElement("div");
innerDiv2.setAttribute("class", "class-name");
innerDiv2.textContent = iconClassNameBeforeDeprecation;
parentDiv.appendChild(innerDiv2);
let innerDiv3 = document.createElement("div");
innerDiv3.setAttribute("class", "codepoint");
innerDiv3.setAttribute("title", "Copy Hex Code to Clipboard");
innerDiv3.textContent = codepoint;
parentDiv.appendChild(innerDiv3);
fragment.appendChild(parentDiv);
}
function loadMoreSearchResults() {
let fragment = document.createDocumentFragment();
remainingSearchResults.slice(0, maxSearchResults).forEach(result => {
addSearchResultItemToFragment(fragment, result.id, result.code);
});
elementGlyphCheatSheet.append(fragment);
remainingSearchResults = remainingSearchResults.slice(maxSearchResults, -1);
}
function searchGlyphs() {
let searchTerm = elementGlyphSearch.value;
if (searchTerm === "") {
// MiniSearch don't allow empty searches, so we search for "nf".
// Also it hides "nfold" (removed) icons.
searchTerm = "nf";
}
// TODO: search suggestions
// TODO: show removed/deprecated icons at the end of results list.
remainingSearchResults = miniSearch.search(searchTerm,
{
prefix: false,
combineWith: "AND",
}
);
console.log(`search: ${remainingSearchResults.length} results found`);
elementGlyphCheatSheet.replaceChildren([]);
elementGlyphCheatSheet.scrollTop = 0;
if (remainingSearchResults.length != 0) {
loadMoreSearchResults();
} else {
let notFoundElem = document.createElement("div");
notFoundElem.setAttribute("style", "padding: 10px;");
notFoundElem.innerHTML = `<span style="font-size: 30px;">No results found</span>`;
elementGlyphCheatSheet.appendChild(notFoundElem);
}
}
elementGlyphCheatSheet && elementGlyphCheatSheet.addEventListener(
'mouseenter',
function (e) {
if (e.target.classList.contains('column')) {
// add Node
const newNode = document.createElement('span');
const copyTextNode = document.createElement('span');
const copyGlyphNode = document.createElement('span');
const copyClassNode = document.createElement('span');
const copyCodePoint = document.createElement('span');
newNode.className = 'glyph-popout-copy-clipboard';
copyTextNode.innerText = 'Copy';
copyGlyphNode.innerText = 'Icon';
copyClassNode.innerText = 'Class';
copyCodePoint.innerText = 'UTF';
copyGlyphNode.title = 'Copy Icon to Clipboard';
copyClassNode.title = 'Copy Class Name to Clipboard';
copyCodePoint.title = 'Copy UTF-16 Codes to Clipboard';
copyGlyphNode.className = 'copy-glyph';
copyClassNode.className = 'copy-class';
copyCodePoint.className = 'copy-utf16';
newNode.appendChild(copyTextNode);
newNode.appendChild(copyGlyphNode);
newNode.appendChild(copyClassNode);
newNode.appendChild(copyCodePoint);
e.target.children[0].before(newNode);
}
},
true
);
elementGlyphCheatSheet && elementGlyphCheatSheet.addEventListener(
'mouseleave',
function (e) {
if (e.target.classList.contains('column')) {
e.target.querySelector('.glyph-popout-copy-clipboard').remove();
}
},
true
);
elementGlyphCheatSheet && elementGlyphCheatSheet.addEventListener('click', function (event) {
let textToCopy = '';
let target = event.target;
let parent = target.parentNode;
if (parent.className === 'glyph-popout-copy-clipboard') {
if (target.className === 'copy-class') {
textToCopy = parent.parentNode.querySelector('.class-name').innerText;
} else if (target.className === 'copy-glyph') {
textToCopy = window
.getComputedStyle(document.querySelector(`.${parent.parentNode.querySelector('.class-name').innerText}`), ':before')
.getPropertyValue('content')
.replace(/"/g, '');
} else if (target.className === 'copy-utf16') {
const glyph = window
.getComputedStyle(document.querySelector(`.${parent.parentNode.querySelector('.class-name').innerText}`), ':before')
.getPropertyValue('content')
.replace(/"/g, '');
textToCopy = '';
let i = 0;
while (i < 10) {
let c = glyph.charCodeAt(i++); // js strings are utf16 already :-)
if (!(c > 0)) break;
if (c <= 0x32) continue;
textToCopy += '\\u' + c.toString(16);
}
}
} else if (parent.className.startsWith('column') && target.className === 'codepoint') {
textToCopy = target.innerText;
}
if (textToCopy.length > 0) {
gtag('event', event.target.className, {
event_category: 'clipboard-copy',
event_label: 'Copy To Clipboard : ' + textToCopy,
value: textToCopy
});
copyToClipboard(textToCopy);
}
});
// Copies a string to the clipboard. Must be called from within an
// event handler such as click. May return false if it failed, but
// this is not always possible. Browser support for Chrome 43+,
// Firefox 42+, Safari 10+, Edge and IE 10+.
// IE: The clipboard feature may be disabled by an administrator. By
// default a prompt is shown the first time the clipboard is
// used (per session).
function copyToClipboard(text) {
if (window.clipboardData && window.clipboardData.setData) {
// IE specific code path to prevent textarea being shown while dialog is visible.
return clipboardData.setData('Text', text);
} else if (document.queryCommandSupported && document.queryCommandSupported('copy')) {
let textarea = document.createElement('textarea');
textarea.textContent = text;
textarea.style.position = 'fixed'; // Prevent scrolling to bottom of page in MS Edge.
document.body.appendChild(textarea);
textarea.select();
try {
return document.execCommand('copy'); // Security exception may be thrown by some browsers.
} catch (ex) {
console.warn('Copy to clipboard failed.', ex);
return false;
} finally {
document.body.removeChild(textarea);
}
}
}
searchGlyphs(); // shows all glyphs at first load
})

223
site.js
View file

@ -1,12 +1,6 @@
document.addEventListener('DOMContentLoaded', function () {
const elementGlyphSearch = document.getElementById('glyphSearch');
const elementGlyphSearchButton = document.getElementById('glyphSearchButton');
const elementGlyphSearchAllButton = document.getElementById('glyphSearchAllButton');
const elementGlyphCheatSheet = document.getElementById('glyphCheatSheet');
// nice scrolling
document.getElementsByTagName('nav')[0].addEventListener('click', function (e) {
if (e.target.matches('a') && e.target.hash) {
const section = document.getElementById(e.target.hash.slice(1));
@ -97,113 +91,6 @@ document.addEventListener('DOMContentLoaded', function () {
scroll();
}
// search via typing in input (debounced)
elementGlyphSearch && elementGlyphSearch.addEventListener(
'keyup',
debounce(function (e) {
gtag('event', 'search-via-input', {
event_category: 'glyph-search',
event_label: 'Cheat Sheet : ' + (e.target && e.target.value),
value: e.target && e.target.value
});
searchGlyphs();
}, 500)
);
// search via search button
elementGlyphSearchButton && elementGlyphSearchButton.addEventListener(
'click',
() => {
gtag('event', 'search-via-button', {
event_category: 'glyph-search',
event_label: 'Cheat Sheet : ' + (e.target && e.target.value),
value: e.target && e.target.value
});
searchGlyphs();
}
)
// search all via search all button
elementGlyphSearchAllButton && elementGlyphSearchAllButton.addEventListener(
'click',
() => {
gtag('event', 'search-all-via-button', {
event_category: 'glyph-search',
event_label: 'Cheat Sheet : all',
value: 'all'
});
searchAllGlyphs();
}
);
// Credit David Walsh (https://davidwalsh.name/javascript-debounce-function)
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
var timeout;
return function executedFunction() {
var context = this;
var args = arguments;
var later = function () {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
function searchAllGlyphs() {
elementGlyphSearch.value = '';
searchGlyphs();
}
function searchGlyphs() {
const filter = elementGlyphSearch.value.toLowerCase();
const elements = elementGlyphCheatSheet.querySelectorAll('.column');
const length = elements.length;
let i = 0;
let elementClassName, elementCodePoint;
let anyVisibleColumns = false;
for (; i < length; i++) {
elementClassName = elements[i].querySelector('div.class-name');
elementCodePoint = elements[i].querySelector('div.codepoint');
if (elementClassName && elementCodePoint) {
if (
elementClassName
.textContent
.indexOf(filter) > -1 ||
elementCodePoint
.textContent
.indexOf(filter) > -1
) {
elementClassName.parentNode.classList.add('is-visible');
anyVisibleColumns = true;
} else {
elementClassName.parentNode.classList.remove('is-visible');
}
}
}
if (anyVisibleColumns) {
elementGlyphCheatSheet.classList.add('has-results');
}
else {
elementGlyphCheatSheet.classList.remove('has-results');
}
}
// extremely basic filtering on load:
function getParameterByName(name, url) {
if (!url) {
@ -240,116 +127,6 @@ document.addEventListener('DOMContentLoaded', function () {
}
}
/* hold on to yer' butts */
// Copies a string to the clipboard. Must be called from within an
// event handler such as click. May return false if it failed, but
// this is not always possible. Browser support for Chrome 43+,
// Firefox 42+, Safari 10+, Edge and IE 10+.
// IE: The clipboard feature may be disabled by an administrator. By
// default a prompt is shown the first time the clipboard is
// used (per session).
function copyToClipboard(text) {
if (window.clipboardData && window.clipboardData.setData) {
// IE specific code path to prevent textarea being shown while dialog is visible.
return clipboardData.setData('Text', text);
} else if (document.queryCommandSupported && document.queryCommandSupported('copy')) {
var textarea = document.createElement('textarea');
textarea.textContent = text;
textarea.style.position = 'fixed'; // Prevent scrolling to bottom of page in MS Edge.
document.body.appendChild(textarea);
textarea.select();
try {
return document.execCommand('copy'); // Security exception may be thrown by some browsers.
} catch (ex) {
console.warn('Copy to clipboard failed.', ex);
return false;
} finally {
document.body.removeChild(textarea);
}
}
}
elementGlyphCheatSheet && elementGlyphCheatSheet.addEventListener(
'mouseenter',
function (e) {
if (e.target.classList.contains('column')) {
// add Node
const newNode = document.createElement('span');
const copyTextNode = document.createElement('span');
const copyGlyphNode = document.createElement('span');
const copyClassNode = document.createElement('span');
const copyCodePoint = document.createElement('span');
newNode.className = 'glyph-popout-copy-clipboard';
copyTextNode.innerText = 'Copy';
copyGlyphNode.innerText = 'Icon';
copyClassNode.innerText = 'Class';
copyCodePoint.innerText = 'UTF';
copyGlyphNode.title = 'Copy Icon to Clipboard';
copyClassNode.title = 'Copy Class Name to Clipboard';
copyCodePoint.title = 'Copy UTF-16 Codes to Clipboard';
copyGlyphNode.className = 'copy-glyph';
copyClassNode.className = 'copy-class';
copyCodePoint.className = 'copy-utf16';
newNode.appendChild(copyTextNode);
newNode.appendChild(copyGlyphNode);
newNode.appendChild(copyClassNode);
newNode.appendChild(copyCodePoint);
e.target.children[0].before(newNode);
}
},
true
);
elementGlyphCheatSheet && elementGlyphCheatSheet.addEventListener(
'mouseleave',
function (e) {
if (e.target.classList.contains('column')) {
e.target.querySelector('.glyph-popout-copy-clipboard').remove();
}
},
true
);
elementGlyphCheatSheet && elementGlyphCheatSheet.addEventListener('click', function (event) {
let textToCopy = '';
let target = event.target;
let parent = target.parentNode;
if (parent.className === 'glyph-popout-copy-clipboard') {
if (target.className === 'copy-class') {
textToCopy = parent.parentNode.querySelector('.class-name').innerText;
} else if (target.className === 'copy-glyph') {
textToCopy = window
.getComputedStyle(document.querySelector(`.${parent.parentNode.querySelector('.class-name').innerText}`), ':before')
.getPropertyValue('content')
.replace(/"/g, '');
} else if (target.className === 'copy-utf16') {
const glyph = window
.getComputedStyle(document.querySelector(`.${parent.parentNode.querySelector('.class-name').innerText}`), ':before')
.getPropertyValue('content')
.replace(/"/g, '');
textToCopy = '';
let i = 0;
while (i < 10) {
let c = glyph.charCodeAt(i++); // js strings are utf16 already :-)
if (!(c > 0)) break;
if (c <= 0x32) continue;
textToCopy += '\\u' + c.toString(16);
}
}
} else if (parent.className.startsWith('column') && target.className === 'codepoint') {
textToCopy = target.innerText;
}
if (textToCopy.length > 0) {
gtag('event', event.target.className, {
event_category: 'clipboard-copy',
event_label: 'Copy To Clipboard : ' + textToCopy,
value: textToCopy
});
copyToClipboard(textToCopy);
}
});
// lazy load images
(function lazyLoadImages() {
const imageObserver = new IntersectionObserver((entries, imgObserver) => {