156 lines
11 KiB
Dart
156 lines
11 KiB
Dart
import 'dart:html';
|
|
import 'dart:svg';
|
|
|
|
// 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>'),
|
|
};
|
|
|
|
String getPageTitle() => querySelector('title').text;
|
|
|
|
Element makeIcon(SvgElement t_elem) {
|
|
final icon = t_elem
|
|
..classes.add('nav-icon');
|
|
return icon;
|
|
}
|
|
|
|
Future<Element> makeToc() async {
|
|
return Element.li()
|
|
..attributes['id'] = 'toc-drop'
|
|
..classes.addAll(['nav-item', 'has-dropdown'])
|
|
..append(Element.a()
|
|
..attributes['href'] = 'javascript:void(0)'
|
|
..append(makeIcon(icons['toc'])));
|
|
}
|
|
|
|
Future<Element> makePages() async {
|
|
var pages = Element.ul()
|
|
..attributes['id'] = 'drop-page'
|
|
..classes.add('dropdown');
|
|
return Element.li()
|
|
..append(Element.a()
|
|
..attributes['href'] = 'javascript:void(0)'
|
|
..append(makeIcon(icons['pages'])))
|
|
..classes.addAll(['nav-item', 'has-dropdown'])
|
|
..append(pages);
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
Future<Element> makeShare() async {
|
|
return Element.li()
|
|
..classes.addAll(['nav-item', 'has-dropdown'])
|
|
..append(Element.a()
|
|
..attributes['href'] = 'javascript:void(0)'
|
|
..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}')));
|
|
}
|
|
|
|
Future<Element> makeThemeChanger() async {
|
|
Element makeThemeItem(String t_btnId, String t_text, [Element t_icon]) {
|
|
return Element.li()
|
|
..classes.add('dropdown-item')
|
|
..append(Element.span()
|
|
..attributes['id'] = t_btnId
|
|
..appendText(' $t_text'));
|
|
}
|
|
|
|
return Element.li()
|
|
..classes.addAll(['nav-item', 'has-dropdown'])
|
|
..append(Element.a()
|
|
..attributes['href'] = 'javascript:void(0)'
|
|
..append(Element.span()
|
|
..style.verticalAlign = 'top'
|
|
..append(makeIcon(icons['theme']))))
|
|
..append(Element.ul()
|
|
..classes.add('dropdown')
|
|
..attributes['id'] = 'theme-dropdown'
|
|
..append(makeThemeItem('lightBtn', 'Clair', makeIcon(icons['sun'])))
|
|
..append(makeThemeItem('darkBtn', 'Sombre', makeIcon(icons['lightbulb'])))
|
|
..append(makeThemeItem('blackBtn', 'Noir', makeIcon(icons['moon']))));
|
|
}
|
|
|
|
Future<Element> makeHome() async {
|
|
return Element.li()
|
|
..classes.add('nav-item')
|
|
..insertAdjacentElement(
|
|
'afterBegin',
|
|
Element.a()
|
|
..attributes['href'] = '/'
|
|
..append(makeIcon(icons['home'])));
|
|
}
|
|
|
|
// Add a navbar atop of the HTML body, containing two buttons:
|
|
// - One back to home
|
|
// - A dropdown to each page detected in the sitemap
|
|
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;
|
|
}
|