Dart backend update and upgrade, visual overhaul, additionally some Ñyqy updates that were meant for master branch #1

Merged
phundrak merged 38 commits from develop into master 2020-05-05 11:44:27 +00:00
5 changed files with 414 additions and 121 deletions
Showing only changes of commit 7c9e8b1e5f - Show all commits

14
TODOs.org Normal file
View File

@ -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 dont 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

View File

@ -1,7 +1,8 @@
import './reorganize_html.dart' show reorganizeHtml; import './reorganize_html.dart' show reorganizeHtml;
import './theme.dart' show makeThemeChanger; import './theme.dart' show makeThemeChanger, setTheme;
Future<void> main() async { Future<void> main() async {
await setTheme();
await reorganizeHtml().then((_) { await reorganizeHtml().then((_) {
makeThemeChanger(); makeThemeChanger();
}); });

View File

@ -7,74 +7,103 @@ String getPageTitle() {
return querySelector('title').text; return querySelector('title').text;
} }
Element makeIcon(List<String> classes, [String id]) {
final icon = Element.tag('i')..classes.addAll(classes);
if (id != null) {
icon.attributes['id'] = id;
}
return icon;
}
Future<Element> addLanguages(Element navbar) async { Future<Element> addLanguages(Element navbar) async {
// Languages // Languages
var languages = Element.ul()..classes.add('dropdown'); var languages = Element.ul()
..attributes['id'] = 'drop-lang'
..classes.add('dropdown');
await parseSitemap().then((final sitemap) => { await parseSitemap().then((final sitemap) => {
sitemap.forEach((url, name) { sitemap.forEach((url, name) {
final link = Element.a() final link = Element.li()
..attributes['href'] = url
..innerText = name;
final linkLi = Element.li()
..classes.add('dropdown-item') ..classes.add('dropdown-item')
..insertAdjacentElement('afterBegin', link); ..insertAdjacentElement(
'afterBegin',
languages.insertAdjacentElement('beforeEnd', linkLi); Element.a()
..attributes['href'] = url
..innerText = name);
languages.insertAdjacentElement('beforeEnd', link);
}) })
}); });
navbar.append(Element.li() navbar.append(Element.li()
..append(Element.a() ..append(Element.a()
..attributes['href'] = '#' ..attributes['href'] = 'javascript:void(0)'
..innerText = 'Langues') ..append(makeIcon(['fas', 'fa-language'])))
..classes.add('nav-item') // ..innerText = 'Langues')
..classes.add('has-dropdown') ..classes.addAll(['nav-item', 'has-dropdown'])
..insertAdjacentElement('beforeEnd', languages)); ..insertAdjacentElement('beforeEnd', languages));
return navbar; 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: // Add a navbar atop of the HTML body, containing two buttons:
// - One back to home // - One back to home
// - A dropdown to each language detected in the sitemap // - A dropdown to each language detected in the sitemap
Future<Element> makeNavbar() async { Future<Element> makeNavbar() async {
// var _navbar = Navbar(); var navbar_content = Element.ul()..classes.add('navbar-nav');
// Home // Home
var navbar_content = Element.ul()..classes.add('navbar-nav');
navbar_content.append(Element.li() navbar_content.append(Element.li()
..classes.add('nav-item') ..classes.add('nav-item')
..insertAdjacentElement( ..insertAdjacentElement(
'afterBegin', 'afterBegin',
Element.a() Element.a()
..attributes['href'] = '/' ..attributes['href'] = '/'
..innerText = 'Accueil')); ..append(makeIcon(['fas', 'fa-home']))));
// TOC icon
navbar_content.append(makeTocDropDown());
// Add languages // Add languages
// navbar_content.append(Element.html('''
// '''));
navbar_content = await addLanguages(navbar_content); navbar_content = await addLanguages(navbar_content);
// Page title
navbar_content.append(Element.li()
..classes.add('nav-item')
..innerText = getPageTitle());
// Share icon // 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'); navbar_content = addIcon(navbar_content, ['fas', 'fa-share-alt'], 'shareBtn');
// Theme changer // Theme changer
// Add dropdown for theming var theme = window.localStorage['theme'];
// navbar_content = addIcon(navbar_content, ['fas', 'fa-sun'], 'themeBtn'); theme = (theme == null || theme == 'light') ? 'fa-moon' : 'fa-sun';
navbar_content.append(Element.html(''' navbar_content.append(makeThemeChanger());
<li class="nav-item has-dropdown">
<a href="#"><i class="fas fa-sun" id="themeBtn"></i></a>
<ul class="dropdown" id="theme-dropdown">
<li class="dropdown-item"><span id="lightBtn"><i class="fas fa-sun"></i> Clair</span></li>
<li class="dropdown-item"><span id="darkBtn"> <i class="fas fa-moon"></i> Sombre</span></li>
</ul>
</li>'''));
// Navbar content added to navbar // Navbar content added to navbar
final navbar = Element.nav() final navbar = Element.nav()
@ -85,14 +114,31 @@ Future<Element> makeNavbar() async {
} }
Element addIcon(Element navbar, List<String> classes, String id) { Element addIcon(Element navbar, List<String> classes, String id) {
var elem = Element.tag('i')..attributes['id'] = id; final icon = makeIcon(classes, id);
for (var c in classes) { navbar.append(Element.li()..append(icon));
elem.classes.add(c);
}
navbar.append(Element.li()..append(elem));
return navbar; 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<void> wrapTables() async { Future<void> wrapTables() async {
for (var table in querySelectorAll('table')) { for (var table in querySelectorAll('table')) {
var largetable = DivElement()..className = 'largetable'; var largetable = DivElement()..className = 'largetable';
@ -101,24 +147,19 @@ Future<void> wrapTables() async {
} }
} }
Future<void> makeHeader() async {
querySelector('body')
.insertAdjacentElement('afterBegin', Element.tag('header'));
querySelector('header').append(querySelector('h1'));
querySelector('header').append(querySelector('.subtitle'));
}
Future<void> reorganizeHtml() async { Future<void> reorganizeHtml() async {
await makeHeader(); // Create navbar and then header
await wrapTables();
await makeNavbar().then((navbar) { await makeNavbar().then((navbar) {
// querySelector('#toc-drop')
// .append(querySelector('#table-of-contents')..classes.add('dropdown'));
querySelector('body').insertAdjacentElement('afterBegin', navbar); 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') // wrap tables in container for better SCSS display
..classes.add('light') await wrapTables();
// Add a <hr> element after the content div
..appendHtml('<hr>')
// Move the postamble in the content div
..append(querySelector('#postamble'));
} }

View File

@ -1,20 +1,53 @@
import 'dart:html'; import 'dart:html';
void switchTheme(final Element body, String theme) { class Theme {
body.classes.clear(); String _name;
body.classes.add(theme); 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() { void makeThemeChanger() {
final darkBtn = querySelector('#darkBtn'); final darkBtn = querySelector('#darkBtn');
final lightBtn = querySelector('#lightBtn'); final lightBtn = querySelector('#lightBtn');
final body = querySelector('body'); final blackBtn = querySelector('#blackBtn');
darkBtn.onClick.listen((_) { lightBtn.onClick.listen((_) => switchTheme(themes['light']));
switchTheme(body, 'dark'); darkBtn.onClick.listen((_) => switchTheme(themes['dark']));
}); blackBtn.onClick.listen((_) => switchTheme(themes['black']));
}
lightBtn.onClick.listen((_) {
switchTheme(body, 'light'); Future<void> 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();
} }

View File

@ -2,7 +2,7 @@
@font-face { @font-face {
font-family: "DoulosSIL"; font-family: "DoulosSIL";
font-display: swap; font-display: swap;
src: url("https://langue.phundrak.com/fonts/DoulosSIL-R.woff"); src: url("/fonts/DoulosSIL-R.woff");
} }
@font-face { @font-face {
font-family: "Noto Sans Runes"; font-family: "Noto Sans Runes";
@ -18,69 +18,157 @@
// Themes ///////////////////////////////////////////////////////////////////// // Themes /////////////////////////////////////////////////////////////////////
$dark: rgba( 52, 73, 94, 1); $dark: rgba( 52, 73, 94, 1);
$accent1: rgba(66, 191, 221, 1); $black: rgba( 0, 0, 0, 1);
$accent1: rgba( 93, 115, 126, 1);
$accent2: rgba( 92, 172, 126, 1); $accent2: rgba( 92, 172, 126, 1);
$accent3: rgba(197, 193, 155, 1); $accent3: rgba(197, 193, 155, 1);
$light: #ddd; $light: rgba(252, 239, 249, 1);
$grey1: #f8f8f8; $grey1: #f8f8f8;
$grey2: #dbe1e8; $grey2: #dbe1e8;
$grey3: #b2becd; $grey3: #b2becd;
$grey4: #6c7983; $grey4: #6c7983;
$grey5: #454e56; $grey5: #454e56;
$grey6: #12181b; $grey6: #12181b;
$gradient-top: linear-gradient(0deg, $dark, $accent1, $accent2, $accent3, $light);
$gradient-right: linear-gradient(90deg, $dark, $accent1, $accent2, $accent3, $light); // Accent 1
$gradient-bottom: linear-gradient(180deg, $dark, $accent1, $accent2, $accent3, $light); // Black
$gradient-left: linear-gradient(270deg, $dark, $accent1, $accent2, $accent3, $light); $gradient-accent1-black-left: linear-gradient(to left, $black, $accent1, $accent1);
$gradient-top-right: linear-gradient(45deg, $dark, $accent1, $accent2, $accent3, $light); $gradient-accent1-black-right: linear-gradient(to right, $black, $accent1, $accent1);
$gradient-bottom-right: linear-gradient(135deg, $dark, $accent1, $accent2, $accent3, $light); // Dark
$gradient-top-left: linear-gradient(225deg, $dark, $accent1, $accent2, $accent3, $light); $gradient-accent1-dark-left: linear-gradient(to left, $dark, $accent1);
$gradient-bottom-left: linear-gradient(315deg, $dark, $accent1, $accent2, $accent3, $light); $gradient-accent1-dark-right: linear-gradient(to right, $dark, $accent1);
$gradient-radial: radial-gradient( $dark, $accent1, $accent2, $accent3, $light); // 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 { .light {
$bg-nav: linear-gradient(to right, $grey1, $grey3); $bg-nav: $gradient-accent3-light-right;
$bg-dropdown: $grey1;
$text: $light;
$border-color: $accent1; $border-color: $accent1;
$bg-solar: $accent3;
transition: background 500ms ease-in-out, color 1s ease-in-out;
color: $dark; color: $dark;
background: $light; background: $light;
.navbar {
background: $grey3;
}
}
.dark {
$background: $dark;
$foreground: $light;
$bg-nav: linear-gradient(to right, $grey5, $grey6);
$bg-dropdown: $grey6;
$text: $dark;
$border-color: $dark;
$bg-solar: $accent3;
transition: background 500ms ease-in-out, color 1s ease-in-out; 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, .black {
$bg-nav: $gradient-accent2-dark-right;
$border-color: $dark;
color: $light; color: $light;
background: $dark; 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; color: $light;
background: $grey6;
} }
} }
/* Style *********************************************************************/ /* Style *********************************************************************/
* {
outline: none;
}
body { body {
margin: 0; margin: 0;
padding: 0; padding: 0;
font-family: "Noto Sans Runes", "DoulosSIL", "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif; 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; transition: background 500ms ease-in-out, color 1s ease-in-out;
header, .navbar { header, .navbar {
@ -100,7 +188,10 @@ a {
} }
.navbar { .navbar {
height: 70px; position: fixed;
top: 0;
z-index: 4;
height: $navbar-height;
width: 100%; width: 100%;
} }
@ -109,27 +200,22 @@ a {
align-items: center; align-items: center;
justify-content: space-evenly; justify-content: space-evenly;
height: 100%; height: 100%;
background: $accent3;
color: $dark;
} }
header { header {
padding: 1em; padding: 1em;
margin-top: $navbar-height;
margin-bottom: 1em; margin-bottom: 1em;
padding-bottom: 3.5em; padding-bottom: 3.5em;
text-align: center; text-align: center;
clip-path: polygon(50% 0%, 100% 0, 100% 65%, 50% 100%, 0 65%, 0 0); clip-path: polygon(50% 0%, 100% 0, 100% 80%, 50% 100%, 0 80%, 0 0);
color: $light; transition: background 500ms ease-in-out;
background: $accent2;
} }
.dropdown { .dropdown {
position: absolute; position: absolute;
width: 500px;
opacity: 0; opacity: 0;
z-index: 2; z-index: 5;
background: blue;
border-top: 2px solid white;
border-bottom-right-radius: 8px; border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px; border-bottom-left-radius: 8px;
@ -137,8 +223,8 @@ header {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-around; justify-content: space-around;
height: 3rem; min-height: 3rem;
margin-top: 2rem; margin-top: 1rem;
padding: 0.5rem; padding: 0.5rem;
box-shadow: rgba(2, 8, 20, 0.1) 0px 0.175em 0.5em; box-shadow: rgba(2, 8, 20, 0.1) 0px 0.175em 0.5em;
@ -148,8 +234,14 @@ header {
} }
#theme-dropdown { #theme-dropdown {
width: 300px; width: 250px;
transform: translateX(-95%); flex-direction: row;
transform: translateX(-50%);
}
#drop-lang {
flex-direction: column;
transform: translateX(-40%);
} }
.has-dropdown { .has-dropdown {
@ -158,15 +250,127 @@ header {
opacity: 1; opacity: 1;
pointer-events: auto; pointer-events: auto;
} }
#table-of-contents {
opacity: 1;
height: 500%;
pointer-events: auto;
}
} }
} }
.dropdown-item { .dropdown-item {
cursor: pointer;
a { a {
width: 100%; width: 100%;
height: 100%; height: 100%;
size: 0.7rem; size: 0.7rem;
padding-left: 10px; padding-left: 10px;
padding-right: 10px;
font-weight: bold; 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;
}
}
}