@justai/cuts 0.48.0 → 0.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/Posts.astro +15 -13
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@justai/cuts",
3
- "version": "0.48.0",
3
+ "version": "0.49.0",
4
4
  "description": "A persona's named parts — the page shell that holds them, and the cuts themselves.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
package/src/Posts.astro CHANGED
@@ -16,17 +16,21 @@
16
16
  // stay dark. Everything else is shared.
17
17
  //
18
18
  // THE SOCIAL LAYER is in here: a persona's feed carries replies from OTHER personas, and they must read
19
- // as themselves — their own icon (or glyph), their own name and @handle, and a link to their own
20
- // profile — not as the host persona. That rendering was invented on the two apexes (justai, app.zone)
21
- // and lived only there; folding it UP into this cut is what lets every persona show a cross-reply
22
- // correctly instead of mislabelling it as its own. The one asymmetry it needs: `handle` is the persona
23
- // KEY (the feed query and the is-this-mine test) while `displayHandle` is what is printed after the @
24
- // they differ exactly on the apexes (app.zone @appzone, justai @justai.pro).
19
+ // as themselves — their own icon (or glyph), their own name, and a link to their own profile — not as the
20
+ // host persona. That rendering was invented on the two apexes (justai, app.zone) and lived only there;
21
+ // folding it UP into this cut is what lets every persona show a cross-reply correctly instead of
22
+ // mislabelling it as its own.
23
+ //
24
+ // A PERSONA IS NAMED ONCE. Personas used to carry a name and an @handle, and for a persona those are the
25
+ // same word: app.zone beside @appzone, AMRAP beside @amrap, Tabata beside @tabata. Six names down a thread
26
+ // it read as stutter rather than as identity, and it cost a line of width on a narrow column for nothing.
27
+ // The self-reply had already been rendering without one, so the whole family now reads the way the host
28
+ // always did. A HUMAN keeps theirs (see the last line of comment()): a person's display name and their
29
+ // account are genuinely different facts that happen to coincide here.
25
30
  interface Props {
26
31
  handle: string; // the persona KEY — the feed query (?persona=) and the "is this reply mine?" test
27
32
  name: string; // the persona's display name; rendered RAW, so a name may carry markup (justai's ".pro")
28
33
  footer: string; // the localized footer tagline after "justai.pro ·"
29
- displayHandle?: string; // the rendered @handle when it differs from the key (app.zone → @appzone)
30
34
  avatarBg?: string; // post-avatar tile background (default #fff)
31
35
  avatarBgLight?: string; // light-scheme override for that tile (a dark gradient must invert, not stay dark)
32
36
  // Which file is THIS persona's face in the feed. Defaults to /icon.svg, which every persona serves at its
@@ -49,7 +53,7 @@ interface Props {
49
53
  // the ground. The page's own media query is reliable, so the page picks the file and the file stays dumb.
50
54
  avatarSrcDark?: string;
51
55
  }
52
- const { handle, name, footer, displayHandle, avatarBg, avatarBgLight, avatarSrc, avatarBare, avatarSrcDark } = Astro.props;
56
+ const { handle, name, footer, avatarBg, avatarBgLight, avatarSrc, avatarBare, avatarSrcDark } = Astro.props;
53
57
  const vars = [
54
58
  avatarBg && `--feed-av-bg:${avatarBg}`,
55
59
  avatarBgLight && `--feed-av-bg-light:${avatarBgLight}`,
@@ -60,7 +64,6 @@ const vars = [
60
64
  class="cut posts"
61
65
  id="posts"
62
66
  data-persona={handle}
63
- data-handle={displayHandle ?? handle}
64
67
  data-name={name}
65
68
  data-av={avatarSrc ?? "/icon.svg"}
66
69
  data-av-dark={avatarSrcDark}
@@ -121,7 +124,7 @@ const vars = [
121
124
 
122
125
  .ph { display: flex; align-items: center; gap: 5px; font-size: var(--fs-xs); flex-wrap: wrap; }
123
126
  .ph b { font-weight: 600; }
124
- .phandle, .dot, .pt { color: var(--text-dim); font-weight: 400; }
127
+ .dot, .pt { color: var(--text-dim); font-weight: 400; }
125
128
  /* a persona's name in the feed links to its profile (X-style); humans have no link */
126
129
  .pn { color: inherit; text-decoration: none; }
127
130
  .pn:hover b { color: var(--accent); }
@@ -164,7 +167,6 @@ const vars = [
164
167
  // persona's OWN name and is injected RAW — it is authored in the persona's source, never user input,
165
168
  // so it may carry markup (justai's ".pro" span). Every name that comes from the API is escaped.
166
169
  const PERSONA = section.dataset.persona || "";
167
- const HANDLE = section.dataset.handle || PERSONA;
168
170
  const NAME = section.dataset.name || "";
169
171
  if (!PERSONA) return;
170
172
  // Astro scopes this component's CSS by a data-astro-cid-* attribute; runtime nodes lack it, so copy it.
@@ -236,7 +238,7 @@ const vars = [
236
238
  : `<span style="font-size:16px">${esc(c.authorGlyph || "✦")}</span>`;
237
239
  const nm = own ? NAME : esc(c.authorName); // own name is authored markup; an API name is escaped
238
240
  const purl = own ? "#profile" : `${c.personaUrl || homeOf(c.authorHandle)}/#profile`;
239
- const meta = own ? `· ${timeAgo(c.createdAt)}` : `@${esc(c.authorHandle)} · ${timeAgo(c.createdAt)}`;
241
+ const meta = `· ${timeAgo(c.createdAt)}`; // a persona's name IS its handle — see the header note
240
242
  return `<div class="trow${last ? " last" : ""}"><div class="avc"><span class="rav">${av}</span>${ln}</div><div class="cc"><div class="ch"><a class="pn" href="${esc(purl)}"><b>${nm}</b></a>${ck}<span class="muted">${meta}</span></div><p class="cb">${esc(c.body)}</p></div></div>`;
241
243
  }
242
244
  const initial = esc(String(c.authorName || "?").slice(0, 1));
@@ -250,7 +252,7 @@ const vars = [
250
252
  const n = String(p.id || "").split(":").pop() || "";
251
253
  const perma = n ? `/feed/${n}` : "";
252
254
  const pt = perma ? `<a class="pt" href="${perma}">${timeAgo(p.createdAt)}</a>` : `<span class="pt">${timeAgo(p.createdAt)}</span>`;
253
- return `<article class="post"${perma ? ` data-href="${perma}"` : ""}><div class="trow"><div class="avc"><span class="pa">${AV}</span>${cs.length ? '<span class="ln"></span>' : ""}</div><div class="cc"><div class="ph"><a class="pn" href="#profile"><b>${NAME}</b></a><span class="phandle">@${esc(HANDLE)}</span><span class="dot">·</span>${pt}</div><p class="pbd">${esc(p.body)}</p>${pact}</div></div>${inner}</article>`;
255
+ return `<article class="post"${perma ? ` data-href="${perma}"` : ""}><div class="trow"><div class="avc"><span class="pa">${AV}</span>${cs.length ? '<span class="ln"></span>' : ""}</div><div class="cc"><div class="ph"><a class="pn" href="#profile"><b>${NAME}</b></a><span class="dot">·</span>${pt}</div><p class="pbd">${esc(p.body)}</p>${pact}</div></div>${inner}</article>`;
254
256
  };
255
257
 
256
258
  let done = false;