diff --git a/TODOs.org b/TODOs.org new file mode 100644 index 0000000..d9217bd --- /dev/null +++ b/TODOs.org @@ -0,0 +1,14 @@ +* TODO Organization of HTML [1/3] +** DONE Add button to display TOC + CLOSED: [2020-04-28 mar. 22:30] +** TODO Add link to images that don’t have any +** TODO Add share links [0/3] +*** TODO Add Twitter share +*** TODO Add Email share +*** TODO Add LinkedIn share +*** TODO Add Facebook share +* TODO Styling [1/3] +** TODO Tables +** DONE Hint bubbles for phonetics (Ñyqy) + CLOSED: [2020-04-28 mar. 22:31] +** TODO Links diff --git a/web/dart/main.dart b/web/dart/main.dart index 8f0b60d..16c3a23 100644 --- a/web/dart/main.dart +++ b/web/dart/main.dart @@ -1,7 +1,8 @@ import './reorganize_html.dart' show reorganizeHtml; -import './theme.dart' show makeThemeChanger; +import './theme.dart' show makeThemeChanger, setTheme; Future main() async { + await setTheme(); await reorganizeHtml().then((_) { makeThemeChanger(); }); diff --git a/web/dart/reorganize_html.dart b/web/dart/reorganize_html.dart index 8f9c769..b66902c 100644 --- a/web/dart/reorganize_html.dart +++ b/web/dart/reorganize_html.dart @@ -7,74 +7,103 @@ String getPageTitle() { return querySelector('title').text; } +Element makeIcon(List classes, [String id]) { + final icon = Element.tag('i')..classes.addAll(classes); + if (id != null) { + icon.attributes['id'] = id; + } + return icon; +} + Future addLanguages(Element navbar) async { // Languages - var languages = Element.ul()..classes.add('dropdown'); + var languages = Element.ul() + ..attributes['id'] = 'drop-lang' + ..classes.add('dropdown'); await parseSitemap().then((final sitemap) => { sitemap.forEach((url, name) { - final link = Element.a() - ..attributes['href'] = url - ..innerText = name; - - final linkLi = Element.li() + final link = Element.li() ..classes.add('dropdown-item') - ..insertAdjacentElement('afterBegin', link); - - languages.insertAdjacentElement('beforeEnd', linkLi); + ..insertAdjacentElement( + 'afterBegin', + Element.a() + ..attributes['href'] = url + ..innerText = name); + languages.insertAdjacentElement('beforeEnd', link); }) }); navbar.append(Element.li() ..append(Element.a() - ..attributes['href'] = '#' - ..innerText = 'Langues') - ..classes.add('nav-item') - ..classes.add('has-dropdown') + ..attributes['href'] = 'javascript:void(0)' + ..append(makeIcon(['fas', 'fa-language']))) + // ..innerText = 'Langues') + ..classes.addAll(['nav-item', 'has-dropdown']) ..insertAdjacentElement('beforeEnd', languages)); return navbar; } +Element makeTocDropDown() { + return Element.li() + ..attributes['id'] = 'toc-drop' + ..classes.addAll(['nav-item', 'has-dropdown']) + ..append(Element.a() + ..attributes['href'] = 'javascript:void(0)' + ..append(makeIcon(['fas', 'fa-list-ol'], 'tocBtn'))); +} + +Element makeThemeChanger() { + Element makeThemeItem(String t_btnId, Element t_icon, String t_text) { + return Element.li() + ..classes.add('dropdown-item') + ..append(Element.span() + ..attributes['id'] = t_btnId + ..append(t_icon) + ..appendText(' $t_text')); + } + + return Element.li() + ..classes.addAll(['nav-item', 'has-dropdown']) + ..append(Element.a() + ..attributes['href'] = 'javascript:void(0)' + ..append(makeIcon(['fas', 'fa-sun'])) + ..append(makeIcon(['fas', 'fa-moon']))) + ..append(Element.ul() + ..classes.add('dropdown') + ..attributes['id'] = 'theme-dropdown' + ..append(makeThemeItem('lightBtn', makeIcon(['fas', 'fa-sun']), 'Clair')) + ..append(makeThemeItem('darkBtn', makeIcon(['fas', 'fa-lightbulb']), 'Sombre')) + ..append(makeThemeItem('blackBtn', makeIcon(['fas', 'fa-moon']), 'Noir'))); +} + // Add a navbar atop of the HTML body, containing two buttons: // - One back to home // - A dropdown to each language detected in the sitemap Future makeNavbar() async { - // var _navbar = Navbar(); + var navbar_content = Element.ul()..classes.add('navbar-nav'); // Home - var navbar_content = Element.ul()..classes.add('navbar-nav'); navbar_content.append(Element.li() ..classes.add('nav-item') ..insertAdjacentElement( 'afterBegin', Element.a() ..attributes['href'] = '/' - ..innerText = 'Accueil')); + ..append(makeIcon(['fas', 'fa-home'])))); + + // TOC icon + navbar_content.append(makeTocDropDown()); // Add languages - // navbar_content.append(Element.html(''' - - // ''')); navbar_content = await addLanguages(navbar_content); - // Page title - navbar_content.append(Element.li() - ..classes.add('nav-item') - ..innerText = getPageTitle()); - // Share icon - // Add dropdown for sharing on multiple platforms + // TODO Add dropdown for sharing on multiple platforms navbar_content = addIcon(navbar_content, ['fas', 'fa-share-alt'], 'shareBtn'); // Theme changer - // Add dropdown for theming - // navbar_content = addIcon(navbar_content, ['fas', 'fa-sun'], 'themeBtn'); - navbar_content.append(Element.html(''' -''')); + var theme = window.localStorage['theme']; + theme = (theme == null || theme == 'light') ? 'fa-moon' : 'fa-sun'; + navbar_content.append(makeThemeChanger()); // Navbar content added to navbar final navbar = Element.nav() @@ -85,14 +114,31 @@ Future makeNavbar() async { } Element addIcon(Element navbar, List classes, String id) { - var elem = Element.tag('i')..attributes['id'] = id; - for (var c in classes) { - elem.classes.add(c); - } - navbar.append(Element.li()..append(elem)); + final icon = makeIcon(classes, id); + navbar.append(Element.li()..append(icon)); return navbar; } +Element makeHeader() { + var header = Element.tag('header'); + + // querySelector('#container').append(Element.tag('header')); + // var header = querySelector('header'); + header + ..append(Element.img() + ..attributes['src'] = + 'https://cdn.phundrak.com/img/mahakala-monochrome.png' + ..attributes['alt'] = 'Logo de Phundrak' + ..attributes['heigh'] = '150px' + ..attributes['width'] = '150px') + ..append(querySelector('h1')); + var subt = querySelector('.subtitle'); + if (subt != null) { + header.append(subt); + } + return header; +} + Future wrapTables() async { for (var table in querySelectorAll('table')) { var largetable = DivElement()..className = 'largetable'; @@ -101,24 +147,19 @@ Future wrapTables() async { } } -Future makeHeader() async { - querySelector('body') - .insertAdjacentElement('afterBegin', Element.tag('header')); - querySelector('header').append(querySelector('h1')); - querySelector('header').append(querySelector('.subtitle')); -} - Future reorganizeHtml() async { - await makeHeader(); - await wrapTables(); + // Create navbar and then header await makeNavbar().then((navbar) { + // querySelector('#toc-drop') + // .append(querySelector('#table-of-contents')..classes.add('dropdown')); querySelector('body').insertAdjacentElement('afterBegin', navbar); + // querySelector('nav').insertAdjacentElement( + // 'afterEnd', Element.div()..attributes['id'] = 'container'); + querySelector('nav').insertAdjacentElement('afterEnd', makeHeader()); + querySelector('#toc-drop') + .append(querySelector('#table-of-contents')..classes.add('dropdown')); }); - querySelector('body') - ..classes.add('light') - // Add a
element after the content div - ..appendHtml('
') - // Move the postamble in the content div - ..append(querySelector('#postamble')); + // wrap tables in container for better SCSS display + await wrapTables(); } diff --git a/web/dart/theme.dart b/web/dart/theme.dart index 37d5e76..c888685 100644 --- a/web/dart/theme.dart +++ b/web/dart/theme.dart @@ -1,20 +1,53 @@ import 'dart:html'; -void switchTheme(final Element body, String theme) { - body.classes.clear(); - body.classes.add(theme); +class Theme { + String _name; + String _icon; + + Theme(String t_name, String t_icon) { + _name = t_name; + _icon = t_icon; + } + + String getIcon() => _icon; + String getName() => _name; } +final themes = { + 'light': Theme('light', 'fa-sun'), + 'dark': Theme('dark', 'fa-lightbulb'), + 'black': Theme('black', 'fa-moon') +}; + +final localStorage = window.localStorage; + +var currentTheme = themes[localStorage['theme']]; + void makeThemeChanger() { final darkBtn = querySelector('#darkBtn'); final lightBtn = querySelector('#lightBtn'); - final body = querySelector('body'); + final blackBtn = querySelector('#blackBtn'); - darkBtn.onClick.listen((_) { - switchTheme(body, 'dark'); - }); - - lightBtn.onClick.listen((_) { - switchTheme(body, 'light'); - }); + lightBtn.onClick.listen((_) => switchTheme(themes['light'])); + darkBtn.onClick.listen((_) => switchTheme(themes['dark'])); + blackBtn.onClick.listen((_) => switchTheme(themes['black'])); +} + +Future setTheme() async { + if (currentTheme == null) { + currentTheme = themes['light']; + localStorage['theme'] = currentTheme.getName(); + } + querySelector('body') + ..classes.clear() + ..classes.add(currentTheme.getName()); +} + +void switchTheme(Theme currentTheme) { + // Set HTML theme + querySelector('body') + ..classes.clear() + ..classes.add(currentTheme.getName()); + // Set storage theme + localStorage['theme'] = currentTheme.getName(); } diff --git a/web/style/style.scss b/web/style/style.scss index bbb30db..47d080a 100644 --- a/web/style/style.scss +++ b/web/style/style.scss @@ -2,7 +2,7 @@ @font-face { font-family: "DoulosSIL"; font-display: swap; - src: url("https://langue.phundrak.com/fonts/DoulosSIL-R.woff"); + src: url("/fonts/DoulosSIL-R.woff"); } @font-face { font-family: "Noto Sans Runes"; @@ -17,70 +17,158 @@ // Themes ///////////////////////////////////////////////////////////////////// -$dark: rgba(52, 73, 94, 1); -$accent1: rgba(66, 191, 221, 1); -$accent2: rgba(92, 172, 126, 1); -$accent3: rgba(197, 193, 155, 1); -$light: #ddd; -$grey1: #f8f8f8; -$grey2: #dbe1e8; -$grey3: #b2becd; -$grey4: #6c7983; -$grey5: #454e56; -$grey6: #12181b; -$gradient-top: linear-gradient(0deg, $dark, $accent1, $accent2, $accent3, $light); -$gradient-right: linear-gradient(90deg, $dark, $accent1, $accent2, $accent3, $light); -$gradient-bottom: linear-gradient(180deg, $dark, $accent1, $accent2, $accent3, $light); -$gradient-left: linear-gradient(270deg, $dark, $accent1, $accent2, $accent3, $light); -$gradient-top-right: linear-gradient(45deg, $dark, $accent1, $accent2, $accent3, $light); -$gradient-bottom-right: linear-gradient(135deg, $dark, $accent1, $accent2, $accent3, $light); -$gradient-top-left: linear-gradient(225deg, $dark, $accent1, $accent2, $accent3, $light); -$gradient-bottom-left: linear-gradient(315deg, $dark, $accent1, $accent2, $accent3, $light); -$gradient-radial: radial-gradient( $dark, $accent1, $accent2, $accent3, $light); +$dark: rgba( 52, 73, 94, 1); +$black: rgba( 0, 0, 0, 1); +$accent1: rgba( 93, 115, 126, 1); +$accent2: rgba( 92, 172, 126, 1); +$accent3: rgba(197, 193, 155, 1); +$light: rgba(252, 239, 249, 1); +$grey1: #f8f8f8; +$grey2: #dbe1e8; +$grey3: #b2becd; +$grey4: #6c7983; +$grey5: #454e56; +$grey6: #12181b; + +// Accent 1 +// Black +$gradient-accent1-black-left: linear-gradient(to left, $black, $accent1, $accent1); +$gradient-accent1-black-right: linear-gradient(to right, $black, $accent1, $accent1); +// Dark +$gradient-accent1-dark-left: linear-gradient(to left, $dark, $accent1); +$gradient-accent1-dark-right: linear-gradient(to right, $dark, $accent1); +// Light +$gradient-accent1-light-left: linear-gradient(to left, $light, $accent1); +$gradient-accent1-light-right: linear-gradient(to right, $light, $accent1); +// Accent 2 +// Black +$gradient-accent2-black-left: linear-gradient(to left, $black, $accent2, $accent2); +$gradient-accent2-black-right: linear-gradient(to right, $black, $accent2, $accent2); +// Dark +$gradient-accent2-dark-left: linear-gradient(to left, $dark, $accent2); +$gradient-accent2-dark-right: linear-gradient(to right, $dark, $accent2); +// Light +$gradient-accent2-light-left: linear-gradient(to left, $light, $accent2); +$gradient-accent2-light-right: linear-gradient(to right, $light, $accent2); +// Accent 3 +// Black +$gradient-accent3-black-left: linear-gradient(to left, $black, $accent3, $accent3); +$gradient-accent3-black-right: linear-gradient(to right, $black, $accent3, $accent3); +// Dark +$gradient-accent3-dark-left: linear-gradient(to left, $dark, $accent3); +$gradient-accent3-dark-right: linear-gradient(to right, $dark, $accent3); +// Light +$gradient-accent3-light-left: linear-gradient(to left, $light, $accent3); +$gradient-accent3-light-right: linear-gradient(to right, $light, $accent3); + +$navbar-height: 70px; +$postamble-height: 55px; .light { - $bg-nav: linear-gradient(to right, $grey1, $grey3); - $bg-dropdown: $grey1; - $text: $light; + $bg-nav: $gradient-accent3-light-right; $border-color: $accent1; - $bg-solar: $accent3; - - transition: background 500ms ease-in-out, color 1s ease-in-out; color: $dark; background: $light; - .navbar { - background: $grey3; + transition: background 500ms ease-in-out, color 1s ease-in-out; + + .navbar, header { + background: $bg-nav; + } + + .status { + background: $gradient-accent3-light-left; + color: $dark; + } + + .tooltip { + border-bottom: 1px dotted $accent3; + + .tooltiptext { + background-color: $accent3; + color: $dark; + + &::after { + border-color: $accent3 transparent transparent transparent; + } + } + } + + .dropdown { + background: $accent3; + color: $dark; } } -.dark { - $background: $dark; - $foreground: $light; - $bg-nav: linear-gradient(to right, $grey5, $grey6); - $bg-dropdown: $grey6; - $text: $dark; +.dark, .black { + $bg-nav: $gradient-accent2-dark-right; $border-color: $dark; - $bg-solar: $accent3; - - transition: background 500ms ease-in-out, color 1s ease-in-out; color: $light; background: $dark; - .navbar { + transition: background 500ms ease-in-out, color 1s ease-in-out; + + .navbar, header { + background: $bg-nav; + } + + .status { + background: $gradient-accent2-dark-left; + color: $light; + } + + .tooltip { + border-bottom: 1px dotted $accent1; + + .tooltiptext { + background-color: $accent1; + color: $light; + + &::after { + border-color: $accent1 transparent transparent transparent; + } + } + } + + .dropdown { + background: $accent3; + color: $dark; + } +} + +.black { + $bg-nav: $gradient-accent1-black-right; + + background: $black; + + .navbar, header { + background: $bg-nav; + } + + .status { + background: $gradient-accent1-black-left; + } + + .dropdown { + background: $dark; color: $light; - background: $grey6; } } /* Style *********************************************************************/ +* { + outline: none; +} + body { margin: 0; padding: 0; font-family: "Noto Sans Runes", "DoulosSIL", "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif; + font-size: 1.2em; + transition: background 500ms ease-in-out, color 1s ease-in-out; header, .navbar { @@ -100,7 +188,10 @@ a { } .navbar { - height: 70px; + position: fixed; + top: 0; + z-index: 4; + height: $navbar-height; width: 100%; } @@ -109,27 +200,22 @@ a { align-items: center; justify-content: space-evenly; height: 100%; - background: $accent3; - color: $dark; } header { padding: 1em; + margin-top: $navbar-height; margin-bottom: 1em; padding-bottom: 3.5em; text-align: center; - clip-path: polygon(50% 0%, 100% 0, 100% 65%, 50% 100%, 0 65%, 0 0); - color: $light; - background: $accent2; + clip-path: polygon(50% 0%, 100% 0, 100% 80%, 50% 100%, 0 80%, 0 0); + transition: background 500ms ease-in-out; } .dropdown { position: absolute; - width: 500px; opacity: 0; - z-index: 2; - background: blue; - border-top: 2px solid white; + z-index: 5; border-bottom-right-radius: 8px; border-bottom-left-radius: 8px; @@ -137,8 +223,8 @@ header { display: flex; align-items: center; justify-content: space-around; - height: 3rem; - margin-top: 2rem; + min-height: 3rem; + margin-top: 1rem; padding: 0.5rem; box-shadow: rgba(2, 8, 20, 0.1) 0px 0.175em 0.5em; @@ -148,8 +234,14 @@ header { } #theme-dropdown { - width: 300px; - transform: translateX(-95%); + width: 250px; + flex-direction: row; + transform: translateX(-50%); +} + +#drop-lang { + flex-direction: column; + transform: translateX(-40%); } .has-dropdown { @@ -158,15 +250,127 @@ header { opacity: 1; pointer-events: auto; } + + #table-of-contents { + opacity: 1; + height: 500%; + pointer-events: auto; + } } } .dropdown-item { + cursor: pointer; + a { width: 100%; height: 100%; size: 0.7rem; padding-left: 10px; + padding-right: 10px; font-weight: bold; } } + +#table-of-contents { + flex-direction: column; + padding: 20px; + float: right; + overflow-y: auto; + height: 0%; + width: 400px; + transform: translateX(0); + transition: height 500ms ease-in-out, opacity 500ms ease-in-out; + font-size: 0.9em; + + h2 { + font-size: 1.2em; + } + + #text-table-of-contents { + height: 100%; + } +} + +#content { + padding: 50px; + padding-top: 0; + max-width: 700px; + margin: 0 auto; + + text-align: justify; +} + +#postamble { + display: grid; + grid-template-areas: 'author email date'; + height: $postamble-height; + + font-size: 0.8em; + align-content: space-evenly; + text-align: center; + + .author { + grid-area: author; + } + + .email { + grid-area: email; + } + + .date { + grid-area: date; + } +} + +h1, h2, h3, h4, h5, h6 { + text-align: center; +} + +h2 { + font-size: 3em; +} + +h3 { + font-size: 2em; +} + +h4 { + font-size: 1.5em; +} + +.tooltip { + position: relative; + display: inline-block; + + .tooltiptext { + visibility: hidden; + + width: 120px; + margin-left: -60px; /* Half the width */ + bottom: 100%; + left: 50%; + padding: 5px 0; + text-align: center; + border-radius: 6px; + + position: absolute; + z-index: 2; + + &::after { + content: " "; + position: absolute; + top: 100%; /* At the bottom of the tooltip */ + left: 50%; + margin-left: -5px; + border-width: 5px; + border-style: solid; + } + } + + &:hover { + .tooltiptext { + visibility: visible; + } + } +}