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 `
  • ` 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( ''), 'pages': SvgElement.svg( ''), 'toc': SvgElement.svg( ''), 'share': SvgElement.svg( ''), 'twitter': SvgElement.svg( ''), 'reddit': SvgElement.svg( ''), 'email': SvgElement.svg( ''), 'linkedin': SvgElement.svg( ''), 'facebook': SvgElement.svg( ''), 'theme': SvgElement.svg( ''), 'sun': SvgElement.svg( ''), 'lightbulb': SvgElement.svg( ''), 'moon': SvgElement.svg( ''), }; // Get the current page’s title String getPageTitle() => querySelector('title').text; // Create the home button Future 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 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 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 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 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 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; }