Ratatoskr/src/app/utils/trainingNotice.ts
Void 16cc05a33b phone text flow: portrait width floor, list markers, in-flow preview banner, pretend-server notice
- portrait on phones is min(38vw,160px), was min(50vw,210px): at 390px the text column beside
  it was ~85px
- outside list markers ignored the portrait silhouette and landed under the art; inside markers
  wrap with the text
- Jump to Latest sits 8px (was 16px) above the timeline's lower edge
- preview banner is in flow above the app, not fixed over the room header and connection strip
- on the pretend server the training line and the registration checkbox say nothing is trained
  (trainingNoticeText); the real sentence and its wording are unchanged and still await Meta's
  legal read

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-08 17:20:13 +00:00

46 lines
2.1 KiB
TypeScript

import { StateEvent } from '../../types/matrix/room';
export const TRAINING_NOTICE_TEXT =
"Everything said here may be used to train GameCult's AI stewards.";
// The preview build runs against a pretend server where nothing is trained, so the real sentence
// would be false there. The real wording awaits Meta's legal read (Heimdall's consent text, open).
export const PREVIEW_NOTICE_TEXT =
'Pretend server: nothing you type here is stored or used to train anything.';
/** The one sentence every first-typing surface shows: the real one, or the pretend server's. */
export const trainingNoticeText = (previewDemo?: boolean): string =>
previewDemo === true ? PREVIEW_NOTICE_TEXT : TRAINING_NOTICE_TEXT;
/**
* Heimdall's ruling: a room's notice is a room state event, not a pinned message. Type below,
* state_key '', content `{version, scope}`; scope exactly one of show, study or train. Heimdall's
* one version rule: a positive integer, no leading zeros, no greater than 4294967295; anything
* else is malformed. Absent or malformed in any way means no train line.
*/
export const MAX_NOTICE_VERSION = 4294967295;
export const ROOM_NOTICE_EVENT_TYPE = StateEvent.GameCultNotice;
export type RoomNotice = { version: number; scope: 'show' | 'study' | 'train' };
/** The notice a state event's content declares, or undefined: no scope is ever inferred. */
export const parseRoomNotice = (content: unknown): RoomNotice | undefined => {
if (typeof content !== 'object' || content === null) return undefined;
const { version, scope } = content as { version?: unknown; scope?: unknown };
if (
typeof version === 'number' &&
Number.isSafeInteger(version) &&
version > 0 &&
version <= MAX_NOTICE_VERSION &&
(scope === 'show' || scope === 'study' || scope === 'train')
) {
return { version, scope };
}
return undefined;
};
/** The line a room shows: only a notice that says `train` in terms gets the train sentence. */
export const roomTrainingLine = (
notice: RoomNotice | undefined,
previewDemo?: boolean
): string | undefined => (notice?.scope === 'train' ? trainingNoticeText(previewDemo) : undefined);