avatar support next to messages x2
All checks were successful
Build Org Website / build (push) Successful in 56s
All checks were successful
Build Org Website / build (push) Successful in 56s
This commit is contained in:
@@ -27,6 +27,44 @@
|
|||||||
const hour = now.getHours();
|
const hour = now.getHours();
|
||||||
const path = window.location.pathname;
|
const path = window.location.pathname;
|
||||||
const state = readState();
|
const state = readState();
|
||||||
|
const CHARACTER_AVATARS = {
|
||||||
|
"lima": {
|
||||||
|
avatar: "/assets/avatars/lima.jpg",
|
||||||
|
fallback: "/assets/avatars/z.jpeg",
|
||||||
|
aliases: ["lima"],
|
||||||
|
glow: "#f2c58b"
|
||||||
|
},
|
||||||
|
"aphy": {
|
||||||
|
avatar: "/assets/avatars/aphy.jpeg",
|
||||||
|
fallback: "/assets/avatars/z.jpeg",
|
||||||
|
aliases: ["aphy"],
|
||||||
|
glow: "#9dd3a6"
|
||||||
|
},
|
||||||
|
"sensei chi": {
|
||||||
|
avatar: "/assets/avatars/sensei-chi.jpeg",
|
||||||
|
fallback: "/assets/avatars/z.jpeg",
|
||||||
|
aliases: ["sensei chi", "sensei"],
|
||||||
|
glow: "#9ccddd"
|
||||||
|
},
|
||||||
|
"young z": {
|
||||||
|
avatar: "/assets/avatars/young-z.jpeg",
|
||||||
|
fallback: "/assets/avatars/z.jpeg",
|
||||||
|
aliases: ["young z", "young"],
|
||||||
|
glow: "#f0b85c"
|
||||||
|
},
|
||||||
|
"future z": {
|
||||||
|
avatar: "/assets/avatars/future-z.jpeg",
|
||||||
|
fallback: "/assets/avatars/z.jpeg",
|
||||||
|
aliases: ["future z", "future"],
|
||||||
|
glow: "#c2a4ee"
|
||||||
|
},
|
||||||
|
"z": {
|
||||||
|
avatar: "/assets/avatars/z.jpeg",
|
||||||
|
fallback: "/assets/avatars/z.jpeg",
|
||||||
|
aliases: ["z", "zaine"],
|
||||||
|
glow: "#ead68e"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// EDITABLE CONTENT
|
// EDITABLE CONTENT
|
||||||
@@ -474,6 +512,41 @@
|
|||||||
// UI HELPERS
|
// UI HELPERS
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
|
|
||||||
|
function characterForMessage(message) {
|
||||||
|
const text = String(message || "").toLowerCase();
|
||||||
|
return Object.entries(CHARACTER_AVATARS).find(([, config]) => {
|
||||||
|
return (config.aliases || []).some((alias) => {
|
||||||
|
const escaped = alias.toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||||
|
return new RegExp(`(^|[^a-z0-9-])${escaped}([^a-z0-9-]|$)`).test(text);
|
||||||
|
});
|
||||||
|
})?.[0] || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function avatarMarkup(character) {
|
||||||
|
const config = CHARACTER_AVATARS[character];
|
||||||
|
if (!config) return "";
|
||||||
|
return `<img class="hidden-message-avatar" src="${escapeHtml(config.avatar)}" alt="" loading="lazy" style="--hidden-avatar-glow:${escapeHtml(config.glow)}" onerror="this.onerror=null;this.src='${escapeHtml(config.fallback)}'">`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hiddenMessageMarkup(message) {
|
||||||
|
const character = characterForMessage(message);
|
||||||
|
return character
|
||||||
|
? `${avatarMarkup(character)}<span class="hidden-message-text">${escapeHtml(message)}</span>`
|
||||||
|
: `<span class="hidden-message-text">${escapeHtml(message)}</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setHiddenMessage(el, message) {
|
||||||
|
const character = characterForMessage(message);
|
||||||
|
el.classList.toggle("has-hidden-avatar", Boolean(character));
|
||||||
|
if (character) {
|
||||||
|
el.dataset.hiddenCharacter = character;
|
||||||
|
el.innerHTML = hiddenMessageMarkup(message);
|
||||||
|
} else {
|
||||||
|
delete el.dataset.hiddenCharacter;
|
||||||
|
el.textContent = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function toast(message, duration) {
|
function toast(message, duration) {
|
||||||
let el = document.querySelector(".hidden-toast");
|
let el = document.querySelector(".hidden-toast");
|
||||||
if (!el) {
|
if (!el) {
|
||||||
@@ -482,7 +555,7 @@
|
|||||||
el.setAttribute("role", "status");
|
el.setAttribute("role", "status");
|
||||||
document.body.appendChild(el);
|
document.body.appendChild(el);
|
||||||
}
|
}
|
||||||
el.textContent = message;
|
setHiddenMessage(el, message);
|
||||||
el.classList.add("is-visible");
|
el.classList.add("is-visible");
|
||||||
window.clearTimeout(el._timer);
|
window.clearTimeout(el._timer);
|
||||||
el._timer = window.setTimeout(() => el.classList.remove("is-visible"), duration || 5600);
|
el._timer = window.setTimeout(() => el.classList.remove("is-visible"), duration || 5600);
|
||||||
@@ -542,17 +615,17 @@
|
|||||||
const note = document.createElement("p");
|
const note = document.createElement("p");
|
||||||
note.className = "hidden-footer-note";
|
note.className = "hidden-footer-note";
|
||||||
const base = pick(details, "footer");
|
const base = pick(details, "footer");
|
||||||
note.textContent = memory.visits > 4 ? `${base} You have passed through ${memory.visits} times.` : base;
|
setHiddenMessage(note, memory.visits > 4 ? `${base} You have passed through ${memory.visits} times.` : base);
|
||||||
footer.appendChild(note);
|
footer.appendChild(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addHomepageGreeting(memory) {
|
function addHomepageGreeting(memory) {
|
||||||
const target = document.querySelector("#db-greeting");
|
const target = document.querySelector("#db-greeting");
|
||||||
if (!target) return;
|
if (!target) return;
|
||||||
target.textContent = pick(greetings, `greeting-${memory.visits}`);
|
setHiddenMessage(target, pick(greetings, `greeting-${memory.visits}`));
|
||||||
const extra = document.createElement("p");
|
const extra = document.createElement("p");
|
||||||
extra.className = "hidden-greeting";
|
extra.className = "hidden-greeting";
|
||||||
extra.textContent = memory.visits > 1 ? "aphy remembers the shape of your return. lima makes it feel less strange." : "First visits count as tiny ceremonies.";
|
setHiddenMessage(extra, memory.visits > 1 ? "aphy remembers the shape of your return. lima makes it feel less strange." : "First visits count as tiny ceremonies.");
|
||||||
target.closest("div")?.appendChild(extra);
|
target.closest("div")?.appendChild(extra);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -665,7 +738,8 @@
|
|||||||
function showDriftNote(text, art) {
|
function showDriftNote(text, art) {
|
||||||
const panel = document.createElement("aside");
|
const panel = document.createElement("aside");
|
||||||
panel.className = "hidden-drift-note";
|
panel.className = "hidden-drift-note";
|
||||||
panel.innerHTML = `<div>${escapeHtml(text)}</div><pre>${escapeHtml(art)}</pre><button type="button">Close</button>`;
|
const character = characterForMessage(text);
|
||||||
|
panel.innerHTML = `<div class="hidden-drift-message${character ? " has-hidden-avatar" : ""}">${hiddenMessageMarkup(text)}</div><pre>${escapeHtml(art)}</pre><button type="button">Close</button>`;
|
||||||
panel.querySelector("button").addEventListener("click", () => panel.remove());
|
panel.querySelector("button").addEventListener("click", () => panel.remove());
|
||||||
document.body.appendChild(panel);
|
document.body.appendChild(panel);
|
||||||
}
|
}
|
||||||
@@ -813,7 +887,7 @@
|
|||||||
if (comments && !comments.querySelector(".hidden-guestbook-line")) {
|
if (comments && !comments.querySelector(".hidden-guestbook-line")) {
|
||||||
const line = document.createElement("p");
|
const line = document.createElement("p");
|
||||||
line.className = "hidden-guestbook-line";
|
line.className = "hidden-guestbook-line";
|
||||||
line.textContent = pick(lore.fakeUsers, "comment-lore");
|
setHiddenMessage(line, pick(lore.fakeUsers, "comment-lore"));
|
||||||
comments.appendChild(line);
|
comments.appendChild(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -886,7 +960,8 @@
|
|||||||
const visits = readState().layerVisits || {};
|
const visits = readState().layerVisits || {};
|
||||||
target.innerHTML = familyLayers.map((line, layer) => {
|
target.innerHTML = familyLayers.map((line, layer) => {
|
||||||
const count = visits[layer] || 0;
|
const count = visits[layer] || 0;
|
||||||
return `<li><strong>${escapeHtml(line)}</strong><br><span>local encounters: ${count}</span></li>`;
|
const character = characterForMessage(line);
|
||||||
|
return `<li class="${character ? "hidden-layer-message" : ""}"><strong>${hiddenMessageMarkup(line)}</strong><br><span>local encounters: ${count}</span></li>`;
|
||||||
}).join("");
|
}).join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -910,7 +985,7 @@
|
|||||||
seconds += 1;
|
seconds += 1;
|
||||||
count.textContent = String(seconds);
|
count.textContent = String(seconds);
|
||||||
if ([30, 90, 180].includes(seconds)) {
|
if ([30, 90, 180].includes(seconds)) {
|
||||||
target.textContent = seconds === 30 ? "lima's note becomes easier to read." : seconds === 90 ? "sensei chi nods once." : "future z says this quiet was not wasted.";
|
setHiddenMessage(target, seconds === 30 ? "lima's note becomes easier to read." : seconds === 90 ? "sensei chi nods once." : "future z says this quiet was not wasted.");
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
@@ -933,7 +1008,7 @@
|
|||||||
if (event.key !== "Enter") return;
|
if (event.key !== "Enter") return;
|
||||||
const value = input.value.trim().toLowerCase();
|
const value = input.value.trim().toLowerCase();
|
||||||
const line = document.createElement("p");
|
const line = document.createElement("p");
|
||||||
line.textContent = `> ${value}\n${commands[value] || "aphy: unknown command. sensei chi: not all unknowns are errors."}`;
|
setHiddenMessage(line, `> ${value}\n${commands[value] || "aphy: unknown command. sensei chi: not all unknowns are errors."}`);
|
||||||
log.appendChild(line);
|
log.appendChild(line);
|
||||||
input.value = "";
|
input.value = "";
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -50,6 +50,53 @@
|
|||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.has-hidden-avatar {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.55rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden-toast.has-hidden-avatar,
|
||||||
|
.hidden-drift-message.has-hidden-avatar {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden-footer-note.has-hidden-avatar,
|
||||||
|
.hidden-greeting.has-hidden-avatar,
|
||||||
|
.hidden-guestbook-line.has-hidden-avatar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden-message-avatar {
|
||||||
|
width: 2.1rem;
|
||||||
|
height: 2.1rem;
|
||||||
|
flex: 0 0 2.1rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
border: 1px solid color-mix(in oklab, var(--hidden-avatar-glow, var(--accent)) 62%, var(--border));
|
||||||
|
box-shadow: 0 0 18px color-mix(in oklab, var(--hidden-avatar-glow, var(--accent)) 34%, transparent);
|
||||||
|
background: color-mix(in oklab, var(--surface) 82%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden-message-text {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden-layer-message strong {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.55rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden-terminal-log .has-hidden-avatar {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden-terminal-log .hidden-message-avatar {
|
||||||
|
margin-top: 0.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.hidden-corner-object {
|
.hidden-corner-object {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0.65rem;
|
left: 0.65rem;
|
||||||
|
|||||||
@@ -150,12 +150,12 @@ CHARACTER_REGISTRY = {
|
|||||||
"aliases": ["Young Z", "young z", "young-z", "young_z", "young"],
|
"aliases": ["Young Z", "young z", "young-z", "young_z", "young"],
|
||||||
"territoryColor": "#d8a95a",
|
"territoryColor": "#d8a95a",
|
||||||
"glow": "#f0b85c",
|
"glow": "#f0b85c",
|
||||||
"avatar": "/assets/avatars/young-z.jpeg",
|
"avatar": "https://zainezq.com/assets/avatars/young-z.jpeg",
|
||||||
"fallbackAvatar": "/assets/avatars/z.jpeg",
|
"fallbackAvatar": "https://zainezq.com/assets/avatars/z.jpeg",
|
||||||
"expressions": {
|
"expressions": {
|
||||||
"default": "/assets/avatars/young-z.jpeg",
|
"default": "https://zainezq.com/assets/avatars/young-z.jpeg",
|
||||||
"nostalgic": "/assets/avatars/young-z.jpeg",
|
"nostalgic": "https://zainezq.com/assets/avatars/young-z.jpeg",
|
||||||
"playful": "/assets/avatars/young-z.jpeg",
|
"playful": "https://zainezq.com/assets/avatars/young-z.jpeg",
|
||||||
},
|
},
|
||||||
"sizes": {"tiny": 18, "medium": 42, "close": 56, "focus": 82},
|
"sizes": {"tiny": 18, "medium": 42, "close": 56, "focus": 82},
|
||||||
"observatory": {"territory": "nostalgic/playful memories", "anchor": {"x": 0.23, "y": 0.7}, "shimmer": "soft"},
|
"observatory": {"territory": "nostalgic/playful memories", "anchor": {"x": 0.23, "y": 0.7}, "shimmer": "soft"},
|
||||||
@@ -172,9 +172,9 @@ CHARACTER_REGISTRY = {
|
|||||||
"aliases": ["Z", "z", "zaine"],
|
"aliases": ["Z", "z", "zaine"],
|
||||||
"territoryColor": "#d6c38a",
|
"territoryColor": "#d6c38a",
|
||||||
"glow": "#ead68e",
|
"glow": "#ead68e",
|
||||||
"avatar": "/assets/avatars/z.jpeg",
|
"avatar": "https://zainezq.com/assets/avatars/z.jpeg",
|
||||||
"fallbackAvatar": "/assets/avatars/z.jpeg",
|
"fallbackAvatar": "https://zainezq.com/assets/avatars/z.jpeg",
|
||||||
"expressions": {"default": "/assets/avatars/z.jpeg", "calm": "/assets/avatars/z.jpeg"},
|
"expressions": {"default": "https://zainezq.com/assets/avatars/z.jpeg", "calm": "https://zainezq.com/assets/avatars/z.jpeg"},
|
||||||
"sizes": {"tiny": 18, "medium": 42, "close": 56, "focus": 82},
|
"sizes": {"tiny": 18, "medium": 42, "close": 56, "focus": 82},
|
||||||
"observatory": {"territory": "self/archive memories", "anchor": {"x": 0.5, "y": 0.52}, "shimmer": "steady"},
|
"observatory": {"territory": "self/archive memories", "anchor": {"x": 0.5, "y": 0.52}, "shimmer": "steady"},
|
||||||
"presenceTones": ["warm", "soft", "hopeful"],
|
"presenceTones": ["warm", "soft", "hopeful"],
|
||||||
@@ -190,12 +190,12 @@ CHARACTER_REGISTRY = {
|
|||||||
"aliases": ["Aphy", "aphy", "aphy_bot", "aphy bot"],
|
"aliases": ["Aphy", "aphy", "aphy_bot", "aphy bot"],
|
||||||
"territoryColor": "#7fb089",
|
"territoryColor": "#7fb089",
|
||||||
"glow": "#9dd3a6",
|
"glow": "#9dd3a6",
|
||||||
"avatar": "/assets/avatars/aphy.jpeg",
|
"avatar": "https://zainezq.com/assets/avatars/aphy.jpeg",
|
||||||
"fallbackAvatar": "/assets/avatars/z.jpeg",
|
"fallbackAvatar": "https://zainezq.com/assets/avatars/z.jpeg",
|
||||||
"expressions": {
|
"expressions": {
|
||||||
"default": "/assets/avatars/aphy.jpeg",
|
"default": "https://zainezq.com/assets/avatars/aphy.jpeg",
|
||||||
"system": "/assets/avatars/aphy.jpeg",
|
"system": "https://zainezq.com/assets/avatars/aphy.jpeg",
|
||||||
"amused": "/assets/avatars/aphy.jpeg",
|
"amused": "https://zainezq.com/assets/avatars/aphy.jpeg",
|
||||||
},
|
},
|
||||||
"sizes": {"tiny": 18, "medium": 42, "close": 56, "focus": 82},
|
"sizes": {"tiny": 18, "medium": 42, "close": 56, "focus": 82},
|
||||||
"observatory": {"territory": "system/symbolic areas", "anchor": {"x": 0.77, "y": 0.35}, "shimmer": "diagnostic"},
|
"observatory": {"territory": "system/symbolic areas", "anchor": {"x": 0.77, "y": 0.35}, "shimmer": "diagnostic"},
|
||||||
@@ -212,13 +212,13 @@ CHARACTER_REGISTRY = {
|
|||||||
"aliases": ["Lima", "lima"],
|
"aliases": ["Lima", "lima"],
|
||||||
"territoryColor": "#d06b78",
|
"territoryColor": "#d06b78",
|
||||||
"glow": "#f2c58b",
|
"glow": "#f2c58b",
|
||||||
"avatar": "/assets/avatars/lima.jpg",
|
"avatar": "https://zainezq.com/assets/avatars/lima.jpg",
|
||||||
"fallbackAvatar": "/assets/avatars/z.jpeg",
|
"fallbackAvatar": "https://zainezq.com/assets/avatars/z.jpeg",
|
||||||
"expressions": {
|
"expressions": {
|
||||||
"default": "/assets/avatars/lima.jpg",
|
"default": "https://zainezq.com/assets/avatars/lima.jpg",
|
||||||
"calm": "/assets/avatars/lima.jpg",
|
"calm": "https://zainezq.com/assets/avatars/lima.jpg",
|
||||||
"warm": "/assets/avatars/lima.jpg",
|
"warm": "https://zainezq.com/assets/avatars/lima.jpg",
|
||||||
"protective": "/assets/avatars/lima.jpg",
|
"protective": "https://zainezq.com/assets/avatars/lima.jpg",
|
||||||
},
|
},
|
||||||
"sizes": {"tiny": 18, "medium": 42, "close": 56, "focus": 82},
|
"sizes": {"tiny": 18, "medium": 42, "close": 56, "focus": 82},
|
||||||
"observatory": {"territory": "warm/protective arcs", "anchor": {"x": 0.29, "y": 0.36}, "shimmer": "warm"},
|
"observatory": {"territory": "warm/protective arcs", "anchor": {"x": 0.29, "y": 0.36}, "shimmer": "warm"},
|
||||||
@@ -235,12 +235,12 @@ CHARACTER_REGISTRY = {
|
|||||||
"aliases": ["Sensei Chi", "sensei chi", "sensei-chi", "sensei_chi", "sensei"],
|
"aliases": ["Sensei Chi", "sensei chi", "sensei-chi", "sensei_chi", "sensei"],
|
||||||
"territoryColor": "#75a9bd",
|
"territoryColor": "#75a9bd",
|
||||||
"glow": "#9ccddd",
|
"glow": "#9ccddd",
|
||||||
"avatar": "/assets/avatars/sensei-chi.jpeg",
|
"avatar": "https://zainezq.com/assets/avatars/sensei-chi.jpeg",
|
||||||
"fallbackAvatar": "/assets/avatars/z.jpeg",
|
"fallbackAvatar": "https://zainezq.com/assets/avatars/z.jpeg",
|
||||||
"expressions": {
|
"expressions": {
|
||||||
"default": "/assets/avatars/sensei-chi.jpeg",
|
"default": "https://zainezq.com/assets/avatars/sensei-chi.jpeg",
|
||||||
"reflective": "/assets/avatars/sensei-chi.jpeg",
|
"reflective": "https://zainezq.com/assets/avatars/sensei-chi.jpeg",
|
||||||
"wise": "/assets/avatars/sensei-chi.jpeg",
|
"wise": "https://zainezq.com/assets/avatars/sensei-chi.jpeg",
|
||||||
},
|
},
|
||||||
"sizes": {"tiny": 18, "medium": 42, "close": 56, "focus": 82},
|
"sizes": {"tiny": 18, "medium": 42, "close": 56, "focus": 82},
|
||||||
"observatory": {"territory": "reflective areas", "anchor": {"x": 0.68, "y": 0.68}, "shimmer": "quiet"},
|
"observatory": {"territory": "reflective areas", "anchor": {"x": 0.68, "y": 0.68}, "shimmer": "quiet"},
|
||||||
@@ -257,12 +257,12 @@ CHARACTER_REGISTRY = {
|
|||||||
"aliases": ["Future Z", "future z", "future-z", "future_z", "future"],
|
"aliases": ["Future Z", "future z", "future-z", "future_z", "future"],
|
||||||
"territoryColor": "#a58ac9",
|
"territoryColor": "#a58ac9",
|
||||||
"glow": "#c2a4ee",
|
"glow": "#c2a4ee",
|
||||||
"avatar": "/assets/avatars/future-z.jpeg",
|
"avatar": "https://zainezq.com/assets/avatars/future-z.jpeg",
|
||||||
"fallbackAvatar": "/assets/avatars/z.jpeg",
|
"fallbackAvatar": "https://zainezq.com/assets/avatars/z.jpeg",
|
||||||
"expressions": {
|
"expressions": {
|
||||||
"default": "/assets/avatars/future-z.jpeg",
|
"default": "https://zainezq.com/assets/avatars/future-z.jpeg",
|
||||||
"temporal": "/assets/avatars/future-z.jpeg",
|
"temporal": "https://zainezq.com/assets/avatars/future-z.jpeg",
|
||||||
"reassuring": "/assets/avatars/future-z.jpeg",
|
"reassuring": "https://zainezq.com/assets/avatars/future-z.jpeg",
|
||||||
},
|
},
|
||||||
"sizes": {"tiny": 18, "medium": 42, "close": 56, "focus": 82},
|
"sizes": {"tiny": 18, "medium": 42, "close": 56, "focus": 82},
|
||||||
"observatory": {"territory": "temporal regions", "anchor": {"x": 0.73, "y": 0.18}, "shimmer": "temporal"},
|
"observatory": {"territory": "temporal regions", "anchor": {"x": 0.73, "y": 0.18}, "shimmer": "temporal"},
|
||||||
|
|||||||
Reference in New Issue
Block a user