nemesis: Persona poses on by default; Safari 14 polyfills (Array.at/findLast, Object.hasOwn, structuredClone) and -webkit-backdrop-filter

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Eureka Self 2026-11-10 13:51:26 +00:00
commit 0fe41efb9b
5 changed files with 78 additions and 1 deletions

View file

@ -48,6 +48,7 @@ globalStyle(within(scene), {
// Blur with a light tint toward the sky, like the chat bubbles; never an opaque slab (PLATE_TINT).
backgroundColor: [fill, `color-mix(in srgb, ${fill} ${PLATE_TINT * 100}%, transparent)`],
backdropFilter: 'blur(12px)',
WebkitBackdropFilter: 'blur(12px)',
color: text,
// Themed ink was chosen for the clear shell; inside the plate every token reads the plate's.
vars: {

View file

@ -83,6 +83,7 @@ globalStyle(`${scene} ${AuthCard}`, {
`color-mix(in srgb, var(--sky-bubble, #0d1a26) ${PLATE_TINT * 100}%, transparent)`,
],
backdropFilter: 'blur(12px)',
WebkitBackdropFilter: 'blur(12px)',
color: 'var(--sky-bubble-text, #b7c7d9)',
borderRadius: config.radii.R500,
border: 'none',
@ -99,6 +100,7 @@ globalStyle(`${scene} ${AuthHeader}`, {
globalStyle(`${scene} #root header.${AuthHeader}`, {
backgroundColor: 'transparent',
backdropFilter: 'none',
WebkitBackdropFilter: 'none',
});
globalStyle(`${scene} ${AuthCardContent}`, {
paddingTop: config.space.S500,
@ -120,6 +122,7 @@ globalStyle(`${scene} ${AuthFooter}`, {
paddingBottom: config.space.S500,
backgroundColor: ['var(--sky-bubble, #0d1a26)', tint],
backdropFilter: 'blur(12px)',
WebkitBackdropFilter: 'blur(12px)',
maskImage: `${FADE_Y}, ${FADE_X}`,
maskComposite: 'intersect',
color: 'var(--sky-bubble-text, #b7c7d9)',

View file

@ -85,7 +85,7 @@ const defaultSettings: Settings = {
encUrlPreview: false,
showHiddenEvents: false,
legacyUsernameColor: false,
poseBubbles: false,
poseBubbles: true,
showNotifications: true,
isNotificationSounds: true,

View file

@ -1,4 +1,5 @@
/* eslint-disable import/first */
import './polyfills';
import './preview-demo/seed';
import React from 'react';
import { createRoot } from 'react-dom/client';

72
src/polyfills.ts Normal file
View file

@ -0,0 +1,72 @@
/* eslint-disable no-extend-native, func-names */
// Safari 14 (iPadOS 14) lacks these; the bundle (ours and matrix-js-sdk) calls them at runtime. Safari 15.4 has all.
// Loaded first by src/index.tsx. Each is installed only when missing.
function at<T>(this: ArrayLike<T>, n: number): T | undefined {
const len = this.length;
const i = Math.trunc(n) || 0;
const k = i < 0 ? len + i : i;
return k < 0 || k >= len ? undefined : this[k];
}
if (!Array.prototype.at) Object.defineProperty(Array.prototype, 'at', { value: at, writable: true, configurable: true });
if (!String.prototype.at)
Object.defineProperty(String.prototype, 'at', { value: at, writable: true, configurable: true });
if (!(Array.prototype as unknown as Record<string, unknown>).findLast)
Object.defineProperty(Array.prototype, 'findLast', {
value: function <T>(this: T[], fn: (v: T, i: number, a: T[]) => unknown, thisArg?: unknown) {
for (let i = this.length - 1; i >= 0; i -= 1) if (fn.call(thisArg, this[i], i, this)) return this[i];
return undefined;
},
writable: true,
configurable: true,
});
if (!(Array.prototype as unknown as Record<string, unknown>).findLastIndex)
Object.defineProperty(Array.prototype, 'findLastIndex', {
value: function <T>(this: T[], fn: (v: T, i: number, a: T[]) => unknown, thisArg?: unknown) {
for (let i = this.length - 1; i >= 0; i -= 1) if (fn.call(thisArg, this[i], i, this)) return i;
return -1;
},
writable: true,
configurable: true,
});
if (!(Object as unknown as Record<string, unknown>).hasOwn)
Object.defineProperty(Object, 'hasOwn', {
value: (o: object, k: PropertyKey) => Object.prototype.hasOwnProperty.call(o, k),
writable: true,
configurable: true,
});
// Structured clone for the data the client clones: plain objects, arrays, Map, Set, Date, RegExp, typed arrays, with cycles.
if (typeof (globalThis as { structuredClone?: unknown }).structuredClone !== 'function') {
const clone = (v: unknown, seen: Map<unknown, unknown>): unknown => {
if (v === null || typeof v !== 'object') return v;
if (seen.has(v)) return seen.get(v);
if (v instanceof Date) return new Date(v.getTime());
if (v instanceof RegExp) return new RegExp(v.source, v.flags);
if (ArrayBuffer.isView(v)) return (v as unknown as { slice: () => unknown }).slice();
if (v instanceof ArrayBuffer) return v.slice(0);
if (v instanceof Map) {
const m = new Map();
seen.set(v, m);
v.forEach((val, key) => m.set(clone(key, seen), clone(val, seen)));
return m;
}
if (v instanceof Set) {
const s = new Set();
seen.set(v, s);
v.forEach((val) => s.add(clone(val, seen)));
return s;
}
const out: Record<string, unknown> | unknown[] = Array.isArray(v) ? [] : {};
seen.set(v, out);
Object.keys(v).forEach((k) => {
(out as Record<string, unknown>)[k] = clone((v as Record<string, unknown>)[k], seen);
});
return out;
};
(globalThis as { structuredClone?: unknown }).structuredClone = (v: unknown) => clone(v, new Map());
}
export {};