@miadi/stateloom-web 0.3.1 → 0.3.3

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 (51) hide show
  1. package/package.json +1 -1
  2. package/server/.next/BUILD_ID +1 -1
  3. package/server/.next/build-manifest.json +2 -2
  4. package/server/.next/server/app/_global-error.html +2 -2
  5. package/server/.next/server/app/_global-error.rsc +1 -1
  6. package/server/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  7. package/server/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  8. package/server/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  9. package/server/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  10. package/server/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  11. package/server/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  12. package/server/.next/server/app/_not-found.html +1 -1
  13. package/server/.next/server/app/_not-found.rsc +2 -2
  14. package/server/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  15. package/server/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  16. package/server/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  17. package/server/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  18. package/server/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  19. package/server/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  20. package/server/.next/server/app/api/docs/route.js.nft.json +1 -1
  21. package/server/.next/server/app/api/file/route.js.nft.json +1 -1
  22. package/server/.next/server/app/api/marks/route.js.nft.json +1 -1
  23. package/server/.next/server/app/api/rispec/route.js.nft.json +1 -1
  24. package/server/.next/server/app/api/watch/route.js.nft.json +1 -1
  25. package/server/.next/server/app/index.html +1 -1
  26. package/server/.next/server/app/index.rsc +3 -3
  27. package/server/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  28. package/server/.next/server/app/index.segments/_full.segment.rsc +3 -3
  29. package/server/.next/server/app/index.segments/_head.segment.rsc +1 -1
  30. package/server/.next/server/app/index.segments/_index.segment.rsc +2 -2
  31. package/server/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  32. package/server/.next/server/app/page.js.nft.json +1 -1
  33. package/server/.next/server/app/page_client-reference-manifest.js +1 -1
  34. package/server/.next/server/chunks/ssr/{[root-of-the-server]__9e661f75._.js → [root-of-the-server]__a593e8b6._.js} +1 -1
  35. package/server/.next/server/chunks/ssr/[root-of-the-server]__edbb995c._.js +6 -6
  36. package/server/.next/server/pages/404.html +1 -1
  37. package/server/.next/server/pages/500.html +2 -2
  38. package/server/.next/static/chunks/59a1ec89a1dc7e34.js +14 -0
  39. package/server/.next/static/chunks/{0d24f3e3dbdef25e.css → 8f45e56f40c207bf.css} +2 -2
  40. package/server/package-lock.json +2 -2
  41. package/server/package.json +1 -1
  42. package/server/src/app/globals.css +20 -0
  43. package/server/src/components/stage/StageLayer.tsx +84 -8
  44. package/server/src/components/stage/StageProvider.tsx +4 -1
  45. package/server/src/components/stage/useEpisodePresence.ts +71 -0
  46. package/server/stateloom-web.json +2 -2
  47. package/server/tsconfig.tsbuildinfo +1 -1
  48. package/server/.next/static/chunks/ec729c54327cc597.js +0 -14
  49. /package/server/.next/static/{pbn7-8jVWdRn8FLy4fHnU → CZ4wRF1efsHnxjkcKHITP}/_buildManifest.js +0 -0
  50. /package/server/.next/static/{pbn7-8jVWdRn8FLy4fHnU → CZ4wRF1efsHnxjkcKHITP}/_clientMiddlewareManifest.json +0 -0
  51. /package/server/.next/static/{pbn7-8jVWdRn8FLy4fHnU → CZ4wRF1efsHnxjkcKHITP}/_ssgManifest.js +0 -0
@@ -0,0 +1,71 @@
1
+ "use client";
2
+
3
+ /**
4
+ * Whether a Mia seat listens in the episode a drawing belongs to (Spec 83, Spec 84),
5
+ * for the line the mark cards show under what a person writes and reads.
6
+ *
7
+ * Read from the companion's thread through this designer's proxy
8
+ * (`/api/companion/thread?episode=`), the same presence the Talk dock shows: listening,
9
+ * answering, answered, away. Polled every 10 s while a mark card is open and the page is
10
+ * visible; what was last read is kept while the cards are closed, so a card opens with
11
+ * its line. Null when there is no episode, before the first answer, and when the
12
+ * companion does not answer.
13
+ */
14
+ import { useEffect, useState } from "react";
15
+ import type { CompanionPresence } from "@miadi/stateloom-react";
16
+
17
+ export type PresenceState = CompanionPresence["state"];
18
+
19
+ const EVERY_MS = 10_000;
20
+
21
+ export function useEpisodePresence(episode: string | null, active: boolean): PresenceState | null {
22
+ const [seen, setSeen] = useState<{ episode: string; state: PresenceState | null } | null>(null);
23
+
24
+ useEffect(() => {
25
+ if (!episode || !active) return;
26
+ let live = true;
27
+ const read = async (): Promise<void> => {
28
+ if (typeof document !== "undefined" && document.visibilityState !== "visible") return;
29
+ try {
30
+ const r = await fetch(`/api/companion/thread?episode=${encodeURIComponent(episode)}`, { cache: "no-store" });
31
+ const body = (await r.json()) as { success?: boolean; presence?: CompanionPresence | null };
32
+ if (live) setSeen({ episode, state: body.success ? (body.presence?.state ?? null) : null });
33
+ } catch {
34
+ if (live) setSeen({ episode, state: null });
35
+ }
36
+ };
37
+ void read();
38
+ const t = setInterval(() => void read(), EVERY_MS);
39
+ return () => {
40
+ live = false;
41
+ clearInterval(t);
42
+ };
43
+ }, [episode, active]);
44
+
45
+ return seen && seen.episode === episode ? seen.state : null;
46
+ }
47
+
48
+ /** "2026-10-19-episode-412-the-loom" → 412. */
49
+ export function episodeNumber(episode: string): number | null {
50
+ const m = episode.match(/-episode-(\d+)-/);
51
+ return m ? Number(m[1]) : null;
52
+ }
53
+
54
+ /** The line under the mark cards: who answers a mark left on a drawing of `episode`. */
55
+ export function presenceLine(state: PresenceState | null, episode: string | null): string | null {
56
+ if (!state || !episode) return null;
57
+ const n = episodeNumber(episode);
58
+ const where = n === null ? "this episode" : `episode ${n}`;
59
+ switch (state) {
60
+ case "listening":
61
+ return `Mia is listening in ${where}: she answers here`;
62
+ case "answering":
63
+ return "Mia is answering";
64
+ case "answered":
65
+ return `Mia has answered in ${where}: your mark waits until she listens again`;
66
+ case "away":
67
+ return `No seat is listening in ${where}: your mark waits until one does`;
68
+ default:
69
+ return null;
70
+ }
71
+ }
@@ -1,5 +1,5 @@
1
1
  {
2
- "package": "0.3.1",
3
- "designer": "0.3.1",
2
+ "package": "0.3.3",
3
+ "designer": "0.3.3",
4
4
  "next": "16.1.6"
5
5
  }