Lucien Cartier-Tilet
8b984e301f
Also make website more mobile-friendly for smaller devices. And ignore temporary scssc files from cache SCSS compiling.
183 lines
12 KiB
Dart
183 lines
12 KiB
Dart
import 'dart:html';
|
||
import 'dart:svg';
|
||
|
||
// You will see here and there some 'tabindex' attributes added to various HTML
|
||
// elements, and I’m sure you will ask "Why? They don’t serve any purpose, do
|
||
// they?". Well you are wrong. Webkit has a **terrible** implementation of
|
||
// `:focus-within`, and the dropdowns will **not** work unless the parent
|
||
// element, in this case a `<li>` has a `tabindex` attribute set to `0` and its
|
||
// first child set to `-1`.
|
||
//
|
||
// Screw WebKit, and screw Apple for using such a terrible web engine.
|
||
|
||
// Icons from https://materialdesignicons.com/
|
||
final icons = {
|
||
'home': SvgElement.svg(
|
||
'<svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M10,20V14H14V20H19V12H22L12,3L2,12H5V20H10Z" /></svg>'),
|
||
'pages': SvgElement.svg(
|
||
'<svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M19,2L14,6.5V17.5L19,13V2M6.5,5C4.55,5 2.45,5.4 1,6.5V21.16C1,21.41 1.25,21.66 1.5,21.66C1.6,21.66 1.65,21.59 1.75,21.59C3.1,20.94 5.05,20.5 6.5,20.5C8.45,20.5 10.55,20.9 12,22C13.35,21.15 15.8,20.5 17.5,20.5C19.15,20.5 20.85,20.81 22.25,21.56C22.35,21.61 22.4,21.59 22.5,21.59C22.75,21.59 23,21.34 23,21.09V6.5C22.4,6.05 21.75,5.75 21,5.5V7.5L21,13V19C19.9,18.65 18.7,18.5 17.5,18.5C15.8,18.5 13.35,19.15 12,20V13L12,8.5V6.5C10.55,5.4 8.45,5 6.5,5V5Z" /></svg>'),
|
||
'toc': SvgElement.svg(
|
||
'<svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M3,4H7V8H3V4M9,5V7H21V5H9M3,10H7V14H3V10M9,11V13H21V11H9M3,16H7V20H3V16M9,17V19H21V17H9"/></svg>'),
|
||
'share': SvgElement.svg(
|
||
'<svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M18,16.08C17.24,16.08 16.56,16.38 16.04,16.85L8.91,12.7C8.96,12.47 9,12.24 9,12C9,11.76 8.96,11.53 8.91,11.3L15.96,7.19C16.5,7.69 17.21,8 18,8A3,3 0 0,0 21,5A3,3 0 0,0 18,2A3,3 0 0,0 15,5C15,5.24 15.04,5.47 15.09,5.7L8.04,9.81C7.5,9.31 6.79,9 6,9A3,3 0 0,0 3,12A3,3 0 0,0 6,15C6.79,15 7.5,14.69 8.04,14.19L15.16,18.34C15.11,18.55 15.08,18.77 15.08,19C15.08,20.61 16.39,21.91 18,21.91C19.61,21.91 20.92,20.61 20.92,19A2.92,2.92 0 0,0 18,16.08Z" /></svg>'),
|
||
'twitter': SvgElement.svg(
|
||
'<svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M22.46,6C21.69,6.35 20.86,6.58 20,6.69C20.88,6.16 21.56,5.32 21.88,4.31C21.05,4.81 20.13,5.16 19.16,5.36C18.37,4.5 17.26,4 16,4C13.65,4 11.73,5.92 11.73,8.29C11.73,8.63 11.77,8.96 11.84,9.27C8.28,9.09 5.11,7.38 3,4.79C2.63,5.42 2.42,6.16 2.42,6.94C2.42,8.43 3.17,9.75 4.33,10.5C3.62,10.5 2.96,10.3 2.38,10C2.38,10 2.38,10 2.38,10.03C2.38,12.11 3.86,13.85 5.82,14.24C5.46,14.34 5.08,14.39 4.69,14.39C4.42,14.39 4.15,14.36 3.89,14.31C4.43,16 6,17.26 7.89,17.29C6.43,18.45 4.58,19.13 2.56,19.13C2.22,19.13 1.88,19.11 1.54,19.07C3.44,20.29 5.7,21 8.12,21C16,21 20.33,14.46 20.33,8.79C20.33,8.6 20.33,8.42 20.32,8.23C21.16,7.63 21.88,6.87 22.46,6Z" /></svg>'),
|
||
'reddit': SvgElement.svg(
|
||
'<svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M14.5 15.41C14.58 15.5 14.58 15.69 14.5 15.8C13.77 16.5 12.41 16.56 12 16.56C11.61 16.56 10.25 16.5 9.54 15.8C9.44 15.69 9.44 15.5 9.54 15.41C9.65 15.31 9.82 15.31 9.92 15.41C10.38 15.87 11.33 16 12 16C12.69 16 13.66 15.87 14.1 15.41C14.21 15.31 14.38 15.31 14.5 15.41M10.75 13.04C10.75 12.47 10.28 12 9.71 12C9.14 12 8.67 12.47 8.67 13.04C8.67 13.61 9.14 14.09 9.71 14.08C10.28 14.08 10.75 13.61 10.75 13.04M14.29 12C13.72 12 13.25 12.5 13.25 13.05S13.72 14.09 14.29 14.09C14.86 14.09 15.33 13.61 15.33 13.05C15.33 12.5 14.86 12 14.29 12M22 12C22 17.5 17.5 22 12 22S2 17.5 2 12C2 6.5 6.5 2 12 2S22 6.5 22 12M18.67 12C18.67 11.19 18 10.54 17.22 10.54C16.82 10.54 16.46 10.7 16.2 10.95C15.2 10.23 13.83 9.77 12.3 9.71L12.97 6.58L15.14 7.05C15.16 7.6 15.62 8.04 16.18 8.04C16.75 8.04 17.22 7.57 17.22 7C17.22 6.43 16.75 5.96 16.18 5.96C15.77 5.96 15.41 6.2 15.25 6.55L12.82 6.03C12.75 6 12.68 6.03 12.63 6.07C12.57 6.11 12.54 6.17 12.53 6.24L11.79 9.72C10.24 9.77 8.84 10.23 7.82 10.96C7.56 10.71 7.2 10.56 6.81 10.56C6 10.56 5.35 11.21 5.35 12C5.35 12.61 5.71 13.11 6.21 13.34C6.19 13.5 6.18 13.62 6.18 13.78C6.18 16 8.79 17.85 12 17.85C15.23 17.85 17.85 16.03 17.85 13.78C17.85 13.64 17.84 13.5 17.81 13.34C18.31 13.11 18.67 12.6 18.67 12Z" /></svg>'),
|
||
'email': SvgElement.svg(
|
||
'<svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M20,8L12,13L4,8V6L12,11L20,6M20,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V6C22,4.89 21.1,4 20,4Z" /></svg>'),
|
||
'linkedin': SvgElement.svg(
|
||
'<svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M19 3A2 2 0 0 1 21 5V19A2 2 0 0 1 19 21H5A2 2 0 0 1 3 19V5A2 2 0 0 1 5 3H19M18.5 18.5V13.2A3.26 3.26 0 0 0 15.24 9.94C14.39 9.94 13.4 10.46 12.92 11.24V10.13H10.13V18.5H12.92V13.57C12.92 12.8 13.54 12.17 14.31 12.17A1.4 1.4 0 0 1 15.71 13.57V18.5H18.5M6.88 8.56A1.68 1.68 0 0 0 8.56 6.88C8.56 5.95 7.81 5.19 6.88 5.19A1.69 1.69 0 0 0 5.19 6.88C5.19 7.81 5.95 8.56 6.88 8.56M8.27 18.5V10.13H5.5V18.5H8.27Z" /></svg>'),
|
||
'facebook': SvgElement.svg(
|
||
'<svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M12 2.04C6.5 2.04 2 6.53 2 12.06C2 17.06 5.66 21.21 10.44 21.96V14.96H7.9V12.06H10.44V9.85C10.44 7.34 11.93 5.96 14.22 5.96C15.31 5.96 16.45 6.15 16.45 6.15V8.62H15.19C13.95 8.62 13.56 9.39 13.56 10.18V12.06H16.34L15.89 14.96H13.56V21.96A10 10 0 0 0 22 12.06C22 6.53 17.5 2.04 12 2.04Z" /></svg>'),
|
||
'theme': SvgElement.svg(
|
||
'<svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M12,18V6A6,6 0 0,1 18,12A6,6 0 0,1 12,18M20,15.31L23.31,12L20,8.69V4H15.31L12,0.69L8.69,4H4V8.69L0.69,12L4,15.31V20H8.69L12,23.31L15.31,20H20V15.31Z" /></svg>'),
|
||
'sun': SvgElement.svg(
|
||
'<svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M3.55,18.54L4.96,19.95L6.76,18.16L5.34,16.74M11,22.45C11.32,22.45 13,22.45 13,22.45V19.5H11M12,5.5A6,6 0 0,0 6,11.5A6,6 0 0,0 12,17.5A6,6 0 0,0 18,11.5C18,8.18 15.31,5.5 12,5.5M20,12.5H23V10.5H20M17.24,18.16L19.04,19.95L20.45,18.54L18.66,16.74M20.45,4.46L19.04,3.05L17.24,4.84L18.66,6.26M13,0.55H11V3.5H13M4,10.5H1V12.5H4M6.76,4.84L4.96,3.05L3.55,4.46L5.34,6.26L6.76,4.84Z" /></svg>'),
|
||
'lightbulb': SvgElement.svg(
|
||
'<svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M12,6A6,6 0 0,1 18,12C18,14.22 16.79,16.16 15,17.2V19A1,1 0 0,1 14,20H10A1,1 0 0,1 9,19V17.2C7.21,16.16 6,14.22 6,12A6,6 0 0,1 12,6M14,21V22A1,1 0 0,1 13,23H11A1,1 0 0,1 10,22V21H14M20,11H23V13H20V11M1,11H4V13H1V11M13,1V4H11V1H13M4.92,3.5L7.05,5.64L5.63,7.05L3.5,4.93L4.92,3.5M16.95,5.63L19.07,3.5L20.5,4.93L18.37,7.05L16.95,5.63Z" /></svg>'),
|
||
'moon': SvgElement.svg(
|
||
'<svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M17.75,4.09L15.22,6.03L16.13,9.09L13.5,7.28L10.87,9.09L11.78,6.03L9.25,4.09L12.44,4L13.5,1L14.56,4L17.75,4.09M21.25,11L19.61,12.25L20.2,14.23L18.5,13.06L16.8,14.23L17.39,12.25L15.75,11L17.81,10.95L18.5,9L19.19,10.95L21.25,11M18.97,15.95C19.8,15.87 20.69,17.05 20.16,17.8C19.84,18.25 19.5,18.67 19.08,19.07C15.17,23 8.84,23 4.94,19.07C1.03,15.17 1.03,8.83 4.94,4.93C5.34,4.53 5.76,4.17 6.21,3.85C6.96,3.32 8.14,4.21 8.06,5.04C7.79,7.9 8.75,10.87 10.95,13.06C13.14,15.26 16.1,16.22 18.97,15.95M17.33,17.97C14.5,17.81 11.7,16.64 9.53,14.5C7.36,12.31 6.2,9.5 6.04,6.68C3.23,9.82 3.34,14.64 6.35,17.66C9.37,20.67 14.19,20.78 17.33,17.97Z" /></svg>'),
|
||
};
|
||
|
||
// Get the current page’s title
|
||
String getPageTitle() => querySelector('title').text;
|
||
|
||
// Create the home button
|
||
Future<Element> makeHome() async {
|
||
return Element.li()
|
||
..classes.add('nav-item')
|
||
..insertAdjacentElement(
|
||
'afterBegin',
|
||
Element.a()
|
||
..attributes['href'] = '/'
|
||
..append(makeIcon(icons['home'])));
|
||
}
|
||
|
||
// Create a clickable icon
|
||
// `t_elem` must be an SVG declared in the above `icons` variable.
|
||
Element makeIcon(SvgElement t_elem) {
|
||
final icon = t_elem..classes.add('nav-icon');
|
||
return icon;
|
||
}
|
||
|
||
// Create the dropdown sitemap
|
||
Future<Element> makePages() async {
|
||
var pages = Element.ul()
|
||
..attributes['id'] = 'drop-page'
|
||
..classes.add('dropdown');
|
||
return Element.li()
|
||
..attributes['tabindex'] = '0'
|
||
..append(Element.a()
|
||
..attributes['tabindex'] = '-1'
|
||
..attributes['href'] = 'javascript:void(0)'
|
||
..append(makeIcon(icons['pages'])))
|
||
..classes.addAll(['nav-item', 'has-dropdown'])
|
||
..append(pages);
|
||
}
|
||
|
||
// Create the array of share icons
|
||
Future<Element> makeShare() async {
|
||
// Create a share button
|
||
Element makeShareLink(Element t_icon, String t_url) {
|
||
return Element.li()
|
||
..classes.add('dropdown-item')
|
||
..append(Element.a()
|
||
..attributes['href'] = t_url
|
||
..attributes['target'] = '_blank'
|
||
..attributes['rel'] = 'noreferrer'
|
||
..append(t_icon));
|
||
}
|
||
|
||
return Element.li()
|
||
..classes.addAll(['nav-item', 'has-dropdown'])
|
||
..attributes['tabindex'] = '0'
|
||
..append(Element.a()
|
||
..attributes['href'] = 'javascript:void(0)'
|
||
..attributes['tabindex'] = '-1'
|
||
..append(makeIcon(icons['share'])))
|
||
..append(Element.ul()
|
||
..classes.add('dropdown')
|
||
..attributes['id'] = 'drop-share'
|
||
..append(makeShareLink(
|
||
makeIcon(icons['twitter']),
|
||
'https://twitter.com/share?text=${getPageTitle()}'
|
||
'&url=${window.location.href}'))
|
||
..append(makeShareLink(makeIcon(icons['reddit']),
|
||
'https://www.reddit.com/submit?title=${getPageTitle()}s&url=${window.location.href}'))
|
||
..append(makeShareLink(makeIcon(icons['email']),
|
||
'mailto:?subject=${getPageTitle}&body=${window.location.href}'))
|
||
..append(makeShareLink(
|
||
makeIcon(icons['linkedin']),
|
||
'https://www.linkedin.com/shareArticle?mini=true&url=${window.location.href}'
|
||
'&title=${getPageTitle()}'))
|
||
..append(makeShareLink(makeIcon(icons['facebook']),
|
||
'https://www.facebook.com/sharer/sharer.php?u=${window.location.href}')));
|
||
}
|
||
|
||
// Create the theme changer
|
||
Future<Element> makeThemeChanger() async {
|
||
Element makeThemeItem(String t_btnId, [Element t_icon]) {
|
||
return Element.li()
|
||
..classes.add('dropdown-item')
|
||
..append(Element.span()..attributes['id'] = t_btnId);
|
||
}
|
||
|
||
return Element.li()
|
||
..classes.addAll(['nav-item', 'has-dropdown'])
|
||
..attributes['tabindex'] = '0'
|
||
..append(Element.a()
|
||
..attributes['href'] = 'javascript:void(0)'
|
||
..attributes['tabindex'] = '-1'
|
||
..append(Element.span()
|
||
..style.verticalAlign = 'top'
|
||
..append(makeIcon(icons['theme']))))
|
||
..append(Element.ul()
|
||
..classes.add('dropdown')
|
||
..attributes['id'] = 'theme-dropdown'
|
||
..append(makeThemeItem('lightBtn', makeIcon(icons['sun'])))
|
||
..append(makeThemeItem('darkBtn', makeIcon(icons['lightbulb'])))
|
||
..append(makeThemeItem('blackBtn', makeIcon(icons['moon']))));
|
||
}
|
||
|
||
// Create the dropdown table of contents
|
||
Future<Element> makeToc() async {
|
||
return Element.li()
|
||
..attributes['id'] = 'toc-drop'
|
||
..attributes['tabindex'] = '0'
|
||
..classes.addAll(['nav-item', 'has-dropdown'])
|
||
..append(Element.a()
|
||
..attributes['tabindex'] = '-1'
|
||
..attributes['href'] = 'javascript:void(0)'
|
||
..append(makeIcon(icons['toc'])));
|
||
}
|
||
|
||
// Add a navbar atop of the HTML body, containing:
|
||
// - A back to home button
|
||
// - A dropdown sitemap
|
||
// - A dropdown table of contents
|
||
// - A dropdown array of share icons
|
||
// - A theme changer
|
||
Future<Element> makeNavbar() async {
|
||
final navbar_content = Element.ul()..classes.add('navbar-nav');
|
||
final home = await makeHome();
|
||
final pages = await makePages();
|
||
final toc = await makeToc();
|
||
final share = await makeShare();
|
||
final theme = await makeThemeChanger();
|
||
|
||
navbar_content
|
||
..append(home)
|
||
..append(pages)
|
||
..append(toc)
|
||
..append(share)
|
||
..append(theme);
|
||
|
||
// Navbar content added to navbar
|
||
final navbar = Element.nav()
|
||
..classes.add('navbar')
|
||
..append(navbar_content);
|
||
|
||
return navbar;
|
||
}
|