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"
|
||||
- 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"
|
||||
- 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:
|
||||
|
||||
|
@ -149,10 +151,10 @@
|
|||
- 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…
|
||||
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"
|
||||
- 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.
|
||||
|
||||
|
@ -162,7 +164,7 @@
|
|||
- (yes, I know that website is super old, but I still find it incredibly funny :hueh:)
|
||||
|
||||
% 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.
|
||||
|
||||
- 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.
|
||||
|
||||
- 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
|
||||
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.
|
||||
|
||||
- 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 branch links to another tree
|
||||
```
|
||||
\- and this is a child of that branch
|
||||
|
||||
\% 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
|
||||
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
|
||||
|
||||
- …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.
|
||||
|
||||
- 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.
|
||||
|
||||
|
@ -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).
|
||||
|
||||
- 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:
|
||||
|
||||
- (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)
|
||||
|
||||
% 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"
|
||||
- or [music][page:/music]
|
||||
- or [music][page:music]
|
||||
|
||||
% id = "01H89P3CH8XQ59YZD3RFRYQ2BM"
|
||||
- various genres from electronic through jazz and even rock
|
||||
|
@ -153,7 +153,7 @@
|
|||
- anyways you can find me on
|
||||
|
||||
% id = "01H89P3CH8EMM31JEMJRVRAKF4"
|
||||
+ Discord - username is [this](#01H89P3CH8GAHS8DDW1HHEWA3P)
|
||||
+ Discord - username is [this][b:01H89P3CH8GAHS8DDW1HHEWA3P]
|
||||
|
||||
% id = "01H89P3CH89HHDVHGB9GE287TR"
|
||||
- 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
|
||||
|
||||
% id = "01H89P3CH8WTBKXP0GGN0HYQK2"
|
||||
+ Matrix - username is [this](#01H89P3CH8943QGT52K7MRW12Q) at gacko.pl
|
||||
+ Matrix - username is [this][b:01H89P3CH8943QGT52K7MRW12Q] at gacko.pl
|
||||
|
||||
% id = "01H89P3CH832E4GK0NJ77KED06"
|
||||
- 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
|
||||
|
||||
- this is my treehouse, the place on the Internet I like to call home.
|
||||
---
|
||||
|
||||
% id = "about"
|
||||
content.link = "about"
|
||||
+ ## about yourself
|
||||
+ ## about me
|
||||
|
||||
% id = "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 component = if let Content::Link(_) = attributes.content {
|
||||
"th-b-linked"
|
||||
} else {
|
||||
"th-b"
|
||||
};
|
||||
|
||||
let linked_branch = if let Content::Link(link) = &attributes.content {
|
||||
format!(
|
||||
" is=\"th-linked-branch\" data-th-link=\"{}\"",
|
||||
EscapeHtml(link)
|
||||
)
|
||||
format!(" data-th-link=\"{}\"", EscapeHtml(link))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
write!(
|
||||
s,
|
||||
"<li class=\"{class}\" id=\"{}\"{linked_branch}>",
|
||||
"<li is=\"{component}\" class=\"{class}\" id=\"{}\"{linked_branch}>",
|
||||
EscapeAttribute(&id)
|
||||
)
|
||||
.unwrap();
|
||||
|
|
|
@ -6,7 +6,6 @@ use codespan_reporting::{
|
|||
files::SimpleFiles,
|
||||
term::termcolor::{ColorChoice, StandardStream},
|
||||
};
|
||||
use log::debug;
|
||||
use ulid::Ulid;
|
||||
|
||||
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() {
|
||||
super();
|
||||
|
||||
this.linkedTree = this.getAttribute("data-th-link");
|
||||
|
||||
this.details = this.childNodes[0];
|
||||
this.innerUL = this.details.childNodes[1];
|
||||
|
||||
this.state = "notloaded";
|
||||
this.loadingState = "notloaded";
|
||||
|
||||
this.loadingText = document.createElement("p");
|
||||
{
|
||||
|
@ -19,12 +47,13 @@ class LinkedBranch extends HTMLLIElement {
|
|||
this.innerUL.appendChild(this.loadingText);
|
||||
|
||||
// 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) {
|
||||
this.loadTree();
|
||||
}
|
||||
|
||||
this.details.addEventListener("toggle", event => {
|
||||
this.details.addEventListener("toggle", _ => {
|
||||
if (this.details.open) {
|
||||
this.loadTree();
|
||||
}
|
||||
|
@ -32,8 +61,8 @@ class LinkedBranch extends HTMLLIElement {
|
|||
}
|
||||
|
||||
loadTree() {
|
||||
if (this.state == "notloaded") {
|
||||
this.state = "loading";
|
||||
if (this.loadingState == "notloaded") {
|
||||
this.loadingState = "loading";
|
||||
|
||||
fetch(`/${this.linkedTree}.html`)
|
||||
.then(response => {
|
||||
|
@ -46,26 +75,22 @@ class LinkedBranch extends HTMLLIElement {
|
|||
let parser = new DOMParser();
|
||||
let linkedDocument = parser.parseFromString(text, "text/html");
|
||||
let main = linkedDocument.getElementsByTagName("main")[0];
|
||||
let ul /*: Element */ = main.getElementsByTagName("ul")[0];
|
||||
console.log(ul);
|
||||
let ul = main.getElementsByTagName("ul")[0];
|
||||
|
||||
this.loadingText.remove();
|
||||
this.innerUL.innerHTML = ul.innerHTML;
|
||||
|
||||
for (let i = 0; i < ul.childNodes.length; ++i) {
|
||||
this.innerUL.appendChild(ul.childNodes[i]);
|
||||
}
|
||||
|
||||
this.state = "loaded";
|
||||
this.loadingState = "loaded";
|
||||
})
|
||||
.catch(error => {
|
||||
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) {
|
||||
while (element && element.tagName != "MAIN") {
|
||||
|
|
|
@ -33,18 +33,9 @@
|
|||
miners.</strong><br>
|
||||
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>
|
||||
<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>
|
||||
|
||||
{{!-- <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>
|
||||
</div>
|
||||
</noscript>
|
||||
|
||||
<main class="tree">
|
||||
|
|
Loading…
Reference in a new issue