rework branches a bit to support saving

This commit is contained in:
liquidex 2023-08-22 19:23:31 +02:00
parent 6c110b61a2
commit 582447e02b
8 changed files with 99 additions and 59 deletions

View file

@ -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]?

View file

@ -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,7 +203,8 @@
- 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" \% id = "root"
\- this is a branch \- this is a branch
@ -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.)

View file

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

View file

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

View file

@ -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();

View file

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

View file

@ -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") {

View file

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