Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
8ca55cb710
|
|||
|
aa4600b588
|
|||
|
2f297b6374
|
|||
|
9f6a32f5d2
|
|||
|
34ac1480d3
|
|||
|
fc1556128c
|
|||
|
3c942b4b8f
|
|||
|
90106df0f6
|
|||
|
a82fa74a6b
|
|||
|
e81986683c
|
|||
|
cc6519c302
|
|||
|
705e35e971
|
|||
|
61fe6f71a4
|
|||
|
404e79211e
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,3 +4,4 @@
|
|||||||
/.packages
|
/.packages
|
||||||
/pubspec.lock
|
/pubspec.lock
|
||||||
/.sass-cache/
|
/.sass-cache/
|
||||||
|
/build/
|
||||||
|
|||||||
14
Dockerfile
14
Dockerfile
@@ -1,7 +1,11 @@
|
|||||||
FROM google/dart:2.7
|
FROM google/dart:2.8
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Get Ruby Sass
|
||||||
|
RUN apt update && apt install ruby-sass ruby-dev build-essential -y
|
||||||
|
RUN gem install sass-listen
|
||||||
|
|
||||||
# Get Dart dependencies
|
# Get Dart dependencies
|
||||||
RUN mkdir -p /pub-cache
|
RUN mkdir -p /pub-cache
|
||||||
ENV PUB_CACHE=/pub-cache
|
ENV PUB_CACHE=/pub-cache
|
||||||
@@ -11,10 +15,8 @@ ADD pubspec.* /app/
|
|||||||
RUN pub get
|
RUN pub get
|
||||||
RUN pub get --offline
|
RUN pub get --offline
|
||||||
|
|
||||||
# Get Ruby Sass
|
# ADD . /app/
|
||||||
RUN apt update && apt install ruby-sass ruby-dev build-essential -y
|
ADD web /app/
|
||||||
RUN gem install sass-listen
|
ADD start.sh /app/
|
||||||
|
|
||||||
ADD . /app/
|
|
||||||
|
|
||||||
CMD ["./start.sh"]
|
CMD ["./start.sh"]
|
||||||
|
|||||||
38
README.org
38
README.org
@@ -100,11 +100,39 @@
|
|||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
** Running in development mode
|
** Running in development mode
|
||||||
To run this backend in development mode, you will have to remove the
|
# To run this backend in development mode, you will have to remove the
|
||||||
~--release~ option from the ~webdev~ command in the ~start.sh~ file. This
|
# ~--release~ option from the ~webdev~ command in the ~start.sh~ file. This
|
||||||
will allow webdev to compile Dart files faster, but at the price of slower
|
# will allow webdev to compile Dart files faster, but at the price of slower
|
||||||
compiled Javascript files. If you use Docker, don’t forget to rebuild your
|
# compiled Javascript files. If you use Docker, don’t forget to rebuild your
|
||||||
image.
|
# image.
|
||||||
|
To run this backend in development mode, you can add to your environment the
|
||||||
|
variable ~RELEASE~ with the value ~debug~. Running the backend locally, you
|
||||||
|
would start it like so:
|
||||||
|
#+BEGIN_SRC sh
|
||||||
|
RELEASE=debug ./start.sh
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Running it with Docker, you would use the following command:
|
||||||
|
#+BEGIN_SRC sh
|
||||||
|
docker run \
|
||||||
|
-p 8080:8080 \
|
||||||
|
-v ./web:/app/web \
|
||||||
|
-e RELEASE=debug \
|
||||||
|
--restart always \
|
||||||
|
--detach \
|
||||||
|
--name owb \
|
||||||
|
owb:1.0
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
And with docker-compose, you would add the following line to your ~owb~
|
||||||
|
service:
|
||||||
|
#+BEGIN_SRC yaml
|
||||||
|
environment:
|
||||||
|
- RELEASE=debug
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Any other value to this environment variable will make your backend run in
|
||||||
|
release mode (actually, it will only make ~webdev~ run in release mode).
|
||||||
|
|
||||||
** How can I use this in my org files?
|
** How can I use this in my org files?
|
||||||
Let’s say you serve your files on org.example.com, add the following lines to
|
Let’s say you serve your files on org.example.com, add the following lines to
|
||||||
|
|||||||
@@ -6,5 +6,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 8010:8080
|
- 8010:8080
|
||||||
restart: always
|
restart: always
|
||||||
|
environment:
|
||||||
|
- RELEASE=debug
|
||||||
volumes:
|
volumes:
|
||||||
- ./web:/app/web
|
- ./web:/app/web
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
name: languephundrakcom
|
name: orgwebsitebackend
|
||||||
description: A bare-bone server for my linguistics website.
|
description: A bare-bone server for org-generated websites.
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
homepage: https://langue.phundrak.com
|
homepage: https://labs.phundrak.com/phundrak/org-website-backend
|
||||||
author: Lucien Cartier-Tilet <lucien@phundrak.com>
|
author: Lucien Cartier-Tilet <lucien@phundrak.com>
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.5.0 <3.0.0'
|
sdk: '>=2.7.0 <3.0.0'
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
html: '^0.14.0+3'
|
html: '^0.14.0+3'
|
||||||
|
|||||||
7
start.sh
7
start.sh
@@ -1,3 +1,8 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
sass --watch web/style/:web/style -tcompressed &
|
sass --watch web/style/:web/style -tcompressed &
|
||||||
webdev serve --release --hostname 0.0.0.0
|
|
||||||
|
[ "$RELEASE" == "debug" ] \
|
||||||
|
&& webdev serve --hostname 0.0.0.0 \
|
||||||
|
|| webdev serve --release --hostname 0.0.0.0
|
||||||
|
|
||||||
|
# webdev serve --release --hostname 0.0.0.0
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import './reorganize_html.dart' show reorganizeHtml;
|
import './reorganize_html.dart' show reorganizeHtml;
|
||||||
import './theme.dart' show enableThemeChanger, setTheme;
|
import './theme.dart' show enableThemeChanger, setTheme;
|
||||||
|
import './parse_sitemap.dart' show getSitemap;
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
await setTheme();
|
await setTheme();
|
||||||
await reorganizeHtml().then((_) {
|
await reorganizeHtml().then((_) => enableThemeChanger());
|
||||||
enableThemeChanger();
|
await getSitemap();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,7 @@ String getPageTitle() {
|
|||||||
|
|
||||||
Element makeIcon(List<String> classes, [String id]) {
|
Element makeIcon(List<String> classes, [String id]) {
|
||||||
final icon = Element.tag('i')..classes.addAll(classes);
|
final icon = Element.tag('i')..classes.addAll(classes);
|
||||||
if (id != null) {
|
icon.attributes['id'] = id ?? '';
|
||||||
icon.attributes['id'] = id;
|
|
||||||
}
|
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,24 +26,12 @@ Future<Element> makePages() async {
|
|||||||
var pages = Element.ul()
|
var pages = Element.ul()
|
||||||
..attributes['id'] = 'drop-page'
|
..attributes['id'] = 'drop-page'
|
||||||
..classes.add('dropdown');
|
..classes.add('dropdown');
|
||||||
await parseSitemap().then((final sitemap) => {
|
|
||||||
sitemap.forEach((url, name) {
|
|
||||||
final link = Element.li()
|
|
||||||
..classes.add('dropdown-item')
|
|
||||||
..insertAdjacentElement(
|
|
||||||
'afterBegin',
|
|
||||||
Element.a()
|
|
||||||
..attributes['href'] = url
|
|
||||||
..innerText = name);
|
|
||||||
pages.insertAdjacentElement('beforeEnd', link);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
return Element.li()
|
return Element.li()
|
||||||
..append(Element.a()
|
..append(Element.a()
|
||||||
..attributes['href'] = 'javascript:void(0)'
|
..attributes['href'] = 'javascript:void(0)'
|
||||||
..append(makeIcon(['fas', 'fa-flag'])))
|
..append(makeIcon(['fas', 'fa-flag'])))
|
||||||
..classes.addAll(['nav-item', 'has-dropdown'])
|
..classes.addAll(['nav-item', 'has-dropdown'])
|
||||||
..insertAdjacentElement('beforeEnd', pages);
|
..append(pages);
|
||||||
}
|
}
|
||||||
|
|
||||||
Element makeShareLink(Element icon, String url) {
|
Element makeShareLink(Element icon, String url) {
|
||||||
@@ -54,6 +40,7 @@ Element makeShareLink(Element icon, String url) {
|
|||||||
..append(Element.a()
|
..append(Element.a()
|
||||||
..attributes['href'] = url
|
..attributes['href'] = url
|
||||||
..attributes['target'] = '_blank'
|
..attributes['target'] = '_blank'
|
||||||
|
..attributes['rel'] = 'noreferrer'
|
||||||
..append(icon));
|
..append(icon));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import 'dart:html' show HttpRequest;
|
import 'dart:html' as html show HttpRequest, Element, querySelector;
|
||||||
|
|
||||||
import 'package:html/parser.dart' show parse;
|
import 'package:html/parser.dart' show parse;
|
||||||
import 'package:html/dom.dart' show Element;
|
import 'package:html/dom.dart' as dom show Element;
|
||||||
|
|
||||||
final excluded_keywords = ['index', 'CONTRIBUTING', 'LICENSE', 'README'];
|
final excluded_keywords = {'index', 'CONTRIBUTING', 'LICENSE', 'README'};
|
||||||
|
|
||||||
// Get the sitemap content
|
// Get the sitemap content
|
||||||
Future<String> getSitemap() async {
|
Future<String> fetchRemoteSitemap() async {
|
||||||
const path = 'sitemap.html';
|
const path = 'sitemap.html';
|
||||||
try {
|
try {
|
||||||
return await HttpRequest.getString(path);
|
return await html.HttpRequest.getString(path);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Couldn’t open $path');
|
print('Couldn’t open $path');
|
||||||
}
|
}
|
||||||
@@ -17,10 +17,10 @@ Future<String> getSitemap() async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse the list of elements and detect pages from this list
|
// Parse the list of elements and detect pages from this list
|
||||||
Map<String, String> detectPages(List<Element> sitemap, [String prefix]) {
|
Map<String, String> detectPages(List<dom.Element> sitemap, [String prefix]) {
|
||||||
final links = <String, String>{};
|
final links = <String, String>{};
|
||||||
for (var elem in sitemap) {
|
for (var elem in sitemap) {
|
||||||
for(var kw in excluded_keywords) {
|
for (var kw in excluded_keywords) {
|
||||||
if (elem.outerHtml.contains(kw)) {
|
if (elem.outerHtml.contains(kw)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,9 @@ Map<String, String> detectPages(List<Element> sitemap, [String prefix]) {
|
|||||||
final text = elem.firstChild.text;
|
final text = elem.firstChild.text;
|
||||||
links[url] = (prefix == null) ? text : '$text ($prefix)';
|
links[url] = (prefix == null) ? text : '$text ($prefix)';
|
||||||
} else {
|
} else {
|
||||||
final prefix = elem.firstChild.text;
|
prefix = (prefix == null)
|
||||||
|
? elem.firstChild.text
|
||||||
|
: '$prefix / ${elem.firstChild.text}';
|
||||||
final ul = elem.children[0].children;
|
final ul = elem.children[0].children;
|
||||||
links.addAll(detectPages(ul, prefix));
|
links.addAll(detectPages(ul, prefix));
|
||||||
}
|
}
|
||||||
@@ -42,7 +44,31 @@ Map<String, String> detectPages(List<Element> sitemap, [String prefix]) {
|
|||||||
// This function returns a Map which contains all links to languages detected
|
// This function returns a Map which contains all links to languages detected
|
||||||
// from the sitemap.
|
// from the sitemap.
|
||||||
Future<Map<String, String>> parseSitemap() async {
|
Future<Map<String, String>> parseSitemap() async {
|
||||||
final content = await getSitemap();
|
final content = await fetchRemoteSitemap();
|
||||||
final sitemap = parse(content).getElementsByClassName('org-ul')[0].children;
|
final sitemap = parse(content).getElementsByClassName('org-ul')[0].children;
|
||||||
return detectPages(sitemap);
|
return detectPages(sitemap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future sleep(Duration time) async {
|
||||||
|
return Future.delayed(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<html.Element> getSitemap() async {
|
||||||
|
final sitemap = await parseSitemap();
|
||||||
|
final pages = <html.Element>[];
|
||||||
|
sitemap.forEach((url, name) {
|
||||||
|
final link = html.Element.li()
|
||||||
|
..classes.add('dropdown-item')
|
||||||
|
..append(html.Element.a()
|
||||||
|
..attributes['href'] = url
|
||||||
|
..innerText = name);
|
||||||
|
pages.add(link);
|
||||||
|
});
|
||||||
|
var drop_container;
|
||||||
|
do {
|
||||||
|
await sleep(Duration(seconds: 1));
|
||||||
|
drop_container = html.querySelector('#drop-page');
|
||||||
|
} while (drop_container != null);
|
||||||
|
pages.forEach((link) => drop_container.append(link));
|
||||||
|
return drop_container;
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,13 +2,15 @@ import 'dart:html';
|
|||||||
|
|
||||||
import './navbar.dart' show makeNavbar;
|
import './navbar.dart' show makeNavbar;
|
||||||
|
|
||||||
|
const image_header =
|
||||||
|
'https://phundrak.fra1.cdn.digitaloceanspaces.com/img/mahakala-monochrome.png';
|
||||||
|
|
||||||
Future<Element> makeHeader() async {
|
Future<Element> makeHeader() async {
|
||||||
var header = Element.tag('header');
|
var header = Element.tag('header');
|
||||||
header
|
header
|
||||||
..append(Element.img()
|
..append(Element.img()
|
||||||
..attributes['src'] =
|
..attributes['src'] = image_header
|
||||||
'https://cdn.phundrak.com/img/mahakala-monochrome.png'
|
..attributes['alt'] = 'Logo'
|
||||||
..attributes['alt'] = 'Logo de Phundrak'
|
|
||||||
..attributes['heigh'] = '150px'
|
..attributes['heigh'] = '150px'
|
||||||
..attributes['width'] = '150px')
|
..attributes['width'] = '150px')
|
||||||
..append(querySelector('h1'));
|
..append(querySelector('h1'));
|
||||||
@@ -28,10 +30,8 @@ Future<void> wrapTables() async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// All images that are not nested inside a link will be linkified to themselves.
|
// All images that are not nested inside a link will be linkified to themselves.
|
||||||
void linkifyImg() {
|
Future<void> linkifyImg() async {
|
||||||
querySelectorAll('img').forEach((img) {
|
querySelectorAll('img').forEach((img) {
|
||||||
print(img.attributes['src']);
|
|
||||||
print(img.parent.tagName);
|
|
||||||
if (img.parent.tagName == 'P') {
|
if (img.parent.tagName == 'P') {
|
||||||
final link = Element.a()..attributes['href'] = img.attributes['src'];
|
final link = Element.a()..attributes['href'] = img.attributes['src'];
|
||||||
img.insertAdjacentElement('beforeBegin', link);
|
img.insertAdjacentElement('beforeBegin', link);
|
||||||
@@ -41,30 +41,31 @@ void linkifyImg() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> reorganizeHtml() async {
|
Future<void> reorganizeHtml() async {
|
||||||
final content = querySelector('#content');
|
|
||||||
|
|
||||||
// Make navbar
|
// Make navbar
|
||||||
await makeNavbar().then((navbar) {
|
final navbar = await makeNavbar();
|
||||||
querySelector('body').insertAdjacentElement('afterBegin', navbar);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Make header
|
// Make header
|
||||||
await makeHeader().then((header) {
|
final header = await makeHeader();
|
||||||
content.insertAdjacentElement('beforeBegin', header);
|
|
||||||
final subtitle = querySelector('.subtitle');
|
|
||||||
if (subtitle != null) {
|
|
||||||
header.append(subtitle);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// wrap tables in container for better SCSS display
|
// wrap tables in container for better SCSS display
|
||||||
await wrapTables();
|
await wrapTables();
|
||||||
|
|
||||||
linkifyImg();
|
// Make images not linking somewhere link to themselves
|
||||||
|
await linkifyImg();
|
||||||
|
|
||||||
|
// Add navbar to page
|
||||||
|
querySelector('body').insertAdjacentElement('afterBegin', navbar);
|
||||||
|
|
||||||
|
// Add headet to page
|
||||||
|
querySelector('#content').insertAdjacentElement('beforeBegin', header);
|
||||||
|
|
||||||
// Add correct class to TOC
|
// Add correct class to TOC
|
||||||
querySelector('#toc-drop')
|
final toc = (querySelector('#table-of-contents') ??
|
||||||
.append(querySelector('#table-of-contents')..classes.add('dropdown'));
|
(Element.div()
|
||||||
|
..attributes['id'] = 'table-of-contents'
|
||||||
|
..innerText = 'Table of Contents Unavailable'))
|
||||||
|
..classes.add('dropdown');
|
||||||
|
navbar.querySelector('#toc-drop').append(toc);
|
||||||
|
|
||||||
// Remove all <br> tags from HTML
|
// Remove all <br> tags from HTML
|
||||||
querySelectorAll('br').forEach((br) => br.remove());
|
querySelectorAll('br').forEach((br) => br.remove());
|
||||||
|
|||||||
@@ -1,20 +1,3 @@
|
|||||||
@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic|Roboto+Slab:400,700|Inconsolata:400,700);
|
|
||||||
@font-face {
|
|
||||||
font-family: "DoulosSIL";
|
|
||||||
font-display: swap;
|
|
||||||
src: url("/fonts/DoulosSIL-R.woff");
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: "Noto Sans Runes";
|
|
||||||
font-display: swap;
|
|
||||||
src: url("../fonts/NotoSansRunic-Regular.ttf");
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: "Helvetica Neue";
|
|
||||||
font-display: swap;
|
|
||||||
src: url("../fonts/HelveticaNeue.ttf");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Variables *****************************************************************/
|
/* Variables *****************************************************************/
|
||||||
|
|
||||||
$switch-small-screen: "only screen and (max-width: 600px)";
|
$switch-small-screen: "only screen and (max-width: 600px)";
|
||||||
@@ -79,7 +62,7 @@ $gradient-accent3-light-right: linear-gradient(to right, $light, $accent3);
|
|||||||
transition: background 500ms ease-in-out, color 1s ease-in-out;
|
transition: background 500ms ease-in-out, color 1s ease-in-out;
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
box-shadow: 3px 3px $dark;
|
box-shadow: 3px 5px $dark;
|
||||||
border-color: $light;
|
border-color: $light;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,7 +260,7 @@ $gradient-accent3-light-right: linear-gradient(to right, $light, $accent3);
|
|||||||
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: "Lato", "proxima-nova", Arial, sans-serif;
|
||||||
font-size: 1.2em;
|
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;
|
||||||
@@ -353,7 +336,7 @@ header {
|
|||||||
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;
|
||||||
transform: translateX(-40%);
|
transform: translateX(-40%);
|
||||||
|
|
||||||
transition: opacity 500ms ease-in-out, top 500ms ease-in-out;
|
transition: opacity 500ms ease-in-out, top 500ms ease-in-out, height 500ms ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.has-dropdown {
|
.has-dropdown {
|
||||||
@@ -365,7 +348,7 @@ header {
|
|||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#table-of-contents {
|
#table-of-contents, #drop-page {
|
||||||
top: $navbar-height / 1.3;
|
top: $navbar-height / 1.3;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
@@ -381,15 +364,26 @@ header {
|
|||||||
transform: translateX(-75%);
|
transform: translateX(-75%);
|
||||||
}
|
}
|
||||||
|
|
||||||
#drop-page {
|
#drop-page, #table-of-contents {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
transform: translateX(-40%);
|
|
||||||
li {
|
transform: translateX(-45%);
|
||||||
padding: 5px;
|
top: -40px;
|
||||||
|
|
||||||
|
height: 0;
|
||||||
|
min-width: 350px;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media #{$switch-small-screen} {
|
||||||
|
#drop-page {
|
||||||
|
transform: translateX(-27.5%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#drop-share {
|
#drop-share, #drop-page {
|
||||||
li {
|
li {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
@@ -401,7 +395,6 @@ header {
|
|||||||
a {
|
a {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
size: 0.7rem;
|
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@@ -409,17 +402,9 @@ header {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#table-of-contents {
|
#table-of-contents {
|
||||||
flex-direction: column;
|
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
float: right;
|
float: right;
|
||||||
overflow-y: auto;
|
|
||||||
height: 0%;
|
|
||||||
width: 75%;
|
width: 75%;
|
||||||
min-width: 350px;
|
|
||||||
transform: translateX(-45%);
|
|
||||||
font-size: 0.9em;
|
|
||||||
top: -40px;
|
|
||||||
|
|
||||||
transition: height 500ms ease-in-out, opacity 500ms ease-in-out, top 500ms ease-in-out;
|
transition: height 500ms ease-in-out, opacity 500ms ease-in-out, top 500ms ease-in-out;
|
||||||
|
|
||||||
li {
|
li {
|
||||||
@@ -442,6 +427,10 @@ header {
|
|||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
text-align: justify;
|
text-align: justify;
|
||||||
|
|
||||||
|
@media #{$switch-small-screen} {
|
||||||
|
padding: 50px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user