This commit is contained in:
りき萌 2024-02-21 23:17:19 +01:00
parent d64cc3fbf2
commit a1464bb865
20 changed files with 636 additions and 193 deletions

View file

@ -184,6 +184,7 @@ class OutputMode {
});
if (this.frame.placeholderImage != null) {
this.frame.placeholderImage.classList.add("js");
this.frame.placeholderImage.classList.add("loading");
}

70
static/js/news.js Normal file
View file

@ -0,0 +1,70 @@
// news.js because new.js makes the TypeScript language server flip out.
// Likely because `new` is a keyword, but also, what the fuck.
import { getSettingValue } from "./settings.js";
import { Branch } from "./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) {
if (!seenStates.has(branch.namedID) && seenCount > 0) {
let badge = document.createElement("span");
badge.classList.add("badge", "red", "before-content");
badge.textContent = "new";
branch.branchContent.firstChild.insertBefore(badge, branch.branchContent.firstChild.firstChild);
}
seenStates.add(branch.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);
}
class New extends HTMLAnchorElement {
connectedCallback() {
// 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 = this.textContent;
this.textContent = "";
this.appendChild(this.newText);
this.badge = document.createElement("span");
this.badge.classList.add("badge", "red");
this.badge.textContent = unseenCount.toString();
this.appendChild(this.badge);
this.classList.add("has-news");
}
}
}
customElements.define("th-new", New, { extends: "a" });

35
static/js/settings.js Normal file
View file

@ -0,0 +1,35 @@
const settingsKey = "treehouse.settings";
const settings = JSON.parse(localStorage.getItem(settingsKey)) || {};
const defaultSettingValues = {
showNewPostIndicator: true,
};
function saveSettings() {
localStorage.setItem(settingsKey, JSON.stringify(settings));
}
export function getSettingValue(setting) {
return settings[setting] ?? defaultSettingValues[setting];
}
class SettingCheckbox extends HTMLInputElement {
connectedCallback() {
this.checked = getSettingValue(this.id);
this.addEventListener("change", () => {
settings[this.id] = this.checked;
saveSettings();
});
}
}
customElements.define("th-setting-checkbox", SettingCheckbox, { extends: "input" });
class Settings extends HTMLElement {
connectedCallback() {
this.style.display = "block";
}
}
customElements.define("th-settings", Settings, { extends: "section" });

View file

@ -1,5 +1,5 @@
// Detect if we can have crucial functionality (ie. custom elements call constructors).
// This doesn't seem to happen in Epiphany, and possibly also other Webkit-based browsers.
// This doesn't seem to happen in Epiphany, and also other Webkit-based browsers.
let works = false;
class WebkitMoment extends HTMLLIElement {
constructor() {

View file

@ -17,12 +17,11 @@ function branchIsOpen(branchID) {
return branchState[branchID];
}
class Branch extends HTMLLIElement {
export class Branch extends HTMLLIElement {
static branchesByNamedID = new Map();
static onAdded = [];
constructor() {
super();
connectedCallback() {
this.isLeaf = this.classList.contains("leaf");
this.details = this.childNodes[0];
@ -48,16 +47,20 @@ class Branch extends HTMLLIElement {
});
}
let namedID = this.id.split(':')[1];
Branch.branchesByNamedID.set(namedID, this);
this.namedID = this.id.split(':')[1];
Branch.branchesByNamedID.set(this.namedID, this);
if (ulid.isCanonicalUlid(namedID)) {
let timestamp = ulid.getTimestamp(namedID);
if (ulid.isCanonicalUlid(this.namedID)) {
let timestamp = ulid.getTimestamp(this.namedID);
let date = document.createElement("span");
date.classList.add("branch-date");
date.innerText = timestamp.toLocaleDateString();
this.buttonBar.insertBefore(date, this.buttonBar.firstChild);
}
for (let callback of Branch.onAdded) {
callback(this);
}
}
}
@ -68,8 +71,8 @@ customElements.define("th-b", Branch, { extends: "li" });
class LinkedBranch extends Branch {
static byLink = new Map();
constructor() {
super();
connectedCallback() {
super.connectedCallback();
this.linkedTree = this.getAttribute("data-th-link");
LinkedBranch.byLink.set(this.linkedTree, this);