revamp the way page:treehouse/new works

- treehouse/new is now a regular page, not a special template
- most of the code related to the `new` badge in page:index has been removed
- you're meant to discern between pages you've read vs ones you haven't by looking at the colors of the links (blue vs purple)
This commit is contained in:
liquidex 2024-11-12 19:49:57 +01:00
parent 8d1deee626
commit e201ea7058
6 changed files with 128 additions and 362 deletions

View file

@ -1,133 +1,159 @@
%% template = "_new.hbs" %% title = "a curated feed of updates to the house"
title = "a curated feed of updates to the house"
styles = ["new.css"] styles = ["new.css"]
feed = "news"
% id = "01J4J5N6WZQ03VTB3TZ51J7QZK" % id = "01JCGWPM6T73PAC5Q8YHPBEAA1"
- [featured]{.badge .blue} I was bored over a weekend, so I decided to write the tiniest programming language I could imagine. + hello!
it came out looking pretty Lispy, and I'm glad about that! if you've been wondering what I've been up to, you've come to the right place.
I learned a ton about Lisps in the process of researching it.
even though it didn't end up having macros...
### haku - writing a little programming language for fun % id = "01JCGWPM6T3W07KAGG3J29JMVF"
- posts are sorted from newest to oldest.
[read][page:programming/blog/haku] % id = "01JCGWPM6TGQ17JPSJW8G58SB0"
- you can keep track of which posts you've read by looking at the color of the links.
% id = "01JCGWPM6TMAJT0B50GQSA4BDW"
- there is currently no RSS or Atom feed for this page, sorry!
% id = "01JBAGZAZ30K443QYPK0XBNZWM" % id = "01JBAGZAZ30K443QYPK0XBNZWM"
- ### the curious case of Amon Tobin's Creatures - ### [the curious case of Amon Tobin's Creatures][page:music/creatures]
a weird anomaly I noticed while listening to some breaks % id = "01JBAGZAZ3NKBED4M9FANR5RPZ"
- a weird anomaly I noticed while listening to some breaks
[read][page:music/creatures]
% id = "01J8ZP2EG9TM8320R9E3K1GQEC" % id = "01J8ZP2EG9TM8320R9E3K1GQEC"
- I was listening to Oneohtrix Point Never's _Magic Oneohtrix Point Never_, and had some retrospective thoughts about the distorted vocals in... - ### [I Don't Love Me Anymore][page:music/reviews/opn/i-dont-love-me-anymore]
### I Don't Love Me Anymore % id = "01J8ZP2EG96VQ2ZK0XYK0FK1NR"
- I was listening to Oneohtrix Point Never's _Magic Oneohtrix Point Never_, and had some retrospective thoughts about the vocals in this song.
it's also a nice opportunity to say that I've refreshed the music section a bit! % id = "01J8ZP2EG92T1SM7F6MTCXZHNJ"
- it's also a nice opportunity to say that I've refreshed the music section a bit!
[read][page:music/reviews/opn/i-dont-love-me-anymore]
% id = "01J7C1KBZ58BR21AVFA1PMWV68" % id = "01J7C1KBZ58BR21AVFA1PMWV68"
- ### [not quite buildless][page:programming/blog/buildsome]
% id = "01J7C1KBZ5XKZRN4V5BWFQTV6Y"
- I like lean websites. did you know that? - I like lean websites. did you know that?
I also really like lean websites that are simple in construction and deployment. did you know the treehouse is a website like that? % id = "01J7C1KBZ50EMBK9VPH9CE3F7H"
- I also really like lean websites that are simple in construction and deployment. did you know the treehouse is a website like that?
so I've decided to write up a few anecdotes and other cool stories about the treehouse's inner workings. % id = "01J7C1KBZ5QCVM6DDT9G5KQGP2"
- so I've decided to write up a few anecdotes and other cool stories about the treehouse's inner workings.
also, it's (way past) its one year anniversary! hooray! % id = "01J7C1KBZ5S0XTQXKY41VZNWJZ"
- also, it's (way past) its one year anniversary! hooray!
### not quite buildless
[read][page:programming/blog/buildsome]
% id = "01J73BSWA15KHTQ21T0S14NZW0" % id = "01J73BSWA15KHTQ21T0S14NZW0"
- ### [the ListenBrainz data set][page:music/brainz]
% id = "01J73BSWA1EX7ZP28KCCG088DD"
- I decided to write up some ideas on what sort of cool data analysis I could do on my [ListenBrainz data set][def:social/listenbrainz]. - I decided to write up some ideas on what sort of cool data analysis I could do on my [ListenBrainz data set][def:social/listenbrainz].
I haven't done any of it yet, but I thought it'd be cool to share my ideas anyways!
### the ListenBrainz data set % id = "01J73BSWA1ANRQ31DNYHTNPSP5"
- I haven't done any of it yet, but I thought it'd be cool to share my ideas anyways!
[read][page:music/brainz] % id = "01J4J5N6WZQ03VTB3TZ51J7QZK"
- ### [haku - writing a little programming language for fun][page:programming/blog/haku]
% id = "01J4J5N6WZQ1316WKDXB1M5W6E"
- I was bored over a weekend, so I decided to write the tiniest programming language I could imagine.
% id = "01J4J5N6WZ2RW32HJX1VBJM58X"
- it came out looking pretty Lispy, and I'm glad about that!
% id = "01J4J5N6WZV6E1AHF65PQ5J6GF"
- I learned a ton about Lisps in the process of researching it.
even though it didn't end up having macros...
% id = "01J293BFEBT15W0Z3XF1HEFGZT" % id = "01J293BFEBT15W0Z3XF1HEFGZT"
- ### [JavaScript is not as bad as people make it out to be][page:programming/languages/javascript]
% id = "01J293BFEB4G7214N20SZA8V7W"
- sometimes people call me crazy for saying that bashing JavaScript is senseless and that it's not as bad of a language as people make it out to be. - sometimes people call me crazy for saying that bashing JavaScript is senseless and that it's not as bad of a language as people make it out to be.
so I decided to collect my thoughts into a nice little page I can link easily.
### JavaScript is not as bad as people make it out to be % id = "01J293BFEBYSW4K7YHVN42J3WP"
- so I decided to collect my thoughts into a nice little page I can link easily.
[why dude why][page:programming/languages/javascript]
% id = "01J0VNHPTRNC1HFXAQ790Y1EZB" % id = "01J0VNHPTRNC1HFXAQ790Y1EZB"
- ### [freeing C memory automatically using `std::unique_ptr` and `std::shared_ptr`][page:programming/languages/cxx/shared-unique-ptr-deleter]
% id = "01J0VNHPTRP51XYDA4N2RPG58F"
- a friend of mine asked if it makes sense to define your own wrapper class for `SDL_Window` the way [Lazy Foo](https://lazyfoo.net/tutorials/SDL/10_color_keying/index.php) does it. - a friend of mine asked if it makes sense to define your own wrapper class for `SDL_Window` the way [Lazy Foo](https://lazyfoo.net/tutorials/SDL/10_color_keying/index.php) does it.
I told him there's no reason to do that in modern C++, because `std::unique_ptr` can do everything for you anyways.
### freeing C memory automatically using `std::unique_ptr` and `std::shared_ptr` % id = "01J0VNHPTRW3XR4YG0GWGFF4N4"
- I told him there's no reason to do that in modern C++, because `std::unique_ptr` can do everything for you anyways.
~on another note, I did read a blog post about this once somewhere, but couldn't be bothered to find it. so there you go! I made a post about this too.~ % id = "01J0VNHPTRMXFTH3F601R7V1S9"
- on another note, I did read a blog post about this once somewhere, but couldn't be bothered to find it. so there you go! I made a post about this too.
[read][page:programming/languages/cxx/shared-unique-ptr-deleter]
% id = "01J0KRPMV7SS48B64BFCJZK7VQ" % id = "01J0KRPMV7SS48B64BFCJZK7VQ"
- ### [about me (version 2)][page:about]
% id = "01J0KRPMV73K71D3QXFQ3GNY2N"
- it's updatin' time! I took some time to clean up old pages and update my _about me_.\ - it's updatin' time! I took some time to clean up old pages and update my _about me_.\
over time I've been learning how to write content on the treehouse effectively, and the new about me reflects that. over time I've been learning how to write content on the treehouse effectively, and the new about me reflects that.
### about me (version 2) % id = "01J0KRPMV7KD7X3HHXGKBS0VAX"
- [version 1][page:about/v1]
[read][page:about] [version 1][page:about/v1]
% id = "01HY5R1ZW2PYZSSP2J2KAA23DA" % id = "01HY5R1ZW2PYZSSP2J2KAA23DA"
- ### [what's up with `*x` not always meaning the same thing in different contexts?][page:programming/blog/lvalues]
% id = "01HY5R1ZW24YJ2NF2RYWRZG4ZT"
- I recently got a question from my someone telling me they doesn't understand why `*x` does not read from the pointer `x` when on the left-hand side of an assignment. - I recently got a question from my someone telling me they doesn't understand why `*x` does not read from the pointer `x` when on the left-hand side of an assignment.
and that made me think, and that made me think, _why_ is that the case?
### what's up with `*x` not always meaning the same thing in different contexts?
[read][page:programming/blog/lvalues]
% id = "01HV1DGFHZ65GJVQRSREKR67J9" % id = "01HV1DGFHZ65GJVQRSREKR67J9"
- ### [systems are just a bunch of code][page:programming/blog/systems]
% id = "01HV1DGFHZFFZSQNCVWBTJ1VHM"
- I've been thinking recently how cool it is to be able to single-step into Unreal Engine's source code and edit it while you're working with it, and how uncool it is that I can't do the same thing easily in the Rust world. - I've been thinking recently how cool it is to be able to single-step into Unreal Engine's source code and edit it while you're working with it, and how uncool it is that I can't do the same thing easily in the Rust world.
after all, aren't we just dealing with a bunch of code running on the computer? why not let me poke at it? % id = "01HV1DGFHZGFYWT5MMM57SEWNN"
- after all, aren't we just dealing with a bunch of code running on the computer? why not let me poke at it?
### systems are just a bunch of code % id = "01HV1DGFHZ2SDPDV3VYRR7VBRR"
- bonus: [dismantling Unreal Engine's `GENERATED_BODY`][page:programming/technologies/unreal-engine/generated-body]
[can _you_ can read other people's code?][page:programming/blog/systems] [bonus: dismantling Unreal Engine's GENERATED_BODY][page:programming/technologies/unreal-engine/generated-body]
% id = "01HTWNETT2S5NSBF3QR4HYA7HN" % id = "01HTWNETT2S5NSBF3QR4HYA7HN"
- ### [OR-types][page:programming/blog/or-types]
% id = "01HTWNETT2N8NPENETWYFBTXEM"
- last night I couldn't sleep because of type theory. in the process of trying to write down my thoughts, I ended up discovering a class of types which, to my knowledge, no language implements. - last night I couldn't sleep because of type theory. in the process of trying to write down my thoughts, I ended up discovering a class of types which, to my knowledge, no language implements.
### OR-types
[what the hell do you mean, aren't sum types exactly that??][page:programming/blog/or-types]
% id = "01HRG3VN091V715A8T54QK5PVX" % id = "01HRG3VN091V715A8T54QK5PVX"
- I really like Lua, did you know that? but I get kind of tired of explaining why a thousand times to people who don't know the language, so… - ### [programming languages: Lua][page:programming/languages/lua]
### programming languages: Lua % id = "01HRG3VN095BNHERHWVX1TKS9K"
- I really like Lua, did you know that? but I get kind of tired of explaining why a thousand times to people who don't know the language, so here's a page with my thoughts!
[read why I like it so much][page:programming/languages/lua]
% id = "01HR9ZTS8RS4VJNJYSNRQYSKHZ" % id = "01HR9ZTS8RS4VJNJYSNRQYSKHZ"
- sidebars! also known as, _"enjoying the main content? how about I distract you from it so that you can't focus!"_\ - ### [design: sidebars][page:design/sidebars]
seriously though. I don't like them.
### design: sidebars % id = "01HR9ZTS8RY3N4EJM5W7WBTF0G"
- sidebars! also known as, _"enjoying the main content? how about I distract you from it so that you can't focus!"_
[read why I don't like them so much][page:design/sidebars] % id = "01HR9ZTS8RQ1EN0THYEVNQRY2A"
- seriously though. I don't like them.
% id = "01HQ8KV8T8GRCVFDJ3EP6QE163" % id = "01HQ8KV8T8GRCVFDJ3EP6QE163"
- ### [liquidex's treehouse: design][page:design]
% id = "01HQ8KV8T8EEX6XBG2K1X3FGKW"
- I started a branch on user interface and user experience design, because I was working with mintty at work and had some thoughts about it. - I started a branch on user interface and user experience design, because I was working with mintty at work and had some thoughts about it.
"why does mintty always feel so _out of place_ compared to `cmd.exe`?" "why does mintty always feel so _out of place_ compared to `cmd.exe`?"
### liquidex's treehouse: design % id = "01HQ8KV8T865WKME5R9TD0DSTN"
- I also wrote a post summarising my thoughts: [_on digital textures_][page:design/digital-textures]
[read: _on digital textures_][page:design/digital-textures] [go to branch][page:design]
% id = "01HQ6G30PTVT5H0Z04VVRHEZQF" % id = "01HQ6G30PTVT5H0Z04VVRHEZQF"
- ### [tairu - an interactive exploration of 2D autotiling techniques][page:programming/blog/tairu]
% id = "01HQ6G30PTG8QA5MAPEJPWSM14"
- ever wondered how Terraria renders its worlds? or how editors like Tiled manage to make painting tiles so easy? - ever wondered how Terraria renders its worlds? or how editors like Tiled manage to make painting tiles so easy?
### tairu - an interactive exploration of 2D autotiling techniques % id = "01HQ6G30PT1D729Z29NYVDCFDB"
- this post explores basically just that.
[read][page:programming/blog/tairu]

View file

@ -1,134 +1,33 @@
/* Give the intro and outro some breathing room. */ .tree .branch-container {
section { &:has(th-bc > h3) > th-bb {
padding: 1em 2em;
}
/* Style all links in the last paragraph as big buttons. */
.tree th-bc>p:last-child {
--transition-duration: 0.2s;
margin-top: var(--8px);
margin-bottom: var(--4px);
&>a {
display: inline-block;
padding: 0.5em 1.5em;
color: var(--text-color);
background-color: transparent;
border: var(--1px) solid var(--border-1);
border-radius: 2em;
text-decoration: none;
transition:
color var(--transition-duration),
background-color var(--transition-duration),
border-color var(--transition-duration);
&:hover,
&:focus {
color: white;
background-color: #058ef0;
border-color: white;
}
}
}
.tree li>div:first-child,
.tree li>details>summary:first-child {
--margin: 2.5em;
border: none;
margin-left: var(--tree-indent-width);
width: calc(100% - var(--tree-indent-width));
margin-top: var(--margin);
margin-bottom: var(--margin);
}
.tree th-bp {
display: none;
}
.tree th-bb {
opacity: 100%; opacity: 100%;
& .branch-date { & .branch-date {
display: block !important; display: block !important;
} }
} }
}
@media (max-width: 600px) { @media (max-width: 720px) {
.tree .branch-container { .tree .branch-container {
flex-direction: column-reverse; &:has(th-bc > h3) {
} flex-direction: column;
} padding-left: 1rem;
padding-top: 0.25rem;
padding-bottom: 0.25rem;
section.settings { & > th-bp {
& h3 {
display: inline;
}
& details>summary {
--recursive-wght: 700;
list-style: none;
cursor: pointer;
opacity: 50%;
transition: opacity var(--transition-duration);
&::-webkit-details-marker {
display: none; display: none;
} }
&::before { & > th-bc > h3 {
--recursive-casl: 0.0; margin-top: 0;
--recursive-mono: 1.0; margin-bottom: 0;
--recursive-slnt: 0.0;
content: '+';
margin-right: 0.3em;
opacity: 50%;
} }
&:hover { & > th-bb {
opacity: 100%; margin: 0;
} }
}
& details[open]>summary {
opacity: 100%;
&::before {
content: '-';
}
}
& p {
margin-bottom: var(--8px);
}
& button {
border: var(--1px) solid var(--border-1);
border-radius: 999px;
padding: var(--4px) var(--12px);
background: none;
color: var(--text-color);
font-size: 1rem;
cursor: pointer;
transition:
color var(--transition-duration),
background-color var(--transition-duration),
border-color var(--transition-duration);
&:hover {
color: white;
background-color: #058ef0;
border-color: white;
} }
} }
} }

View file

@ -1,71 +0,0 @@
// news.js because new.js makes the TypeScript language server flip out.
// Likely because `new` is a keyword, but also, what the fuck.
import { addSpell, spell } from "treehouse/spells.js";
import { getSettingValue } from "treehouse/settings.js";
import { Branch } from "treehouse/tree.js";
const seenStatesKey = "treehouse.news.seenBranches";
const seenStates = new Set(JSON.parse(localStorage.getItem(seenStatesKey)) || []);
let seenCount = seenStates.size;
let unseenCount = TREEHOUSE_NEWS_COUNT - seenCount;
function saveSeenStates() {
localStorage.setItem(seenStatesKey, JSON.stringify(Array.from(seenStates)));
}
function markAsRead(branch) {
let branchData = spell(branch, Branch);
if (!seenStates.has(branchData.namedID) && seenCount > 0) {
let badge = document.createElement("span");
badge.classList.add("badge", "red", "before-content");
badge.textContent = "new";
branchData.branchContent.firstChild.insertBefore(badge, branchData.branchContent.firstChild.firstChild);
}
seenStates.add(branchData.namedID);
}
export function initNewsPage() {
for (let [_, branch] of Branch.branchesByNamedID) {
markAsRead(branch);
}
saveSeenStates();
// If any branches are added past the initial load, add them to the seen set too.
Branch.onAdded.push(branch => {
markAsRead(branch);
saveSeenStates();
})
}
export function markAllAsUnread() {
localStorage.removeItem(seenStatesKey);
}
addSpell("new", class New {
constructor(element) {
// Do not show the badge to people who have never seen any news.
// It's just annoying in that case.
// In case you do not wish to see the badge anymore, go to the news page and uncheck the
// checkbox at the bottom.
let userSawNews = seenCount > 0;
let userWantsToSeeNews = getSettingValue("showNewPostIndicator");
if (userSawNews && userWantsToSeeNews && unseenCount > 0) {
this.newText = document.createElement("span");
this.newText.classList.add("new-text");
this.newText.textContent = element.textContent;
element.textContent = "";
element.appendChild(this.newText);
this.badge = document.createElement("span");
this.badge.classList.add("badge", "red");
this.badge.textContent = unseenCount.toString();
element.appendChild(this.badge);
element.classList.add("has-news");
}
}
});

View file

@ -1,72 +0,0 @@
<!DOCTYPE html>
<html lang="en-US" prefix="og: https://ogp.me/ns#">
<head>
{{> components/_head.hbs }}
</head>
<body>
{{#> components/_nav.hbs }}
{{!-- For /index, include a "new" link that goes to the curated news feed page. --}}
{{#if (eq page.tree_path "index")}}
<a href="{{ config.site }}/treehouse/new" data-cast="new">new</a>
{{/if}}
{{/ components/_nav.hbs }}
{{> components/_noscript.hbs }}
<section>
<p>welcome!</p>
<p>since you clicked here, you must be curious as to what's been going on since your last visit to the house. so
here's a recap just for you - enjoy!</p>
</section>
{{> components/_tree.hbs }}
<section>
<p>note that this page does not include any updates that were made to the website itself - for that, you can
visit <a href="{{ config.site }}/treehouse/changelog">the changelog</a>.
</p>
</section>
<section class="settings" data-cast="js">
<details>
<summary>
settings
</summary>
<section>
<p>if you find the newsfeed annoying, you can customize some aspects of it.</p>
<p>
<input type="checkbox" data-cast="setting-checkbox" id="showNewPostIndicator">
<label for="showNewPostIndicator">show the <span class="badge red">1</span> badge on the homepage
for
new posts you haven't read yet</label>
</p>
<p>
<button id="mark-all-as-unread"
title="Mostly useful for debugging purposes, but it's there if you really wanna do it.">
mark all as unread</button>
</p>
</section>
</details>
</section>
{{!-- For all pages except the one linked from the footer, include the footer icon. --}}
{{#if (ne page.tree_path "treehouse")}}
{{> components/_footer.hbs }}
{{/if}}
<script type="module" defer>
import { initNewsPage, markAllAsUnread } from "{{ config.site }}/static/js/news.js";
initNewsPage();
document.getElementById("mark-all-as-unread").addEventListener("click", () => {
markAllAsUnread();
alert("congration! you done it");
});
</script>
</body>
</html>

View file

@ -18,7 +18,6 @@ clever to do while browser vendors figure that out, we'll just have to do a cach
<script> <script>
const TREEHOUSE_SITE = `{{ config.site }}`; const TREEHOUSE_SITE = `{{ config.site }}`;
const TREEHOUSE_NEWS_COUNT = {{ len feeds.news.branches }};
{{!-- Yeah, this should probably be solved in a better way somehow. {{!-- Yeah, this should probably be solved in a better way somehow.
For now this is used to allow literate-programming.js to refer to syntax files with the ?cache attribute, For now this is used to allow literate-programming.js to refer to syntax files with the ?cache attribute,
@ -35,7 +34,6 @@ clever to do while browser vendors figure that out, we'll just have to do a cach
import "treehouse/settings.js"; import "treehouse/settings.js";
import "treehouse/tree.js"; import "treehouse/tree.js";
import "treehouse/emoji.js"; import "treehouse/emoji.js";
import "treehouse/news.js";
</script> </script>
<meta property="og:site_name" content="{{ config.user.title }}"> <meta property="og:site_name" content="{{ config.user.title }}">

View file

@ -3,17 +3,3 @@
{{{ include_static 'svg/object/logo.svg' }}} {{{ include_static 'svg/object/logo.svg' }}}
</a> </a>
</nav> </nav>
{{!--
I don't have any idea where to put this right now.
There's no obvious place, and even when it is there, I hate the hideous red badge on new entries.
No time to figure it out. Will do later.
{{#if (eq page.tree_path 'index')}}
<nav id="nav-links">
<a href="{{ config.site }}/treehouse/new" data-cast="new">new</a>
</nav>
{{/if}}
--}}