rework branches a bit to support saving
This commit is contained in:
parent
6c110b61a2
commit
582447e02b
|
@ -1 +1 @@
|
||||||
- section under construction. sorry! in the meantime, maybe you wanna read [my ramblings about the treehouse](#01H89RFHCQCD3E1XS5XAPW86J5)?
|
- section under construction. sorry! in the meantime, maybe you wanna read [my ramblings about the treehouse][b:01H89RFHCQCD3E1XS5XAPW86J5]?
|
||||||
|
|
|
@ -136,8 +136,10 @@
|
||||||
% id = "01H89RFHCQ2GWJPTAKTRGS1QAC"
|
% id = "01H89RFHCQ2GWJPTAKTRGS1QAC"
|
||||||
- weird poems and philosophical talk are over, it's time to focus on the tech.
|
- weird poems and philosophical talk are over, it's time to focus on the tech.
|
||||||
|
|
||||||
|
- call this an overview, Defense of Design, or what have you
|
||||||
|
|
||||||
% id = "01H89RFHCQF4N9T05B9DVWX67K"
|
% id = "01H89RFHCQF4N9T05B9DVWX67K"
|
||||||
- treehouse is built in the programming language that gives me the most pleasure while developing.
|
- treehouse is built in the programming language that gives me the most pleasure coding.
|
||||||
|
|
||||||
- no need for you to know more. :shhh:
|
- no need for you to know more. :shhh:
|
||||||
|
|
||||||
|
@ -149,10 +151,10 @@
|
||||||
- but being the altruist I am - don't worry, it _will_ be open source one day.
|
- but being the altruist I am - don't worry, it _will_ be open source one day.
|
||||||
|
|
||||||
- in case you're reading this in the far future, and this is still here…
|
- in case you're reading this in the far future, and this is still here…
|
||||||
you wouldn't mind [dropping me a line](#01H89P3CH8CD28KGX9GVRFK60E) would you?
|
you wouldn't mind [dropping me a line][b:01H89P3CH8CD28KGX9GVRFK60E] would you?
|
||||||
|
|
||||||
% id = "01H89RFHCQAQVXP6B2H0T8NNDS"
|
% id = "01H89RFHCQAQVXP6B2H0T8NNDS"
|
||||||
- personally… the language you build a personal project in almost never matters. it's rather how you execute your ideas.
|
- personally… the language you build a personal project with almost never matters. it's rather how you execute your ideas.
|
||||||
|
|
||||||
+ therefore I find boasting that my project is powered by a `$LANGUAGE` or a `$FRAMEWORK` unnecessary.
|
+ therefore I find boasting that my project is powered by a `$LANGUAGE` or a `$FRAMEWORK` unnecessary.
|
||||||
|
|
||||||
|
@ -162,7 +164,7 @@
|
||||||
- (yes, I know that website is super old, but I still find it incredibly funny :hueh:)
|
- (yes, I know that website is super old, but I still find it incredibly funny :hueh:)
|
||||||
|
|
||||||
% id = "01H89RFHCQFWC2FWBAE9PVNC08"
|
% id = "01H89RFHCQFWC2FWBAE9PVNC08"
|
||||||
- as I alluded to [here](#01H89RFHCQ3EAP0F6PRSEK7S1T), treehouse is built to decay gracefully
|
- as I alluded to [here][b:01H89RFHCQ3EAP0F6PRSEK7S1T], treehouse is built to decay gracefully
|
||||||
as you take away the fancy parts.
|
as you take away the fancy parts.
|
||||||
|
|
||||||
- you will be able to read it just fine without JavaScript, just that it'll be a little
|
- you will be able to read it just fine without JavaScript, just that it'll be a little
|
||||||
|
@ -185,6 +187,14 @@
|
||||||
|
|
||||||
- if you have accessibility concerns about this decision, please let me know.
|
- if you have accessibility concerns about this decision, please let me know.
|
||||||
|
|
||||||
|
- it also saves your progress as you read. if you refresh the page, you'll notice you end up exactly where you left off!
|
||||||
|
|
||||||
|
- but, there is one very crucial piece of JavaScript that makes this website tick, and your experience **will be degraded** if you disable it. that feature is linking to branches.
|
||||||
|
|
||||||
|
- by default, if you link to an element by its id and it's contained within a `<details>`, the `<details>` will not expand. :ralsei_dead:
|
||||||
|
|
||||||
|
- therefore there's a bit of JS to make that work, _and_ to tie that together with lazy loading.
|
||||||
|
|
||||||
- treehouse will not work *as* fine without CSS though - the `<details>` will look extremely
|
- treehouse will not work *as* fine without CSS though - the `<details>` will look extremely
|
||||||
janky, but the content should still be fully readable.
|
janky, but the content should still be fully readable.
|
||||||
|
|
||||||
|
@ -193,20 +203,21 @@
|
||||||
- the structure of `.tree` files is extremely minimal. there are only a few syntactic features to speak of.
|
- the structure of `.tree` files is extremely minimal. there are only a few syntactic features to speak of.
|
||||||
|
|
||||||
- here's a taste of `.tree`:
|
- here's a taste of `.tree`:
|
||||||
```
|
|
||||||
\% id = "root"
|
|
||||||
\- this is a branch
|
|
||||||
|
|
||||||
\% id = "child"
|
- ```
|
||||||
\- this is a child branch
|
\% id = "root"
|
||||||
|
\- this is a branch
|
||||||
|
|
||||||
\+ this is a branch that is collapsed
|
\% id = "child"
|
||||||
|
\- this is a child branch
|
||||||
|
|
||||||
\- and this is a child of that branch
|
\+ this is a branch that is collapsed
|
||||||
|
|
||||||
\% content.link = "some-other-tree"
|
\- and this is a child of that branch
|
||||||
\- and this branch links to another tree
|
|
||||||
```
|
\% content.link = "some-other-tree"
|
||||||
|
\- and this branch links to another tree
|
||||||
|
```
|
||||||
|
|
||||||
- the `.tree` format is line-based. that means the `%`, `-`, and `+` tokens are only
|
- the `.tree` format is line-based. that means the `%`, `-`, and `+` tokens are only
|
||||||
interpreted when at the beginning of a line.
|
interpreted when at the beginning of a line.
|
||||||
|
@ -219,15 +230,15 @@
|
||||||
|
|
||||||
- …may or may not be expanded by default (this is the branch's _kind_) - that's what the minus `-` and plus `+` tokens do
|
- …may or may not be expanded by default (this is the branch's _kind_) - that's what the minus `-` and plus `+` tokens do
|
||||||
|
|
||||||
- …are sequenced like: optional attributes, kind, content
|
- each branch is constructed in this order: optional attributes, kind, content
|
||||||
|
|
||||||
- …end when another line beginning with `%`, `-`, or `+` is found.
|
- and ends when another line beginning with `%`, `-`, or `+` is found.
|
||||||
|
|
||||||
- other than that, `.tree` assumes nothing about what format the branch attributes or content are encoded in.
|
- other than that, `.tree` assumes nothing about what format the branch attributes or content are encoded in.
|
||||||
|
|
||||||
- I chose TOML and Markdown for their ease of use and flexibility, but the parser couldn't care less.
|
- I chose TOML and Markdown for their ease of use and flexibility, but the parser couldn't care less.
|
||||||
|
|
||||||
- …actually, that's a lie. see that code example above? Markdown code fences \`\`\` are handled specially to let you do that kind of stuff. that's all.
|
- …actually, that's a lie. see that code example above? Markdown code fences \`\`\` are handled specially to let embed `.tree` source code blocks within `.tree` files. that's all.
|
||||||
|
|
||||||
- you may have noticed in that code example above that almost every branch has an `id` attribute.
|
- you may have noticed in that code example above that almost every branch has an `id` attribute.
|
||||||
|
|
||||||
|
@ -261,6 +272,16 @@
|
||||||
|
|
||||||
- which is cool because it's much denser while avoiding ambiguous characters - `0`, `O`, and `o` are all interpreted as `0` (zero).
|
- which is cool because it's much denser while avoiding ambiguous characters - `0`, `O`, and `o` are all interpreted as `0` (zero).
|
||||||
|
|
||||||
|
- noticed how fast the treehouse restores your state? there's basically no delay.
|
||||||
|
|
||||||
|
- this is because it restores your state _as it's loading in_, by using [Web Components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements).
|
||||||
|
|
||||||
|
- despite many people calling that API extremely low-level, I beg to differ. it's actually pretty easy and pleasant to use.
|
||||||
|
|
||||||
|
- most importantly it lets me enhance vanilla `<li>` elements with custom behavior executed on load, which I use to restore your reading progress as the page is loading in.
|
||||||
|
|
||||||
|
- linked branches also use Web Components by the way.
|
||||||
|
|
||||||
- while not strictly a technical topic, I'd like to shout out [Recursive](https://recursive.design) for being an awesome font :ralsei_love:
|
- while not strictly a technical topic, I'd like to shout out [Recursive](https://recursive.design) for being an awesome font :ralsei_love:
|
||||||
|
|
||||||
- (not to be confused with Font Awesome, which I do not use here. icon designs are my own.)
|
- (not to be confused with Font Awesome, which I do not use here. icon designs are my own.)
|
||||||
|
|
|
@ -97,10 +97,10 @@
|
||||||
- [DELTARUNE](https://deltarune.com)
|
- [DELTARUNE](https://deltarune.com)
|
||||||
|
|
||||||
% id = "01H89P3CH89TQ3SFG2Z40J29HX"
|
% id = "01H89P3CH89TQ3SFG2Z40J29HX"
|
||||||
- they're pretty great you should check them out (also check out [my games corner][page:/games]? :pleading_face:)
|
- they're pretty great you should check them out (also check out [my games corner][page:games]? :pleading_face:)
|
||||||
|
|
||||||
% id = "01H89P3CH8AJATQ5DJBBFXJ1NH"
|
% id = "01H89P3CH8AJATQ5DJBBFXJ1NH"
|
||||||
- or [music][page:/music]
|
- or [music][page:music]
|
||||||
|
|
||||||
% id = "01H89P3CH8XQ59YZD3RFRYQ2BM"
|
% id = "01H89P3CH8XQ59YZD3RFRYQ2BM"
|
||||||
- various genres from electronic through jazz and even rock
|
- various genres from electronic through jazz and even rock
|
||||||
|
@ -153,7 +153,7 @@
|
||||||
- anyways you can find me on
|
- anyways you can find me on
|
||||||
|
|
||||||
% id = "01H89P3CH8EMM31JEMJRVRAKF4"
|
% id = "01H89P3CH8EMM31JEMJRVRAKF4"
|
||||||
+ Discord - username is [this](#01H89P3CH8GAHS8DDW1HHEWA3P)
|
+ Discord - username is [this][b:01H89P3CH8GAHS8DDW1HHEWA3P]
|
||||||
|
|
||||||
% id = "01H89P3CH89HHDVHGB9GE287TR"
|
% id = "01H89P3CH89HHDVHGB9GE287TR"
|
||||||
- I'm most active there so you'll have the best chance of getting a reply
|
- I'm most active there so you'll have the best chance of getting a reply
|
||||||
|
@ -162,7 +162,7 @@
|
||||||
- you'll know it's me if you see a profile with a fluffy boy avatar
|
- you'll know it's me if you see a profile with a fluffy boy avatar
|
||||||
|
|
||||||
% id = "01H89P3CH8WTBKXP0GGN0HYQK2"
|
% id = "01H89P3CH8WTBKXP0GGN0HYQK2"
|
||||||
+ Matrix - username is [this](#01H89P3CH8943QGT52K7MRW12Q) at gacko.pl
|
+ Matrix - username is [this][b:01H89P3CH8943QGT52K7MRW12Q] at gacko.pl
|
||||||
|
|
||||||
% id = "01H89P3CH832E4GK0NJ77KED06"
|
% id = "01H89P3CH832E4GK0NJ77KED06"
|
||||||
- I try to be as active there as on Discord but my availability may be a little more
|
- I try to be as active there as on Discord but my availability may be a little more
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
|
|
||||||
- welcome! make yourself at home
|
- welcome! make yourself at home
|
||||||
|
|
||||||
- this is my treehouse, the place on the Internet I like to call home.
|
---
|
||||||
|
|
||||||
% id = "about"
|
% id = "about"
|
||||||
content.link = "about"
|
content.link = "about"
|
||||||
+ ## about yourself
|
+ ## about me
|
||||||
|
|
||||||
% id = "about-treehouse"
|
% id = "about-treehouse"
|
||||||
content.link = "about-treehouse"
|
content.link = "about-treehouse"
|
||||||
|
|
|
@ -31,17 +31,21 @@ pub fn branch_to_html(s: &mut String, treehouse: &mut Treehouse, file_id: FileId
|
||||||
);
|
);
|
||||||
|
|
||||||
let class = if has_children { "branch" } else { "leaf" };
|
let class = if has_children { "branch" } else { "leaf" };
|
||||||
|
let component = if let Content::Link(_) = attributes.content {
|
||||||
|
"th-b-linked"
|
||||||
|
} else {
|
||||||
|
"th-b"
|
||||||
|
};
|
||||||
|
|
||||||
let linked_branch = if let Content::Link(link) = &attributes.content {
|
let linked_branch = if let Content::Link(link) = &attributes.content {
|
||||||
format!(
|
format!(" data-th-link=\"{}\"", EscapeHtml(link))
|
||||||
" is=\"th-linked-branch\" data-th-link=\"{}\"",
|
|
||||||
EscapeHtml(link)
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
s,
|
s,
|
||||||
"<li class=\"{class}\" id=\"{}\"{linked_branch}>",
|
"<li is=\"{component}\" class=\"{class}\" id=\"{}\"{linked_branch}>",
|
||||||
EscapeAttribute(&id)
|
EscapeAttribute(&id)
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -6,7 +6,6 @@ use codespan_reporting::{
|
||||||
files::SimpleFiles,
|
files::SimpleFiles,
|
||||||
term::termcolor::{ColorChoice, StandardStream},
|
term::termcolor::{ColorChoice, StandardStream},
|
||||||
};
|
};
|
||||||
use log::debug;
|
|
||||||
use ulid::Ulid;
|
use ulid::Ulid;
|
||||||
|
|
||||||
pub type Files = SimpleFiles<String, String>;
|
pub type Files = SimpleFiles<String, String>;
|
||||||
|
|
|
@ -1,13 +1,41 @@
|
||||||
class LinkedBranch extends HTMLLIElement {
|
const branchStateKey = "treehouse.openBranches";
|
||||||
|
let branchState = JSON.parse(localStorage.getItem(branchStateKey)) || {};
|
||||||
|
|
||||||
|
function saveBranchIsOpen(branchID, state) {
|
||||||
|
branchState[branchID] = state;
|
||||||
|
localStorage.setItem(branchStateKey, JSON.stringify(branchState));
|
||||||
|
}
|
||||||
|
|
||||||
|
function branchIsOpen(branchID) {
|
||||||
|
return branchState[branchID];
|
||||||
|
}
|
||||||
|
|
||||||
|
class Branch extends HTMLLIElement {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.details = this.childNodes[0];
|
||||||
|
this.innerUL = this.details.childNodes[1];
|
||||||
|
|
||||||
|
let isOpen = branchIsOpen(this.id);
|
||||||
|
if (isOpen !== undefined) {
|
||||||
|
this.details.open = isOpen;
|
||||||
|
}
|
||||||
|
this.details.addEventListener("toggle", _ => {
|
||||||
|
saveBranchIsOpen(this.id, this.details.open);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("th-b", Branch, { extends: "li" });
|
||||||
|
|
||||||
|
class LinkedBranch extends Branch {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.linkedTree = this.getAttribute("data-th-link");
|
this.linkedTree = this.getAttribute("data-th-link");
|
||||||
|
|
||||||
this.details = this.childNodes[0];
|
this.loadingState = "notloaded";
|
||||||
this.innerUL = this.details.childNodes[1];
|
|
||||||
|
|
||||||
this.state = "notloaded";
|
|
||||||
|
|
||||||
this.loadingText = document.createElement("p");
|
this.loadingText = document.createElement("p");
|
||||||
{
|
{
|
||||||
|
@ -19,12 +47,13 @@ class LinkedBranch extends HTMLLIElement {
|
||||||
this.innerUL.appendChild(this.loadingText);
|
this.innerUL.appendChild(this.loadingText);
|
||||||
|
|
||||||
// This produces a warning during static generation but we still want to handle that
|
// This produces a warning during static generation but we still want to handle that
|
||||||
// correctly. Having an expanded-by-default linked block can be useful in development.
|
// correctly, as Branch saves the state in localStorage. Having an expanded-by-default
|
||||||
|
// linked block can be useful in development.
|
||||||
if (this.details.open) {
|
if (this.details.open) {
|
||||||
this.loadTree();
|
this.loadTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.details.addEventListener("toggle", event => {
|
this.details.addEventListener("toggle", _ => {
|
||||||
if (this.details.open) {
|
if (this.details.open) {
|
||||||
this.loadTree();
|
this.loadTree();
|
||||||
}
|
}
|
||||||
|
@ -32,8 +61,8 @@ class LinkedBranch extends HTMLLIElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
loadTree() {
|
loadTree() {
|
||||||
if (this.state == "notloaded") {
|
if (this.loadingState == "notloaded") {
|
||||||
this.state = "loading";
|
this.loadingState = "loading";
|
||||||
|
|
||||||
fetch(`/${this.linkedTree}.html`)
|
fetch(`/${this.linkedTree}.html`)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
|
@ -46,26 +75,22 @@ class LinkedBranch extends HTMLLIElement {
|
||||||
let parser = new DOMParser();
|
let parser = new DOMParser();
|
||||||
let linkedDocument = parser.parseFromString(text, "text/html");
|
let linkedDocument = parser.parseFromString(text, "text/html");
|
||||||
let main = linkedDocument.getElementsByTagName("main")[0];
|
let main = linkedDocument.getElementsByTagName("main")[0];
|
||||||
let ul /*: Element */ = main.getElementsByTagName("ul")[0];
|
let ul = main.getElementsByTagName("ul")[0];
|
||||||
console.log(ul);
|
|
||||||
|
|
||||||
this.loadingText.remove();
|
this.loadingText.remove();
|
||||||
|
this.innerUL.innerHTML = ul.innerHTML;
|
||||||
|
|
||||||
for (let i = 0; i < ul.childNodes.length; ++i) {
|
this.loadingState = "loaded";
|
||||||
this.innerUL.appendChild(ul.childNodes[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.state = "loaded";
|
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
this.loadingText.innerText = error.toString();
|
this.loadingText.innerText = error.toString();
|
||||||
this.state = "error";
|
this.loadingState = "error";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("th-linked-branch", LinkedBranch, { extends: "li" });
|
customElements.define("th-b-linked", LinkedBranch, { extends: "li" });
|
||||||
|
|
||||||
function expandDetailsRecursively(element) {
|
function expandDetailsRecursively(element) {
|
||||||
while (element && element.tagName != "MAIN") {
|
while (element && element.tagName != "MAIN") {
|
||||||
|
|
|
@ -33,18 +33,9 @@
|
||||||
miners.</strong><br>
|
miners.</strong><br>
|
||||||
if you don't believe me, you're free to inspect the source yourself! all the scripts are written
|
if you don't believe me, you're free to inspect the source yourself! all the scripts are written
|
||||||
lovingly in vanilla JS (not minified!) by yours truly ❤️</p>
|
lovingly in vanilla JS (not minified!) by yours truly ❤️</p>
|
||||||
<small>and if this box is annoying, feel free to zap it with uBlock Origin or something. I have no
|
<small>and if this box is annoying, feel free to block it with uBlock Origin or something. I have no
|
||||||
way of remembering you closed it, and don't wanna host this site on a dynamic server.</small>
|
way of remembering you closed it, and don't wanna host this site on a dynamic server.</small>
|
||||||
|
</div>
|
||||||
{{!-- <form method="dialog">
|
|
||||||
<button name="th-noscript-close" class="noscript-close">I understand and wish to proceed without
|
|
||||||
JavaScript. And don't nag me about it anymore.<br>
|
|
||||||
I consent to you storing a cookie on my device to remember this decision.</button>
|
|
||||||
</form>
|
|
||||||
--}}
|
|
||||||
{{!-- I disabled the button because I can't figure out a way to do this without storing a cookie, and I
|
|
||||||
don't like those. I'd prefer if this website were fully static. --}}
|
|
||||||
</dialog>
|
|
||||||
</noscript>
|
</noscript>
|
||||||
|
|
||||||
<main class="tree">
|
<main class="tree">
|
||||||
|
|
Loading…
Reference in a new issue