Compare commits
135 changed files with 403 additions and 2610 deletions
|
|
@ -47,10 +47,6 @@ handoff states which config differs and the installer decides. From Yggdrasil th
|
|||
not resolve: pass `LIVE_CURL_ARGS="--resolve chat.gamecult.org:443:127.0.0.1"`.
|
||||
The folder, with the three pins (`SHA256SUMS` sha256, `BUILD-INFO` sha256, lockfile sha256) and
|
||||
the node and npm versions, is what the install request names.
|
||||
Every build stamps its commit into `index.html` (`scripts/buildSha.js`): `<meta name="build-sha" content="<40-hex>">`,
|
||||
with `-dirty` appended when the tree had uncommitted changes and `unknown` when there was no git. Where git governs the tree it decides: an explicit `BUILD_SHA` naming a different commit than HEAD stamps `<sha>-mismatch`, a git failure stamps `unknown`. A full-sha `BUILD_SHA` stands only for a tree git does not govern (a source archive) or cannot read (unusable git, for example a dubious-ownership refusal). The handoff
|
||||
build refuses a dist whose stamp differs from the sha it was asked for, and prints the stamp in its block.
|
||||
To read it from anywhere: `curl -s https://chat.gamecult.org/ | grep -o 'build-sha" content="[^"]*'`.
|
||||
|
||||
Before handing off:
|
||||
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
// The commit a bundle was built from, stamped into its index.html as <meta name="build-sha">, so a built
|
||||
// folder says what it is without a build log: `grep -o 'build-sha" content="[^"]*' dist/index.html`.
|
||||
// Where git governs the tree (REPO_DIR is a repository root) git decides: HEAD, suffixed -dirty when the tree has
|
||||
// uncommitted changes, or `<BUILD_SHA>-mismatch` when an explicit BUILD_SHA names a different commit, so a stamp
|
||||
// never vouches for code it does not hold; a git failure there is 'unknown'. Where git does not govern (a source
|
||||
// archive), a full-sha BUILD_SHA stands, else 'unknown'.
|
||||
import { execFileSync } from 'child_process';
|
||||
import { dirname, resolve } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const REPO_DIR = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
||||
|
||||
// Vite writes vite.config.js.timestamp-*.mjs next to the config while it loads it; that file is the
|
||||
// build's own, not source, so an UNTRACKED one must not mark the tree dirty. A tracked file of that name,
|
||||
// or any other change, still does. Filtering status lines (not a pathspec) is what keeps it untracked-only.
|
||||
const VITE_TEMP = /^\?\? (?:.*\/)?vite\.config\.[a-z]+\.timestamp-\d+-[0-9a-f]+\.mjs$/;
|
||||
|
||||
export const gitIn =
|
||||
(cwd) =>
|
||||
(...args) =>
|
||||
execFileSync('git', args, { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
||||
|
||||
const FULL_SHA = /^[0-9a-f]{40}$/;
|
||||
|
||||
export const readBuildSha = (env = process.env, run = gitIn(REPO_DIR)) => {
|
||||
const fromEnv = (env.BUILD_SHA ?? '').trim();
|
||||
const explicit = FULL_SHA.test(fromEnv) ? fromEnv : null;
|
||||
// Git governs this tree only when REPO_DIR is its root: a source archive unpacked inside some other
|
||||
// repository has no git of its own, and that repository's HEAD says nothing about it.
|
||||
let governed;
|
||||
try {
|
||||
governed = run('rev-parse', '--show-prefix').trim() === '';
|
||||
} catch {
|
||||
governed = false;
|
||||
}
|
||||
if (!governed) return explicit ?? 'unknown';
|
||||
// Git governs and answers: from here a failure is 'unknown', never the bare explicit sha.
|
||||
try {
|
||||
const head = run('rev-parse', 'HEAD').trim();
|
||||
if (!FULL_SHA.test(head)) return 'unknown';
|
||||
if (explicit && explicit !== head) return `${explicit}-mismatch`;
|
||||
const dirty = run('status', '--porcelain', '-uall', '--', '.')
|
||||
.split('\n')
|
||||
.some((l) => l.trim() !== '' && !VITE_TEMP.test(l));
|
||||
return dirty ? `${head}-dirty` : head;
|
||||
} catch {
|
||||
return 'unknown';
|
||||
}
|
||||
};
|
||||
|
||||
export const buildShaPlugin = (sha = readBuildSha()) => ({
|
||||
name: 'ratatoskr-build-sha',
|
||||
transformIndexHtml: () => [
|
||||
{ tag: 'meta', attrs: { name: 'build-sha', content: sha }, injectTo: 'head-prepend' },
|
||||
],
|
||||
});
|
||||
|
|
@ -1,170 +0,0 @@
|
|||
import { execFileSync } from 'child_process';
|
||||
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'fs';
|
||||
import { tmpdir } from 'os';
|
||||
import { join } from 'path';
|
||||
import { afterEach, describe, expect, it } from 'vitest';
|
||||
import { buildShaPlugin, gitIn, readBuildSha } from './buildSha';
|
||||
|
||||
const SHA = 'b6b1d522f1c0a9d3e2b4c5d6e7f8091a2b3c4d5e';
|
||||
const gitAt =
|
||||
(head, status = '') =>
|
||||
(cmd, ...args) =>
|
||||
cmd === 'rev-parse' ? (args[0] === '--show-prefix' ? '\n' : `${head}\n`) : status;
|
||||
|
||||
describe('readBuildSha', () => {
|
||||
it('reads the checkout it is built from', () => {
|
||||
expect(readBuildSha({}, gitAt(SHA))).toBe(SHA);
|
||||
});
|
||||
it('marks a tree with uncommitted changes, so a stamp never vouches for code it does not hold', () => {
|
||||
expect(readBuildSha({}, gitAt(SHA, ' M src/x.ts\n'))).toBe(`${SHA}-dirty`);
|
||||
});
|
||||
it('lets BUILD_SHA stand in where there is no git, and ignores a value that is not a full sha', () => {
|
||||
const noGit = () => {
|
||||
throw new Error('not a git repository');
|
||||
};
|
||||
expect(readBuildSha({ BUILD_SHA: SHA }, noGit)).toBe(SHA);
|
||||
expect(readBuildSha({ BUILD_SHA: SHA }, gitAt(SHA))).toBe(SHA);
|
||||
// a different HEAD is a mismatch, not a clean stamp of the explicit sha
|
||||
expect(readBuildSha({ BUILD_SHA: SHA }, gitAt('c'.repeat(40)))).toBe(`${SHA}-mismatch`);
|
||||
// a value that is not a lowercase full sha is ignored
|
||||
['b6b1d52', SHA.toUpperCase(), `${SHA}0`].forEach((v) =>
|
||||
expect(readBuildSha({ BUILD_SHA: v }, noGit)).toBe('unknown')
|
||||
);
|
||||
// git that answers but cannot say what the tree holds fails closed
|
||||
const brokenStatus = (cmd, ...args) => {
|
||||
if (cmd === 'status') throw new Error('index file smaller than expected');
|
||||
return args[0] === '--show-prefix' ? '\n' : `${SHA}\n`;
|
||||
};
|
||||
expect(readBuildSha({ BUILD_SHA: SHA }, brokenStatus)).toBe('unknown');
|
||||
expect(readBuildSha({}, brokenStatus)).toBe('unknown');
|
||||
expect(readBuildSha({}, gitAt('nope'))).toBe('unknown');
|
||||
// inside another repository's subfolder git does not govern: the explicit sha stands
|
||||
const nested = (cmd, ...args) => (args[0] === '--show-prefix' ? 'vendor/ratatoskr/\n' : SHA);
|
||||
expect(readBuildSha({ BUILD_SHA: SHA }, nested)).toBe(SHA);
|
||||
expect(readBuildSha({}, nested)).toBe('unknown');
|
||||
expect(readBuildSha({ BUILD_SHA: 'main' }, noGit)).toBe('unknown');
|
||||
});
|
||||
it("says 'unknown' rather than failing the build when git is absent", () => {
|
||||
expect(
|
||||
readBuildSha({}, () => {
|
||||
throw new Error('spawn git ENOENT');
|
||||
})
|
||||
).toBe('unknown');
|
||||
});
|
||||
});
|
||||
|
||||
describe('readBuildSha against a real repository', () => {
|
||||
const made = [];
|
||||
afterEach(() => {
|
||||
made.splice(0).forEach((d) => rmSync(d, { recursive: true, force: true }));
|
||||
});
|
||||
const repo = () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), 'buildsha-'));
|
||||
made.push(dir);
|
||||
const g = (...a) => execFileSync('git', a, { cwd: dir, stdio: 'ignore' });
|
||||
g('init', '-q');
|
||||
mkdirSync(join(dir, 'src'));
|
||||
writeFileSync(join(dir, 'src', 'a.ts'), 'export {};\n');
|
||||
g('add', '.');
|
||||
g('-c', 'user.name=t', '-c', 'user.email=t@t', 'commit', '-qm', 'x');
|
||||
return dir;
|
||||
};
|
||||
it("stays clean with vite's temp config file present, and is dirty with a stray source file", () => {
|
||||
const dir = repo();
|
||||
const run = gitIn(dir);
|
||||
writeFileSync(join(dir, 'vite.config.js.timestamp-1700000000-abc123.mjs'), '');
|
||||
expect(readBuildSha({}, run)).toMatch(/^[0-9a-f]{40}$/);
|
||||
writeFileSync(join(dir, 'src', 'zz-stray.ts'), '');
|
||||
expect(readBuildSha({}, run)).toMatch(/^[0-9a-f]{40}-dirty$/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('readBuildSha dirty rules against a real repository', () => {
|
||||
const made2 = [];
|
||||
afterEach(() => {
|
||||
made2.splice(0).forEach((d) => rmSync(d, { recursive: true, force: true }));
|
||||
});
|
||||
const TEMP = 'vite.config.js.timestamp-1700000000-abc123.mjs';
|
||||
const repo2 = (tracked = []) => {
|
||||
const dir = mkdtempSync(join(tmpdir(), 'buildsha-'));
|
||||
made2.push(dir);
|
||||
const g = (...a) => execFileSync('git', a, { cwd: dir, stdio: 'ignore' });
|
||||
g('init', '-q');
|
||||
mkdirSync(join(dir, 'src'));
|
||||
writeFileSync(join(dir, 'src', 'a.ts'), 'export {};\n');
|
||||
tracked.forEach((f) => writeFileSync(join(dir, f), 'x\n'));
|
||||
g('add', '.');
|
||||
g('-c', 'user.name=t', '-c', 'user.email=t@t', 'commit', '-qm', 'x');
|
||||
return {
|
||||
dir,
|
||||
head: execFileSync('git', ['rev-parse', 'HEAD'], { cwd: dir, encoding: 'utf8' }).trim(),
|
||||
};
|
||||
};
|
||||
it('does not let an explicit BUILD_SHA mask a dirty tree', () => {
|
||||
const { dir, head } = repo2();
|
||||
const run = gitIn(dir);
|
||||
expect(readBuildSha({ BUILD_SHA: head }, run)).toBe(head);
|
||||
writeFileSync(join(dir, 'src', 'zz-stray.ts'), '');
|
||||
expect(readBuildSha({ BUILD_SHA: head }, run)).toBe(`${head}-dirty`);
|
||||
});
|
||||
it('lets git speak only for a tree whose root it is: an archive unpacked inside another repository keeps its explicit sha', () => {
|
||||
const { dir } = repo2();
|
||||
const inner = join(dir, 'vendor', 'ratatoskr');
|
||||
mkdirSync(inner, { recursive: true });
|
||||
writeFileSync(join(inner, 'x.ts'), '');
|
||||
expect(readBuildSha({ BUILD_SHA: SHA }, gitIn(inner))).toBe(SHA);
|
||||
expect(readBuildSha({}, gitIn(inner))).toBe('unknown');
|
||||
});
|
||||
it("notices an untracked .mjs that is not vite's temp file", () => {
|
||||
const { dir, head } = repo2();
|
||||
writeFileSync(join(dir, 'foo.mjs'), '');
|
||||
expect(readBuildSha({}, gitIn(dir))).toBe(`${head}-dirty`);
|
||||
rmSync(join(dir, 'foo.mjs'));
|
||||
// only vite's exact shape is its own: vite.config.<ext>.timestamp-<digits>-<hex>.mjs
|
||||
[
|
||||
'vite.config.js.timestamp-1-ab.mjs.bak',
|
||||
'vite.config.js.timestamp-x-ab.mjs',
|
||||
'vite.config.js.timestamp-1-zz.mjs',
|
||||
'vite.config.a.b.timestamp-1-ab.mjs',
|
||||
'vite.config.js.timestamp-1-ab-c.mjs',
|
||||
].forEach((name) => {
|
||||
writeFileSync(join(dir, name), '');
|
||||
expect(readBuildSha({}, gitIn(dir)), name).toBe(`${head}-dirty`);
|
||||
rmSync(join(dir, name));
|
||||
});
|
||||
expect(readBuildSha({}, gitIn(dir))).toBe(head);
|
||||
});
|
||||
it('treats a stray source file as dirty even beside the vite temp file, in the root or a subfolder', () => {
|
||||
const { dir, head } = repo2();
|
||||
const run = gitIn(dir);
|
||||
writeFileSync(join(dir, TEMP), '');
|
||||
writeFileSync(join(dir, 'src', TEMP), '');
|
||||
expect(readBuildSha({}, run)).toBe(head);
|
||||
writeFileSync(join(dir, 'src', 'zz-stray.ts'), '');
|
||||
expect(readBuildSha({}, run)).toBe(`${head}-dirty`);
|
||||
});
|
||||
it('marks a tracked file of the temp name dirty once it changes', () => {
|
||||
const { dir, head } = repo2([TEMP]);
|
||||
const run = gitIn(dir);
|
||||
expect(readBuildSha({}, run)).toBe(head);
|
||||
writeFileSync(join(dir, TEMP), 'changed\n');
|
||||
expect(readBuildSha({}, run)).toBe(`${head}-dirty`);
|
||||
});
|
||||
it('marks an untracked file in a new folder dirty (status lists files, not the folder)', () => {
|
||||
const { dir, head } = repo2();
|
||||
mkdirSync(join(dir, 'new'));
|
||||
writeFileSync(join(dir, 'new', TEMP), '');
|
||||
expect(readBuildSha({}, gitIn(dir))).toBe(head);
|
||||
writeFileSync(join(dir, 'new', 'b.ts'), '');
|
||||
expect(readBuildSha({}, gitIn(dir))).toBe(`${head}-dirty`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildShaPlugin', () => {
|
||||
it("hands vite a meta tag for the page's head carrying the sha", () => {
|
||||
const plugin = buildShaPlugin(SHA);
|
||||
expect(plugin.transformIndexHtml()).toEqual([
|
||||
{ tag: 'meta', attrs: { name: 'build-sha', content: SHA }, injectTo: 'head-prepend' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
@ -16,7 +16,6 @@ import {
|
|||
} from 'folds';
|
||||
import { MatrixError } from 'matrix-js-sdk';
|
||||
import { Cursor } from '../plugins/text-area';
|
||||
import { PhoneHit } from '../styles/PhoneHit.css';
|
||||
import { syntaxErrorPosition } from '../utils/dom';
|
||||
import { AsyncStatus, useAsyncCallback } from '../hooks/useAsyncCallback';
|
||||
import { Page, PageHeader } from './page';
|
||||
|
|
@ -295,7 +294,7 @@ export function AccountDataEditor({
|
|||
</Chip>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton onClick={requestClose} variant="Surface" className={PhoneHit}>
|
||||
<IconButton onClick={requestClose} variant="Surface">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ import {
|
|||
} from '../hooks/useKeyBackup';
|
||||
import { stopPropagation } from '../utils/keyboard';
|
||||
import { useRestoreBackupOnVerification } from '../hooks/useRestoreBackupOnVerification';
|
||||
import { PhoneHit } from '../styles/PhoneHit.css';
|
||||
|
||||
type BackupStatusProps = {
|
||||
enabled: boolean;
|
||||
|
|
@ -178,7 +177,6 @@ export function BackupRestoreTile({ crypto }: BackupRestoreTileProps) {
|
|||
<BackupSyncing count={remainingSession} />
|
||||
)}
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
aria-pressed={!!menuCords}
|
||||
size="300"
|
||||
variant="Surface"
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ import {
|
|||
} from '../hooks/useVerificationRequest';
|
||||
import { AsyncStatus, useAsyncCallback } from '../hooks/useAsyncCallback';
|
||||
import { ContainerColor } from '../styles/ContainerColor.css';
|
||||
import { PhoneHit } from '../styles/PhoneHit.css';
|
||||
|
||||
const DialogHeaderStyles: CSSProperties = {
|
||||
padding: `0 ${config.space.S200} 0 ${config.space.S400}`,
|
||||
|
|
@ -262,7 +261,7 @@ export function DeviceVerification({ request, onExit }: DeviceVerificationProps)
|
|||
<Box grow="Yes">
|
||||
<Text size="H4">Device Verification</Text>
|
||||
</Box>
|
||||
<IconButton className={PhoneHit} size="300" radii="300" onClick={handleCancel}>
|
||||
<IconButton size="300" radii="300" onClick={handleCancel}>
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import { ActionUIA, ActionUIAFlowsLoader } from './ActionUIA';
|
|||
import { useMatrixClient } from '../hooks/useMatrixClient';
|
||||
import { useAlive } from '../hooks/useAlive';
|
||||
import { UseStateProvider } from './UseStateProvider';
|
||||
import { PhoneHit } from '../styles/PhoneHit.css';
|
||||
|
||||
type UIACallback<T> = (
|
||||
authDict: AuthDict | null
|
||||
|
|
@ -302,7 +301,7 @@ export const DeviceVerificationSetup = forwardRef<HTMLDivElement, DeviceVerifica
|
|||
<Box grow="Yes">
|
||||
<Text size="H4">Setup Device Verification</Text>
|
||||
</Box>
|
||||
<IconButton className={PhoneHit} size="300" radii="300" onClick={onCancel}>
|
||||
<IconButton size="300" radii="300" onClick={onCancel}>
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
@ -337,7 +336,7 @@ export const DeviceVerificationReset = forwardRef<HTMLDivElement, DeviceVerifica
|
|||
<Box grow="Yes">
|
||||
<Text size="H4">Reset Device Verification</Text>
|
||||
</Box>
|
||||
<IconButton className={PhoneHit} size="300" radii="300" onClick={onCancel}>
|
||||
<IconButton size="300" radii="300" onClick={onCancel}>
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import { AsyncStatus } from '../../hooks/useAsyncCallback';
|
|||
import { useZoom } from '../../hooks/useZoom';
|
||||
import { createPage, usePdfDocumentLoader, usePdfJSLoader } from '../../plugins/pdfjs-dist';
|
||||
import { stopPropagation } from '../../utils/keyboard';
|
||||
import { PhoneHit, PhoneHitSpread24 } from '../../styles/PhoneHit.css';
|
||||
|
||||
export type PdfViewerProps = {
|
||||
name: string;
|
||||
|
|
@ -109,7 +108,7 @@ export const PdfViewer = as<'div', PdfViewerProps>(
|
|||
<Box className={classNames(css.PdfViewer, className)} direction="Column" {...props} ref={ref}>
|
||||
<Header className={css.PdfViewerHeader} size="400">
|
||||
<Box grow="Yes" alignItems="Center" gap="200">
|
||||
<IconButton className={PhoneHit} size="300" radii="300" onClick={requestClose}>
|
||||
<IconButton size="300" radii="300" onClick={requestClose}>
|
||||
<Icon size="50" src={Icons.ArrowLeft} />
|
||||
</IconButton>
|
||||
<Text size="T300" truncate>
|
||||
|
|
@ -118,7 +117,6 @@ export const PdfViewer = as<'div', PdfViewerProps>(
|
|||
</Box>
|
||||
<Box shrink="No" alignItems="Center" gap="200">
|
||||
<IconButton
|
||||
className={PhoneHitSpread24}
|
||||
variant={zoom < 1 ? 'Success' : 'SurfaceVariant'}
|
||||
outlined={zoom < 1}
|
||||
size="300"
|
||||
|
|
@ -132,7 +130,6 @@ export const PdfViewer = as<'div', PdfViewerProps>(
|
|||
<Text size="B300">{Math.round(zoom * 100)}%</Text>
|
||||
</Chip>
|
||||
<IconButton
|
||||
className={PhoneHitSpread24}
|
||||
variant={zoom > 1 ? 'Success' : 'SurfaceVariant'}
|
||||
outlined={zoom > 1}
|
||||
size="300"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import {
|
|||
IconButton,
|
||||
} from 'folds';
|
||||
import FocusTrap from 'focus-trap-react';
|
||||
import { PhoneHit } from '../styles/PhoneHit.css';
|
||||
|
||||
export type UIAFlowOverlayProps = {
|
||||
currentStep: number;
|
||||
|
|
@ -54,7 +53,6 @@ export function UIAFlowOverlay({
|
|||
>
|
||||
{(anchorRef) => (
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
ref={anchorRef}
|
||||
variant="Critical"
|
||||
size="300"
|
||||
|
|
|
|||
84
src/app/components/editor/Editor.preview.tsx
Normal file
84
src/app/components/editor/Editor.preview.tsx
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import React, { useState } from 'react';
|
||||
import FocusTrap from 'focus-trap-react';
|
||||
import {
|
||||
config,
|
||||
Icon,
|
||||
IconButton,
|
||||
Icons,
|
||||
Line,
|
||||
Modal,
|
||||
Overlay,
|
||||
OverlayBackdrop,
|
||||
OverlayCenter,
|
||||
} from 'folds';
|
||||
|
||||
import { CustomEditor, useEditor } from './Editor';
|
||||
import { Toolbar } from './Toolbar';
|
||||
import { stopPropagation } from '../../utils/keyboard';
|
||||
|
||||
export function EditorPreview() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const editor = useEditor();
|
||||
const [toolbar, setToolbar] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<IconButton variant="SurfaceVariant" onClick={() => setOpen(!open)}>
|
||||
<Icon src={Icons.BlockQuote} />
|
||||
</IconButton>
|
||||
<Overlay open={open} backdrop={<OverlayBackdrop />}>
|
||||
<OverlayCenter>
|
||||
<FocusTrap
|
||||
focusTrapOptions={{
|
||||
initialFocus: false,
|
||||
onDeactivate: () => setOpen(false),
|
||||
clickOutsideDeactivates: true,
|
||||
escapeDeactivates: stopPropagation,
|
||||
}}
|
||||
>
|
||||
<Modal size="500">
|
||||
<div style={{ padding: config.space.S400 }}>
|
||||
<CustomEditor
|
||||
editor={editor}
|
||||
placeholder="Send a message..."
|
||||
before={
|
||||
<IconButton variant="SurfaceVariant" size="300" radii="300">
|
||||
<Icon src={Icons.PlusCircle} />
|
||||
</IconButton>
|
||||
}
|
||||
after={
|
||||
<>
|
||||
<IconButton
|
||||
variant="SurfaceVariant"
|
||||
size="300"
|
||||
radii="300"
|
||||
onClick={() => setToolbar(!toolbar)}
|
||||
aria-pressed={toolbar}
|
||||
>
|
||||
<Icon src={toolbar ? Icons.AlphabetUnderline : Icons.Alphabet} />
|
||||
</IconButton>
|
||||
<IconButton variant="SurfaceVariant" size="300" radii="300">
|
||||
<Icon src={Icons.Smile} />
|
||||
</IconButton>
|
||||
<IconButton variant="SurfaceVariant" size="300" radii="300">
|
||||
<Icon src={Icons.Send} />
|
||||
</IconButton>
|
||||
</>
|
||||
}
|
||||
bottom={
|
||||
toolbar && (
|
||||
<div>
|
||||
<Line variant="SurfaceVariant" size="300" />
|
||||
<Toolbar />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</Modal>
|
||||
</FocusTrap>
|
||||
</OverlayCenter>
|
||||
</Overlay>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -36,7 +36,6 @@ import { KeySymbol } from '../../utils/key-symbol';
|
|||
import { useSetting } from '../../state/hooks/settings';
|
||||
import { settingsAtom } from '../../state/settings';
|
||||
import { stopPropagation } from '../../utils/keyboard';
|
||||
import { PhoneHit, PhoneHitRoom36, PhoneHitSpread36 } from '../../styles/PhoneHit.css';
|
||||
|
||||
function BtnTooltip({ text, shortCode }: { text: string; shortCode?: string }) {
|
||||
return (
|
||||
|
|
@ -73,7 +72,6 @@ export function MarkButton({ format, icon, tooltip }: MarkButtonProps) {
|
|||
<TooltipProvider tooltip={tooltip} delay={500}>
|
||||
{(triggerRef) => (
|
||||
<IconButton
|
||||
className={PhoneHitSpread36}
|
||||
ref={triggerRef}
|
||||
variant="SurfaceVariant"
|
||||
onClick={handleClick}
|
||||
|
|
@ -106,7 +104,6 @@ export function BlockButton({ format, icon, tooltip }: BlockButtonProps) {
|
|||
<TooltipProvider tooltip={tooltip} delay={500}>
|
||||
{(triggerRef) => (
|
||||
<IconButton
|
||||
className={PhoneHitSpread36}
|
||||
ref={triggerRef}
|
||||
variant="SurfaceVariant"
|
||||
onClick={handleClick}
|
||||
|
|
@ -166,7 +163,6 @@ export function HeadingBlockButton() {
|
|||
>
|
||||
{(triggerRef) => (
|
||||
<IconButton
|
||||
className={PhoneHitRoom36}
|
||||
ref={triggerRef}
|
||||
onClick={() => handleMenuSelect(1)}
|
||||
size="400"
|
||||
|
|
@ -182,7 +178,6 @@ export function HeadingBlockButton() {
|
|||
>
|
||||
{(triggerRef) => (
|
||||
<IconButton
|
||||
className={PhoneHitRoom36}
|
||||
ref={triggerRef}
|
||||
onClick={() => handleMenuSelect(2)}
|
||||
size="400"
|
||||
|
|
@ -198,7 +193,6 @@ export function HeadingBlockButton() {
|
|||
>
|
||||
{(triggerRef) => (
|
||||
<IconButton
|
||||
className={PhoneHitRoom36}
|
||||
ref={triggerRef}
|
||||
onClick={() => handleMenuSelect(3)}
|
||||
size="400"
|
||||
|
|
@ -214,7 +208,6 @@ export function HeadingBlockButton() {
|
|||
}
|
||||
>
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
style={{ width: 'unset' }}
|
||||
variant="SurfaceVariant"
|
||||
onClick={handleMenuOpen}
|
||||
|
|
@ -246,7 +239,6 @@ export function ExitFormatting({ tooltip }: ExitFormattingProps) {
|
|||
<TooltipProvider tooltip={tooltip} delay={500}>
|
||||
{(triggerRef) => (
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
ref={triggerRef}
|
||||
variant="SurfaceVariant"
|
||||
onClick={handleClick}
|
||||
|
|
@ -352,7 +344,6 @@ export function Toolbar() {
|
|||
>
|
||||
{(triggerRef) => (
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
ref={triggerRef}
|
||||
variant="SurfaceVariant"
|
||||
onClick={() => setIsMarkdown(!isMarkdown)}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import {
|
|||
} from 'folds';
|
||||
import classNames from 'classnames';
|
||||
import * as css from './styles.css';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
export function Sidebar({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
|
|
@ -69,7 +68,6 @@ function SidebarBtn<T extends string>({
|
|||
>
|
||||
{(ref) => (
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
aria-pressed={active}
|
||||
aria-labelledby={`SidebarStackItem-${id}-label`}
|
||||
ref={ref}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
|
|||
import { useOpenUserRoomProfile } from '../../state/hooks/userRoomProfile';
|
||||
import { useSpaceOptionally } from '../../hooks/useSpace';
|
||||
import { getMouseEventCords } from '../../utils/dom';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
export type EventReadersProps = {
|
||||
room: Room;
|
||||
|
|
@ -53,7 +52,7 @@ export const EventReaders = as<'div', EventReadersProps>(
|
|||
<Box grow="Yes">
|
||||
<Text size="H3">Seen by</Text>
|
||||
</Box>
|
||||
<IconButton className={PhoneHit} size="300" onClick={requestClose}>
|
||||
<IconButton size="300" onClick={requestClose}>
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import React from 'react';
|
|||
import classNames from 'classnames';
|
||||
import { Box, Chip, Header, Icon, IconButton, Icons, Text, as } from 'folds';
|
||||
import * as css from './ImageEditor.css';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
export type ImageEditorProps = {
|
||||
name: string;
|
||||
|
|
@ -25,7 +24,7 @@ export const ImageEditor = as<'div', ImageEditorProps>(
|
|||
>
|
||||
<Header className={css.ImageEditorHeader} size="400">
|
||||
<Box grow="Yes" alignItems="Center" gap="200">
|
||||
<IconButton className={PhoneHit} size="300" radii="300" onClick={requestClose}>
|
||||
<IconButton size="300" radii="300" onClick={requestClose}>
|
||||
<Icon size="50" src={Icons.ArrowLeft} />
|
||||
</IconButton>
|
||||
<Text size="T300" truncate>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import React from 'react';
|
||||
import { Box, IconButton, Text, Icon, Icons, Scroll, Chip } from 'folds';
|
||||
import { PackAddress } from '../../plugins/custom-emoji';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
import { Page, PageHeader, PageContent } from '../page';
|
||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||
import { RoomImagePack } from './RoomImagePack';
|
||||
|
|
@ -30,7 +29,7 @@ export function ImagePackView({ address, requestClose }: ImagePackViewProps) {
|
|||
</Chip>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton onClick={requestClose} variant="Surface" className={PhoneHit}>
|
||||
<IconButton onClick={requestClose} variant="Surface">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import * as css from './ImageViewer.css';
|
|||
import { useZoom } from '../../hooks/useZoom';
|
||||
import { usePan } from '../../hooks/usePan';
|
||||
import { downloadMedia } from '../../utils/matrix';
|
||||
import { PhoneHit, PhoneHitSpread24 } from '../../styles/PhoneHit.css';
|
||||
|
||||
export type ImageViewerProps = {
|
||||
alt: string;
|
||||
|
|
@ -34,7 +33,7 @@ export const ImageViewer = as<'div', ImageViewerProps>(
|
|||
>
|
||||
<Header className={css.ImageViewerHeader} size="400">
|
||||
<Box grow="Yes" alignItems="Center" gap="200">
|
||||
<IconButton className={PhoneHit} size="300" radii="300" onClick={requestClose}>
|
||||
<IconButton size="300" radii="300" onClick={requestClose}>
|
||||
<Icon size="50" src={Icons.ArrowLeft} />
|
||||
</IconButton>
|
||||
<Text size="T300" truncate>
|
||||
|
|
@ -43,7 +42,6 @@ export const ImageViewer = as<'div', ImageViewerProps>(
|
|||
</Box>
|
||||
<Box shrink="No" alignItems="Center" gap="200">
|
||||
<IconButton
|
||||
className={PhoneHitSpread24}
|
||||
variant={zoom < 1 ? 'Success' : 'SurfaceVariant'}
|
||||
outlined={zoom < 1}
|
||||
size="300"
|
||||
|
|
@ -57,7 +55,6 @@ export const ImageViewer = as<'div', ImageViewerProps>(
|
|||
<Text size="B300">{Math.round(zoom * 100)}%</Text>
|
||||
</Chip>
|
||||
<IconButton
|
||||
className={PhoneHitSpread24}
|
||||
variant={zoom > 1 ? 'Success' : 'SurfaceVariant'}
|
||||
outlined={zoom > 1}
|
||||
size="300"
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
|
|||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||
import { BreakWord } from '../../styles/Text.css';
|
||||
import { useAlive } from '../../hooks/useAlive';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
const SEARCH_OPTIONS: UseAsyncSearchOptions = {
|
||||
limit: 1000,
|
||||
|
|
@ -174,7 +173,7 @@ export function InviteUserPrompt({ room, requestClose }: InviteUserProps) {
|
|||
</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} size="300" radii="300" onClick={requestClose}>
|
||||
<IconButton size="300" radii="300" onClick={requestClose}>
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import { stopPropagation } from '../../utils/keyboard';
|
|||
import { isRoomAlias, isRoomId } from '../../utils/matrix';
|
||||
import { parseMatrixToRoom, parseMatrixToRoomEvent, testMatrixTo } from '../../plugins/matrix-to';
|
||||
import { tryDecodeURIComponent } from '../../utils/dom';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
type JoinAddressProps = {
|
||||
onOpen: (roomIdOrAlias: string, via?: string[], eventId?: string) => void;
|
||||
|
|
@ -83,7 +82,7 @@ export function JoinAddressPrompt({ onOpen, onCancel }: JoinAddressProps) {
|
|||
<Box grow="Yes">
|
||||
<Text size="H4">Join with Address</Text>
|
||||
</Box>
|
||||
<IconButton className={PhoneHit} size="300" onClick={onCancel} radii="300">
|
||||
<IconButton size="300" onClick={onCancel} radii="300">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import { MatrixError } from 'matrix-js-sdk';
|
|||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
|
||||
import { stopPropagation } from '../../utils/keyboard';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
type LeaveRoomPromptProps = {
|
||||
roomId: string;
|
||||
|
|
@ -69,7 +68,7 @@ export function LeaveRoomPrompt({ roomId, onDone, onCancel }: LeaveRoomPromptPro
|
|||
<Box grow="Yes">
|
||||
<Text size="H4">Leave Room</Text>
|
||||
</Box>
|
||||
<IconButton className={PhoneHit} size="300" onClick={onCancel} radii="300">
|
||||
<IconButton size="300" onClick={onCancel} radii="300">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import { MatrixError } from 'matrix-js-sdk';
|
|||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
|
||||
import { stopPropagation } from '../../utils/keyboard';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
type LeaveSpacePromptProps = {
|
||||
roomId: string;
|
||||
|
|
@ -69,7 +68,7 @@ export function LeaveSpacePrompt({ roomId, onDone, onCancel }: LeaveSpacePromptP
|
|||
<Box grow="Yes">
|
||||
<Text size="H4">Leave Space</Text>
|
||||
</Box>
|
||||
<IconButton className={PhoneHit} size="300" onClick={onCancel} radii="300">
|
||||
<IconButton size="300" onClick={onCancel} radii="300">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import { Badge, Box, Icon, IconButton, Icons, Spinner, Text, as, toRem } from 'f
|
|||
import React, { ReactNode, useCallback } from 'react';
|
||||
import { EncryptedAttachmentInfo } from 'browser-encrypt-attachment';
|
||||
import FileSaver from 'file-saver';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
import { mimeTypeToExt } from '../../utils/mimeTypes';
|
||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
|
||||
|
|
@ -49,7 +48,6 @@ export function FileDownloadButton({ filename, url, mimeType, encInfo }: FileDow
|
|||
variant={hasError ? 'Critical' : 'SurfaceVariant'}
|
||||
size="300"
|
||||
radii="300"
|
||||
className={PhoneHit}
|
||||
>
|
||||
{downloading ? (
|
||||
<Spinner size="100" variant={hasError ? 'Critical' : 'Secondary'} />
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
import { createVar, style } from '@vanilla-extract/css';
|
||||
import { DefaultReset, FocusOutline, color, config, toRem } from 'folds';
|
||||
import { MOBILE_BREAKPOINT } from '../../hooks/useScreenSize';
|
||||
import { PHONE_TAP } from '../../styles/PhoneHit.css';
|
||||
|
||||
const PHONE = `screen and (max-width: ${MOBILE_BREAKPOINT}px)`;
|
||||
const Container = createVar();
|
||||
const ContainerHover = createVar();
|
||||
const ContainerActive = createVar();
|
||||
|
|
@ -28,14 +25,6 @@ export const Reaction = style([
|
|||
selectors: {
|
||||
'button&': {
|
||||
cursor: 'pointer',
|
||||
// Phone tap target: the chip is 26 px tall, so its hit area grows 9 px above and below (an ::after) and the
|
||||
// same 9 px of margin opens the row, so the chips of one row and of the next never share a tap.
|
||||
'@media': { [PHONE]: { position: 'relative', marginBlock: (PHONE_TAP - 26) / 2 } },
|
||||
},
|
||||
'button&::after': {
|
||||
'@media': {
|
||||
[PHONE]: { content: '""', position: 'absolute', inset: `${-(PHONE_TAP - 26) / 2}px 0` },
|
||||
},
|
||||
},
|
||||
'&[aria-pressed=true]': {
|
||||
vars: {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import React, { ReactNode, useCallback, useRef, useState } from 'react';
|
|||
import { Badge, Chip, Icon, IconButton, Icons, ProgressBar, Spinner, Text, toRem } from 'folds';
|
||||
import { EncryptedAttachmentInfo } from 'browser-encrypt-attachment';
|
||||
import { Range } from 'react-range';
|
||||
import { PhoneHitSpread24 } from '../../../styles/PhoneHit.css';
|
||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
||||
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
|
||||
import { IAudioInfo } from '../../../../types/matrix/common';
|
||||
|
|
@ -160,7 +159,6 @@ export function AudioContent({
|
|||
variant="SurfaceVariant"
|
||||
size="300"
|
||||
radii="Pill"
|
||||
className={PhoneHitSpread24}
|
||||
onClick={() => setMute(!mute)}
|
||||
aria-pressed={mute}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -299,10 +299,7 @@ export const BubbleLeftArrow = style({
|
|||
});
|
||||
|
||||
// Phone tap target: a sender name is 23 px tall, so the button grows 11 px above and below (44+ px to tap) and the
|
||||
// negative margin takes the growth back out of the layout. Sideways it cannot borrow from the layout the
|
||||
// same way (a negative inline margin makes the button shrink inside its shrink-to-fit parent and clip the name), so
|
||||
// a name under 44 px is 44 px wide, text kept at the start: real growth of at most 16 px, in a row with room for it.
|
||||
// No background, border or outline moves.
|
||||
// negative margin takes the growth back out of the layout. Hit area only: no background, border or outline moves.
|
||||
const SCREEN_PHONE = `screen and (max-width: ${MOBILE_BREAKPOINT}px)`;
|
||||
export const Username = style({
|
||||
overflow: 'hidden',
|
||||
|
|
@ -312,7 +309,7 @@ export const Username = style({
|
|||
'button&': {
|
||||
cursor: 'pointer',
|
||||
'@media': {
|
||||
[SCREEN_PHONE]: { paddingBlock: 11, marginBlock: -11, minWidth: 44, textAlign: 'start' },
|
||||
[SCREEN_PHONE]: { paddingBlock: 11, marginBlock: -11 },
|
||||
},
|
||||
},
|
||||
'button&:hover, button&:focus-visible': {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import React, { ComponentProps, forwardRef } from 'react';
|
||||
import { Icon, IconButton, Input, config, Icons } from 'folds';
|
||||
import { UseStateProvider } from '../UseStateProvider';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
type PasswordInputProps = Omit<ComponentProps<typeof Input>, 'type' | 'size'> & {
|
||||
size: '400' | '500';
|
||||
|
|
@ -24,7 +23,6 @@ export const PasswordInput = forwardRef<HTMLInputElement, PasswordInputProps>(
|
|||
<>
|
||||
{after}
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
onClick={() => setVisible(!visible)}
|
||||
type="button"
|
||||
variant={visible ? 'Warning' : variant}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import classNames from 'classnames';
|
|||
import Linkify from 'linkify-react';
|
||||
import * as css from './style.css';
|
||||
import { LINKIFY_OPTS, scaleSystemEmoji } from '../../plugins/react-custom-html-parser';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
export const RoomTopicViewer = as<
|
||||
'div',
|
||||
|
|
@ -27,7 +26,7 @@ export const RoomTopicViewer = as<
|
|||
{name}
|
||||
</Text>
|
||||
</Box>
|
||||
<IconButton className={PhoneHit} size="300" onClick={requestClose} radii="300">
|
||||
<IconButton size="300" onClick={requestClose} radii="300">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import { Box, Chip, Header, Icon, IconButton, Icons, Scroll, Text, as } from 'fo
|
|||
import { ErrorBoundary } from 'react-error-boundary';
|
||||
import * as css from './TextViewer.css';
|
||||
import { copyToClipboard } from '../../utils/dom';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
const ReactPrism = lazy(() => import('../../plugins/react-prism/ReactPrism'));
|
||||
|
||||
|
|
@ -54,7 +53,7 @@ export const TextViewer = as<'div', TextViewerProps>(
|
|||
>
|
||||
<Header className={css.TextViewerHeader} size="400">
|
||||
<Box grow="Yes" alignItems="Center" gap="200">
|
||||
<IconButton className={PhoneHit} size="300" radii="300" onClick={requestClose}>
|
||||
<IconButton size="300" radii="300" onClick={requestClose}>
|
||||
<Icon size="50" src={Icons.ArrowLeft} />
|
||||
</IconButton>
|
||||
<Text size="T300" truncate>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { AuthType } from 'matrix-js-sdk';
|
|||
import { StageComponentProps } from './types';
|
||||
import { ErrorCode } from '../../cs-errorcode';
|
||||
import { PasswordInput } from '../password-input';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
export function PasswordStage({
|
||||
stageData,
|
||||
|
|
@ -46,7 +45,7 @@ export function PasswordStage({
|
|||
<Box grow="Yes">
|
||||
<Text size="H4">Account Password</Text>
|
||||
</Box>
|
||||
<IconButton className={PhoneHit} size="300" onClick={onCancel} radii="300">
|
||||
<IconButton size="300" onClick={onCancel} radii="300">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { Box, Button, color, config, Dialog, Header, Icon, IconButton, Icons, Text } from 'folds';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { StageComponentProps } from './types';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
export function SSOStage({
|
||||
ssoRedirectURL,
|
||||
|
|
@ -57,7 +56,7 @@ export function SSOStage({
|
|||
<Box grow="Yes">
|
||||
<Text size="H4">SSO Login</Text>
|
||||
</Box>
|
||||
<IconButton className={PhoneHit} size="300" onClick={onCancel} radii="300">
|
||||
<IconButton size="300" onClick={onCancel} radii="300">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import { useMatrixClient } from '../../hooks/useMatrixClient';
|
|||
import { TUploadContent } from '../../utils/matrix';
|
||||
import { bytesToSize, getFileTypeIcon } from '../../utils/common';
|
||||
import { useMediaConfig } from '../../hooks/useMediaConfig';
|
||||
import { PhoneHitSpread28 } from '../../styles/PhoneHit.css';
|
||||
|
||||
type CompactUploadCardRendererProps = {
|
||||
isEncrypted?: boolean;
|
||||
|
|
@ -64,7 +63,6 @@ export function CompactUploadCardRenderer({
|
|||
</Chip>
|
||||
)}
|
||||
<IconButton
|
||||
className={PhoneHitSpread28}
|
||||
onClick={removeUpload}
|
||||
aria-label="Cancel Upload"
|
||||
variant="SurfaceVariant"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import {
|
|||
} from '../../state/room/roomInputDrafts';
|
||||
import { useObjectURL } from '../../hooks/useObjectURL';
|
||||
import { useMediaConfig } from '../../hooks/useMediaConfig';
|
||||
import { PhoneHitSpread28 } from '../../styles/PhoneHit.css';
|
||||
|
||||
type PreviewImageProps = {
|
||||
fileItem: TUploadItem;
|
||||
|
|
@ -161,7 +160,6 @@ export function UploadCardRenderer({
|
|||
</Chip>
|
||||
)}
|
||||
<IconButton
|
||||
className={PhoneHitSpread28}
|
||||
onClick={removeUpload}
|
||||
aria-label="Cancel Upload"
|
||||
variant="SurfaceVariant"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import classNames from 'classnames';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { IPreviewUrlResponse } from 'matrix-js-sdk';
|
||||
import { Box, Icon, IconButton, Icons, Scroll, Spinner, Text, as, color, config } from 'folds';
|
||||
|
|
@ -11,7 +10,6 @@ import {
|
|||
useIntersectionObserver,
|
||||
} from '../../hooks/useIntersectionObserver';
|
||||
import * as css from './UrlPreviewCard.css';
|
||||
import { PhoneHitInPlace } from '../../styles/PhoneHit.css';
|
||||
import { tryDecodeURIComponent } from '../../utils/dom';
|
||||
import { mxcUrlToHttp } from '../../utils/matrix';
|
||||
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
|
||||
|
|
@ -183,10 +181,7 @@ export const UrlPreviewHolder = as<'div'>(({ children, ...props }, ref) => {
|
|||
<>
|
||||
<div className={css.UrlPreviewHolderGradient({ position: 'Left' })} />
|
||||
<IconButton
|
||||
className={classNames(
|
||||
css.UrlPreviewHolderBtn({ position: 'Left' }),
|
||||
PhoneHitInPlace
|
||||
)}
|
||||
className={css.UrlPreviewHolderBtn({ position: 'Left' })}
|
||||
variant="Secondary"
|
||||
radii="Pill"
|
||||
size="300"
|
||||
|
|
@ -204,10 +199,7 @@ export const UrlPreviewHolder = as<'div'>(({ children, ...props }, ref) => {
|
|||
<>
|
||||
<div className={css.UrlPreviewHolderGradient({ position: 'Right' })} />
|
||||
<IconButton
|
||||
className={classNames(
|
||||
css.UrlPreviewHolderBtn({ position: 'Right' }),
|
||||
PhoneHitInPlace
|
||||
)}
|
||||
className={css.UrlPreviewHolderBtn({ position: 'Right' })}
|
||||
variant="Primary"
|
||||
radii="Pill"
|
||||
size="300"
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ import { getPowerTagIconSrc, useGetMemberPowerTag } from '../../hooks/useMemberP
|
|||
import { useRoomCreators } from '../../hooks/useRoomCreators';
|
||||
import { useRoomPermissions } from '../../hooks/useRoomPermissions';
|
||||
import { useMemberPowerCompare } from '../../hooks/useMemberPowerCompare';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
type SelfDemoteAlertProps = {
|
||||
power: number;
|
||||
|
|
@ -71,7 +70,7 @@ function SelfDemoteAlert({ power, onCancel, onChange }: SelfDemoteAlertProps) {
|
|||
<Box grow="Yes">
|
||||
<Text size="H4">Self Demotion</Text>
|
||||
</Box>
|
||||
<IconButton className={PhoneHit} size="300" onClick={onCancel} radii="300">
|
||||
<IconButton size="300" onClick={onCancel} radii="300">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
@ -121,7 +120,7 @@ function SharedPowerAlert({ power, onCancel, onChange }: SharedPowerAlertProps)
|
|||
<Box grow="Yes">
|
||||
<Text size="H4">Shared Power</Text>
|
||||
</Box>
|
||||
<IconButton className={PhoneHit} size="300" onClick={onCancel} radii="300">
|
||||
<IconButton size="300" onClick={onCancel} radii="300">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ import { StateEvent } from '../../../types/matrix/room';
|
|||
import { getViaServers } from '../../plugins/via-servers';
|
||||
import { rateLimitedActions } from '../../utils/matrix';
|
||||
import { useAlive } from '../../hooks/useAlive';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
const SEARCH_OPTS: UseAsyncSearchOptions = {
|
||||
limit: 500,
|
||||
|
|
@ -202,7 +201,7 @@ export function AddExistingModal({ parentId, space, requestClose }: AddExistingM
|
|||
<Text size="H4">Add Existing</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} size="300" radii="300" onClick={requestClose}>
|
||||
<IconButton size="300" radii="300" onClick={requestClose}>
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import { StatusDivider } from './components';
|
|||
import { CallEmbed, useCallControlState } from '../../plugins/call';
|
||||
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
|
||||
import { callEmbedAtom } from '../../state/callEmbed';
|
||||
import { PhoneHitSpread26 } from '../../styles/PhoneHit.css';
|
||||
|
||||
type MicrophoneButtonProps = {
|
||||
enabled: boolean;
|
||||
|
|
@ -27,7 +26,6 @@ function MicrophoneButton({ enabled, onToggle, disabled }: MicrophoneButtonProps
|
|||
>
|
||||
{(anchorRef) => (
|
||||
<IconButton
|
||||
className={PhoneHitSpread26}
|
||||
ref={anchorRef}
|
||||
variant={enabled ? 'Surface' : 'Warning'}
|
||||
fill="Soft"
|
||||
|
|
@ -61,7 +59,6 @@ function SoundButton({ enabled, onToggle, disabled }: SoundButtonProps) {
|
|||
>
|
||||
{(anchorRef) => (
|
||||
<IconButton
|
||||
className={PhoneHitSpread26}
|
||||
ref={anchorRef}
|
||||
variant={enabled ? 'Surface' : 'Warning'}
|
||||
fill="Soft"
|
||||
|
|
@ -102,7 +99,6 @@ function VideoButton({ enabled, onToggle, disabled }: VideoButtonProps) {
|
|||
>
|
||||
{(anchorRef) => (
|
||||
<IconButton
|
||||
className={PhoneHitSpread26}
|
||||
ref={anchorRef}
|
||||
variant={enabled ? 'Success' : 'Surface'}
|
||||
fill="Soft"
|
||||
|
|
@ -140,7 +136,6 @@ function ScreenShareButton({ enabled, onToggle, disabled }: ScreenShareButtonPro
|
|||
>
|
||||
{(anchorRef) => (
|
||||
<IconButton
|
||||
className={PhoneHitSpread26}
|
||||
ref={anchorRef}
|
||||
variant={enabled ? 'Success' : 'Surface'}
|
||||
fill="Soft"
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import {
|
|||
SoundButton,
|
||||
VideoButton,
|
||||
} from './Controls';
|
||||
import { PhoneHitSpread40 } from '../../styles/PhoneHit.css';
|
||||
import { CallEmbed, useCallControlState } from '../../plugins/call';
|
||||
import { useResizeObserver } from '../../hooks/useResizeObserver';
|
||||
import { stopPropagation } from '../../utils/keyboard';
|
||||
|
|
@ -170,7 +169,6 @@ export function CallControls({ callEmbed }: CallControlsProps) {
|
|||
}
|
||||
>
|
||||
<IconButton
|
||||
className={PhoneHitSpread40}
|
||||
variant="Surface"
|
||||
fill="Soft"
|
||||
radii="400"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { useAtom } from 'jotai';
|
|||
import * as css from './styles.css';
|
||||
import { callChatAtom } from '../../state/callEmbed';
|
||||
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
|
||||
import { PhoneHitSpread40 } from '../../styles/PhoneHit.css';
|
||||
|
||||
export function ControlDivider() {
|
||||
return (
|
||||
|
|
@ -32,7 +31,6 @@ export function MicrophoneButton({ enabled, onToggle }: MicrophoneButtonProps) {
|
|||
>
|
||||
{(anchorRef) => (
|
||||
<IconButton
|
||||
className={PhoneHitSpread40}
|
||||
ref={anchorRef}
|
||||
variant={enabled ? 'Surface' : 'Warning'}
|
||||
fill="Soft"
|
||||
|
|
@ -66,7 +64,6 @@ export function SoundButton({ enabled, onToggle }: SoundButtonProps) {
|
|||
>
|
||||
{(anchorRef) => (
|
||||
<IconButton
|
||||
className={PhoneHitSpread40}
|
||||
ref={anchorRef}
|
||||
variant={enabled ? 'Surface' : 'Warning'}
|
||||
fill="Soft"
|
||||
|
|
@ -106,7 +103,6 @@ export function VideoButton({ enabled, onToggle }: VideoButtonProps) {
|
|||
>
|
||||
{(anchorRef) => (
|
||||
<IconButton
|
||||
className={PhoneHitSpread40}
|
||||
ref={anchorRef}
|
||||
variant={enabled ? 'Success' : 'Surface'}
|
||||
fill="Soft"
|
||||
|
|
@ -144,7 +140,6 @@ export function ScreenShareButton({ enabled, onToggle }: ScreenShareButtonProps)
|
|||
>
|
||||
{(anchorRef) => (
|
||||
<IconButton
|
||||
className={PhoneHitSpread40}
|
||||
ref={anchorRef}
|
||||
variant={enabled ? 'Success' : 'Surface'}
|
||||
fill="Soft"
|
||||
|
|
@ -175,7 +170,6 @@ export function ChatButton() {
|
|||
>
|
||||
{(anchorRef) => (
|
||||
<IconButton
|
||||
className={PhoneHitSpread40}
|
||||
ref={anchorRef}
|
||||
variant={chat ? 'Success' : 'Surface'}
|
||||
fill="Soft"
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ import {
|
|||
AccountDataSubmitCallback,
|
||||
} from '../../../components/AccountDataEditor';
|
||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
type DeveloperToolsProps = {
|
||||
requestClose: () => void;
|
||||
|
|
@ -93,7 +92,7 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
|||
</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Surface">
|
||||
<IconButton onClick={requestClose} variant="Surface">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import { useTextAreaCodeEditor } from '../../../hooks/useTextAreaCodeEditor';
|
|||
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
|
||||
import { syntaxErrorPosition } from '../../../utils/dom';
|
||||
import { Cursor } from '../../../plugins/text-area';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
const EDITOR_INTENT_SPACE_COUNT = 2;
|
||||
|
||||
|
|
@ -119,7 +118,7 @@ export function SendRoomEvent({ type, stateKey, requestClose }: SendRoomEventPro
|
|||
</Chip>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Surface">
|
||||
<IconButton onClick={requestClose} variant="Surface">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ import { usePowerLevels } from '../../../hooks/usePowerLevels';
|
|||
import { useTextAreaCodeEditor } from '../../../hooks/useTextAreaCodeEditor';
|
||||
import { useRoomCreators } from '../../../hooks/useRoomCreators';
|
||||
import { useRoomPermissions } from '../../../hooks/useRoomPermissions';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
const EDITOR_INTENT_SPACE_COUNT = 2;
|
||||
|
||||
|
|
@ -276,7 +275,7 @@ export function StateEventEditor({ type, stateKey, requestClose }: StateEventEdi
|
|||
</Chip>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Surface">
|
||||
<IconButton onClick={requestClose} variant="Surface">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { Page, PageContent, PageHeader } from '../../../components/page';
|
|||
import { ImagePack } from '../../../plugins/custom-emoji';
|
||||
import { ImagePackView } from '../../../components/image-pack-view';
|
||||
import { RoomPacks } from './RoomPacks';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
type EmojisStickersProps = {
|
||||
requestClose: () => void;
|
||||
|
|
@ -30,7 +29,7 @@ export function EmojisStickers({ requestClose }: EmojisStickersProps) {
|
|||
</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Surface">
|
||||
<IconButton onClick={requestClose} variant="Surface">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
|
|||
import { useAlive } from '../../../hooks/useAlive';
|
||||
import { useRoomCreators } from '../../../hooks/useRoomCreators';
|
||||
import { useRoomPermissions } from '../../../hooks/useRoomPermissions';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
type CreatePackTileProps = {
|
||||
packs: ImagePack[];
|
||||
|
|
@ -216,7 +215,6 @@ export function RoomPacks({ onViewPack }: RoomPacksProps) {
|
|||
{canEdit &&
|
||||
(removed ? (
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
size="300"
|
||||
radii="Pill"
|
||||
variant="Critical"
|
||||
|
|
@ -227,7 +225,6 @@ export function RoomPacks({ onViewPack }: RoomPacksProps) {
|
|||
</IconButton>
|
||||
) : (
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
size="300"
|
||||
radii="Pill"
|
||||
variant="Secondary"
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ import { useRoom } from '../../../hooks/useRoom';
|
|||
import { useStateEvent } from '../../../hooks/useStateEvent';
|
||||
import { stopPropagation } from '../../../utils/keyboard';
|
||||
import { RoomPermissionsAPI } from '../../../hooks/useRoomPermissions';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
const ROOM_ENC_ALGO = 'm.megolm.v1.aes-sha2';
|
||||
|
||||
|
|
@ -124,12 +123,7 @@ export function RoomEncryption({ permissions }: RoomEncryptionProps) {
|
|||
<Box grow="Yes">
|
||||
<Text size="H4">Enable Encryption</Text>
|
||||
</Box>
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
size="300"
|
||||
onClick={() => setPrompt(false)}
|
||||
radii="300"
|
||||
>
|
||||
<IconButton size="300" onClick={() => setPrompt(false)} radii="300">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ import { useAlive } from '../../../hooks/useAlive';
|
|||
import { creatorsSupported } from '../../../utils/matrix';
|
||||
import { useRoomCreators } from '../../../hooks/useRoomCreators';
|
||||
import { BreakWord } from '../../../styles/Text.css';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
function RoomUpgradeDialog({ requestClose }: { requestClose: () => void }) {
|
||||
const mx = useMatrixClient();
|
||||
|
|
@ -106,7 +105,7 @@ function RoomUpgradeDialog({ requestClose }: { requestClose: () => void }) {
|
|||
<Box grow="Yes">
|
||||
<Text size="H4">{room.isSpaceRoom() ? 'Space Upgrade' : 'Room Upgrade'}</Text>
|
||||
</Box>
|
||||
<IconButton className={PhoneHit} size="300" onClick={requestClose} radii="300">
|
||||
<IconButton size="300" onClick={requestClose} radii="300">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ import { useSpaceOptionally } from '../../../hooks/useSpace';
|
|||
import { useFlattenPowerTagMembers, useGetMemberPowerTag } from '../../../hooks/useMemberPowerTag';
|
||||
import { useRoomCreators } from '../../../hooks/useRoomCreators';
|
||||
import { getMouseEventCords } from '../../../utils/dom';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
const SEARCH_OPTIONS: UseAsyncSearchOptions = {
|
||||
limit: 1000,
|
||||
|
|
@ -162,7 +161,7 @@ export function Members({ requestClose }: MembersProps) {
|
|||
</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Surface">
|
||||
<IconButton onClick={requestClose} variant="Surface">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
@ -278,7 +277,6 @@ export function Members({ requestClose }: MembersProps) {
|
|||
anchorRef={scrollTopAnchorRef}
|
||||
>
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
onClick={() => virtualizer.scrollToOffset(0)}
|
||||
variant="Surface"
|
||||
radii="Pill"
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ import { useAlive } from '../../../hooks/useAlive';
|
|||
import { BetaNoticeBadge } from '../../../components/BetaNoticeBadge';
|
||||
import { getPowerTagIconSrc } from '../../../hooks/useMemberPowerTag';
|
||||
import { creatorsSupported } from '../../../utils/matrix';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
type EditPowerProps = {
|
||||
maxPower: number;
|
||||
|
|
@ -370,7 +369,7 @@ export function PowersEditor({ powerLevels, requestClose }: PowersEditorProps) {
|
|||
</Chip>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Surface">
|
||||
<IconButton onClick={requestClose} variant="Surface">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import {
|
|||
import { CreateRoomModalState } from '../../state/createRoomModal';
|
||||
import { stopPropagation } from '../../utils/keyboard';
|
||||
import { CreateRoomType } from '../../components/create-room/types';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
type CreateRoomModalProps = {
|
||||
state: CreateRoomModalState;
|
||||
|
|
@ -64,7 +63,7 @@ function CreateRoomModal({ state }: CreateRoomModalProps) {
|
|||
</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} size="300" radii="300" onClick={closeDialog}>
|
||||
<IconButton size="300" radii="300" onClick={closeDialog}>
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import {
|
|||
} from '../../state/hooks/createSpaceModal';
|
||||
import { CreateSpaceModalState } from '../../state/createSpaceModal';
|
||||
import { stopPropagation } from '../../utils/keyboard';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
type CreateSpaceModalProps = {
|
||||
state: CreateSpaceModalState;
|
||||
|
|
@ -62,7 +61,7 @@ function CreateSpaceModal({ state }: CreateSpaceModalProps) {
|
|||
<Text size="H4">New Space</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} size="300" radii="300" onClick={closeDialog}>
|
||||
<IconButton size="300" radii="300" onClick={closeDialog}>
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { Box, Icon, IconButton, Icons, Scroll, Text } from 'folds';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
import { Page, PageContent, PageContentCenter, PageHeader } from '../../components/page';
|
||||
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
|
||||
import { getHomePath } from '../../pages/pathUtils';
|
||||
|
|
@ -34,11 +33,7 @@ export function Desk() {
|
|||
<Box grow="Yes" alignItems="Center" gap="200">
|
||||
<Box grow="Yes" basis="No">
|
||||
{phone && (
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
aria-label="Back to rooms"
|
||||
onClick={() => navigate(getHomePath())}
|
||||
>
|
||||
<IconButton aria-label="Back to rooms" onClick={() => navigate(getHomePath())}>
|
||||
<Icon src={Icons.ArrowLeft} />
|
||||
</IconButton>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import { useMatrixClient } from '../../hooks/useMatrixClient';
|
|||
import { allRoomsAtom } from '../../state/room-list/roomList';
|
||||
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
|
||||
import { BackRouteHandler } from '../../components/BackRouteHandler';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
type JoinBeforeNavigateProps = { roomIdOrAlias: string; eventId?: string; viaServers?: string[] };
|
||||
export function JoinBeforeNavigate({
|
||||
|
|
@ -39,7 +38,7 @@ export function JoinBeforeNavigate({
|
|||
{screenSize === ScreenSize.Mobile && (
|
||||
<BackRouteHandler>
|
||||
{(onBack) => (
|
||||
<IconButton className={PhoneHit} onClick={onBack}>
|
||||
<IconButton onClick={onBack}>
|
||||
<Icon src={Icons.ArrowLeft} />
|
||||
</IconButton>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ import { IPowerLevels } from '../../hooks/usePowerLevels';
|
|||
import { getRoomCreatorsForRoomId } from '../../hooks/useRoomCreators';
|
||||
import { getRoomPermissionsAPI } from '../../hooks/useRoomPermissions';
|
||||
import { InviteUserPrompt } from '../../components/invite-user-prompt';
|
||||
import { PhoneHitSpread24 } from '../../styles/PhoneHit.css';
|
||||
|
||||
type HierarchyItemWithParent = HierarchyItem & {
|
||||
parentId: string;
|
||||
|
|
@ -232,7 +231,6 @@ export function HierarchyItemMenu({
|
|||
return (
|
||||
<Box gap="200" alignItems="Center" shrink="No">
|
||||
<IconButton
|
||||
className={PhoneHitSpread24}
|
||||
onClick={handleOpenMenu}
|
||||
size="300"
|
||||
variant="SurfaceVariant"
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ import { useGetRoom } from '../../hooks/useGetRoom';
|
|||
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
|
||||
import { getRoomPermissionsAPI } from '../../hooks/useRoomPermissions';
|
||||
import { getRoomCreatorsForRoomId } from '../../hooks/useRoomCreators';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
const useCanDropLobbyItem = (
|
||||
space: Room,
|
||||
|
|
@ -414,7 +413,6 @@ export function Lobby() {
|
|||
onVisibilityChange={setOnTop}
|
||||
>
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
onClick={() => virtualizer.scrollToOffset(0)}
|
||||
variant="SurfaceVariant"
|
||||
radii="Pill"
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ import { useOpenSpaceSettings } from '../../state/hooks/spaceSettings';
|
|||
import { useRoomCreators } from '../../hooks/useRoomCreators';
|
||||
import { useRoomPermissions } from '../../hooks/useRoomPermissions';
|
||||
import { InviteUserPrompt } from '../../components/invite-user-prompt';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
type LobbyMenuProps = {
|
||||
powerLevels: IPowerLevels;
|
||||
|
|
@ -166,7 +165,7 @@ export function LobbyHeader({ showProfile, powerLevels }: LobbyHeaderProps) {
|
|||
<Box shrink="No">
|
||||
<BackRouteHandler>
|
||||
{(onBack) => (
|
||||
<IconButton className={PhoneHit} fill="None" onClick={onBack}>
|
||||
<IconButton fill="None" onClick={onBack}>
|
||||
<Icon src={Icons.ArrowLeft} />
|
||||
</IconButton>
|
||||
)}
|
||||
|
|
@ -241,7 +240,6 @@ export function LobbyHeader({ showProfile, powerLevels }: LobbyHeaderProps) {
|
|||
>
|
||||
{(triggerRef) => (
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
fill="None"
|
||||
onClick={handleOpenMenu}
|
||||
ref={triggerRef}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import { SearchResultGroup } from './SearchResultGroup';
|
|||
import { SearchInput } from './SearchInput';
|
||||
import { SearchFilters } from './SearchFilters';
|
||||
import { VirtualTile } from '../../components/virtualizer';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
const useSearchPathSearchParams = (searchParams: URLSearchParams): _SearchPathSearchParams =>
|
||||
useMemo(
|
||||
|
|
@ -194,7 +193,6 @@ export function MessageSearch({
|
|||
<Box direction="Column" gap="700">
|
||||
<ScrollTopContainer scrollRef={scrollRef} anchorRef={scrollTopAnchorRef}>
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
onClick={() => virtualizer.scrollToOffset(0)}
|
||||
variant="SurfaceVariant"
|
||||
radii="Pill"
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@ import { useAutoDiscoveryInfo } from '../../hooks/useAutoDiscoveryInfo';
|
|||
import { livekitSupport } from '../../hooks/useLivekitSupport';
|
||||
import { StateEvent } from '../../../types/matrix/room';
|
||||
import { webRTCSupported } from '../../utils/rtc';
|
||||
import { PhoneHitSpread24 } from '../../styles/PhoneHit.css';
|
||||
|
||||
type RoomNavItemMenuProps = {
|
||||
room: Room;
|
||||
|
|
@ -230,7 +229,6 @@ function CallChatToggle() {
|
|||
|
||||
return (
|
||||
<IconButton
|
||||
className={PhoneHitSpread24}
|
||||
onClick={() => setChat(!chat)}
|
||||
aria-pressed={chat}
|
||||
aria-label="Toggle Chat"
|
||||
|
|
@ -438,7 +436,6 @@ export function RoomNavItem({
|
|||
}
|
||||
>
|
||||
<IconButton
|
||||
className={PhoneHitSpread24}
|
||||
onClick={handleOpenMenu}
|
||||
aria-pressed={!!menuAnchor}
|
||||
aria-controls={`menu-${room.roomId}`}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import { Permissions } from './permissions';
|
|||
import { RoomSettingsPage } from '../../state/roomSettings';
|
||||
import { useRoom } from '../../hooks/useRoom';
|
||||
import { DeveloperTools } from '../common-settings/developer-tools';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
type RoomSettingsMenuItem = {
|
||||
page: RoomSettingsPage;
|
||||
|
|
@ -118,7 +117,7 @@ export function RoomSettings({ initialPage, requestClose }: RoomSettingsProps) {
|
|||
</Box>
|
||||
<Box shrink="No">
|
||||
{screenSize === ScreenSize.Mobile && (
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Background">
|
||||
<IconButton onClick={requestClose} variant="Background">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import {
|
|||
} from '../../common-settings/general';
|
||||
import { useRoomCreators } from '../../../hooks/useRoomCreators';
|
||||
import { useRoomPermissions } from '../../../hooks/useRoomPermissions';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
type GeneralProps = {
|
||||
requestClose: () => void;
|
||||
|
|
@ -36,7 +35,7 @@ export function General({ requestClose }: GeneralProps) {
|
|||
</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Surface">
|
||||
<IconButton onClick={requestClose} variant="Surface">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import { usePermissionGroups } from './usePermissionItems';
|
|||
import { PermissionGroups, Powers, PowersEditor } from '../../common-settings/permissions';
|
||||
import { useRoomCreators } from '../../../hooks/useRoomCreators';
|
||||
import { useRoomPermissions } from '../../../hooks/useRoomPermissions';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
type PermissionsProps = {
|
||||
requestClose: () => void;
|
||||
|
|
@ -46,7 +45,7 @@ export function Permissions({ requestClose }: PermissionsProps) {
|
|||
</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Surface">
|
||||
<IconButton onClick={requestClose} variant="Surface">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import { Page, PageHeader } from '../../components/page';
|
|||
import { callChatAtom } from '../../state/callEmbed';
|
||||
import { RoomView } from './RoomView';
|
||||
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
export function CallChatView() {
|
||||
const { eventId } = useParams();
|
||||
|
|
@ -42,12 +41,7 @@ export function CallChatView() {
|
|||
}
|
||||
>
|
||||
{(triggerRef) => (
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
ref={triggerRef}
|
||||
variant="Surface"
|
||||
onClick={handleClose}
|
||||
>
|
||||
<IconButton ref={triggerRef} variant="Surface" onClick={handleClose}>
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ import { useSpaceOptionally } from '../../hooks/useSpace';
|
|||
import { ContainerColor } from '../../styles/ContainerColor.css';
|
||||
import { useFlattenPowerTagMembers, useGetMemberPowerTag } from '../../hooks/useMemberPowerTag';
|
||||
import { useRoomCreators } from '../../hooks/useRoomCreators';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
type MemberDrawerHeaderProps = {
|
||||
room: Room;
|
||||
|
|
@ -88,7 +87,6 @@ function MemberDrawerHeader({ room }: MemberDrawerHeaderProps) {
|
|||
>
|
||||
{(triggerRef) => (
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
ref={triggerRef}
|
||||
variant="Background"
|
||||
onClick={() => setPeopleDrawer(false)}
|
||||
|
|
@ -361,7 +359,6 @@ export function MembersDrawer({ room, members }: MembersDrawerProps) {
|
|||
|
||||
<ScrollTopContainer scrollRef={scrollRef} anchorRef={scrollTopAnchorRef}>
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
onClick={() => virtualizer.scrollToOffset(0)}
|
||||
variant="Surface"
|
||||
radii="Pill"
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@ import {
|
|||
config,
|
||||
toRem,
|
||||
} from 'folds';
|
||||
import { RoomOutbox } from './RoomOutbox';
|
||||
import { sendTracked } from '../../state/room/outboxSend';
|
||||
import { RoomOutbox, sendTracked } from './RoomOutbox';
|
||||
import { clearDraft, loadDraft, saveDraft } from '../../state/room/composerStore';
|
||||
|
||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||
|
|
@ -116,7 +115,6 @@ import { useTheme } from '../../hooks/useTheme';
|
|||
import { useRoomCreatorsTag } from '../../hooks/useRoomCreatorsTag';
|
||||
import { usePowerLevelTags } from '../../hooks/usePowerLevelTags';
|
||||
import { useComposingCheck } from '../../hooks/useComposingCheck';
|
||||
import { PhoneHitSpread24, PhoneHitSpread32 } from '../../styles/PhoneHit.css';
|
||||
|
||||
interface RoomInputProps {
|
||||
editor: Editor;
|
||||
|
|
@ -335,7 +333,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
|||
});
|
||||
handleCancelUpload(uploads);
|
||||
const contents = fulfilledPromiseSettledResult(await Promise.allSettled(contentsPromises));
|
||||
contents.forEach((content) => sendTracked(mx, roomId, content as Record<string, unknown>));
|
||||
contents.forEach((content) => mx.sendMessage(roomId, content as any));
|
||||
};
|
||||
|
||||
const submit = useCallback(() => {
|
||||
|
|
@ -494,7 +492,11 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
|||
await getImageUrlBlob(stickerUrl)
|
||||
);
|
||||
|
||||
sendTracked(mx, roomId, { body: label, url: mxc, info }, EventType.Sticker);
|
||||
mx.sendEvent(roomId, EventType.Sticker, {
|
||||
body: label,
|
||||
url: mxc,
|
||||
info,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
@ -606,7 +608,6 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
|||
style={{ padding: `${config.space.S200} ${config.space.S300} 0` }}
|
||||
>
|
||||
<IconButton
|
||||
className={PhoneHitSpread24}
|
||||
onClick={() => setReplyDraft(undefined)}
|
||||
variant="SurfaceVariant"
|
||||
size="300"
|
||||
|
|
@ -640,7 +641,6 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
|||
}
|
||||
before={
|
||||
<IconButton
|
||||
className={PhoneHitSpread32}
|
||||
onClick={() => pickFile('*')}
|
||||
variant="SurfaceVariant"
|
||||
size="300"
|
||||
|
|
@ -652,7 +652,6 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
|||
after={
|
||||
<>
|
||||
<IconButton
|
||||
className={PhoneHitSpread32}
|
||||
variant="SurfaceVariant"
|
||||
size="300"
|
||||
radii="300"
|
||||
|
|
@ -695,7 +694,6 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
|||
>
|
||||
{!hideStickerBtn && (
|
||||
<IconButton
|
||||
className={PhoneHitSpread32}
|
||||
aria-pressed={emojiBoardTab === EmojiBoardTab.Sticker}
|
||||
onClick={() => setEmojiBoardTab(EmojiBoardTab.Sticker)}
|
||||
variant="SurfaceVariant"
|
||||
|
|
@ -709,7 +707,6 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
|||
</IconButton>
|
||||
)}
|
||||
<IconButton
|
||||
className={PhoneHitSpread32}
|
||||
ref={emojiBtnRef}
|
||||
aria-pressed={
|
||||
hideStickerBtn ? !!emojiBoardTab : emojiBoardTab === EmojiBoardTab.Emoji
|
||||
|
|
@ -729,13 +726,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
|||
</PopOut>
|
||||
)}
|
||||
</UseStateProvider>
|
||||
<IconButton
|
||||
className={PhoneHitSpread32}
|
||||
onClick={submit}
|
||||
variant="SurfaceVariant"
|
||||
size="300"
|
||||
radii="300"
|
||||
>
|
||||
<IconButton onClick={submit} variant="SurfaceVariant" size="300" radii="300">
|
||||
<Icon src={Icons.Send} />
|
||||
</IconButton>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -1,102 +0,0 @@
|
|||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { enqueueOutbox, failOutbox, loadOutbox } from '../../state/room/composerStore';
|
||||
import { RoomOutbox } from './RoomOutbox';
|
||||
|
||||
// The component's hooks are held still (state is its initial value, effects do not run) so the element tree
|
||||
// it returns can be read and its click handlers called without a DOM.
|
||||
vi.mock('react', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('react')>();
|
||||
const useState = (init: unknown) => [
|
||||
typeof init === 'function' ? (init as () => unknown)() : init,
|
||||
() => undefined,
|
||||
];
|
||||
return {
|
||||
...actual,
|
||||
default: { ...actual, useState, useEffect: () => undefined },
|
||||
useState,
|
||||
useEffect: () => undefined,
|
||||
};
|
||||
});
|
||||
|
||||
type El = { props?: { children?: unknown; onClick?: () => void } };
|
||||
const flatten = (node: unknown): El[] => {
|
||||
if (Array.isArray(node)) return node.flatMap(flatten);
|
||||
if (node && typeof node === 'object') {
|
||||
const el = node as El;
|
||||
return [el, ...flatten(el.props?.children)];
|
||||
}
|
||||
return [];
|
||||
};
|
||||
const textOf = (node: unknown): string => {
|
||||
if (typeof node === 'string' || typeof node === 'number') return String(node);
|
||||
if (Array.isArray(node)) return node.map(textOf).join('');
|
||||
if (node && typeof node === 'object') return textOf((node as El).props?.children);
|
||||
return '';
|
||||
};
|
||||
/** The onClick of the chip whose label is `label`. */
|
||||
const clickOf = (tree: unknown, label: string) => {
|
||||
const chip = flatten(tree).find((e) => e.props?.onClick && textOf(e) === label);
|
||||
if (!chip?.props?.onClick) throw new Error(`no ${label} chip`);
|
||||
return chip.props.onClick;
|
||||
};
|
||||
|
||||
describe('RoomOutbox actions', () => {
|
||||
beforeEach(() => {
|
||||
const m = new Map<string, string>();
|
||||
vi.stubGlobal('localStorage', {
|
||||
getItem: (k: string) => m.get(k) ?? null,
|
||||
setItem: (k: string, v: string) => {
|
||||
m.set(k, v);
|
||||
},
|
||||
removeItem: (k: string) => {
|
||||
m.delete(k);
|
||||
},
|
||||
});
|
||||
enqueueOutbox('@a:x', { txnId: 'keep', roomId: '!r:x', content: { body: 'stay' } });
|
||||
enqueueOutbox('@a:x', { txnId: 'bad', roomId: '!r:x', content: { body: 'did not go' } });
|
||||
failOutbox('@a:x', 'bad', 'ECONNRESET');
|
||||
});
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
const mount = () => {
|
||||
const mx = {
|
||||
getUserId: () => '@a:x',
|
||||
makeTxnId: () => 'txn-new',
|
||||
getRoom: () => undefined,
|
||||
sendEvent: vi.fn().mockResolvedValue({ event_id: '$e' }),
|
||||
};
|
||||
const tree = (RoomOutbox as unknown as (p: unknown) => unknown)({ mx, roomId: '!r:x' });
|
||||
return { mx, tree };
|
||||
};
|
||||
|
||||
it('Discard removes that message from the outbox and no other', () => {
|
||||
const { mx, tree } = mount();
|
||||
// both entries are shown; the failed one is the one with Discard
|
||||
clickOf(tree, 'Discard')();
|
||||
expect(loadOutbox('@a:x').map((e) => e.txnId)).toEqual(['keep']);
|
||||
expect(mx.sendEvent).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Resend sends that message again and does not discard it first', async () => {
|
||||
const { mx, tree } = mount();
|
||||
// the server has not answered yet: the resend is in flight
|
||||
mx.sendEvent.mockReturnValue(
|
||||
new Promise<never>(() => {
|
||||
// never settles
|
||||
})
|
||||
);
|
||||
clickOf(tree, 'Resend')();
|
||||
await Promise.resolve();
|
||||
expect(mx.sendEvent).toHaveBeenCalledTimes(1);
|
||||
expect(mx.sendEvent).toHaveBeenCalledWith(
|
||||
'!r:x',
|
||||
'm.room.message',
|
||||
{ body: 'did not go' },
|
||||
'bad'
|
||||
);
|
||||
// still in the outbox, pending again under the same id, until the server confirms it
|
||||
expect(loadOutbox('@a:x').find((e) => e.txnId === 'bad')).toMatchObject({ status: 'pending' });
|
||||
});
|
||||
});
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
import React from 'react';
|
||||
import { renderToStaticMarkup } from 'react-dom/server';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { enqueueOutbox, failOutbox } from '../../state/room/composerStore';
|
||||
import { RoomOutbox } from './RoomOutbox';
|
||||
|
||||
// What the person sees under the timeline for sends the server has not confirmed.
|
||||
const text = (html: string) => html.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ');
|
||||
|
||||
describe('RoomOutbox as rendered', () => {
|
||||
beforeEach(() => {
|
||||
const m = new Map<string, string>();
|
||||
vi.stubGlobal('localStorage', {
|
||||
getItem: (k: string) => m.get(k) ?? null,
|
||||
setItem: (k: string, v: string) => {
|
||||
m.set(k, v);
|
||||
},
|
||||
removeItem: (k: string) => {
|
||||
m.delete(k);
|
||||
},
|
||||
});
|
||||
});
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
const mx = { getUserId: () => '@a:x' } as never;
|
||||
const entry = (txnId: string, roomId: string, body: string) => ({
|
||||
txnId,
|
||||
roomId,
|
||||
content: { body },
|
||||
});
|
||||
|
||||
it('renders nothing when the room has no unconfirmed sends', () => {
|
||||
enqueueOutbox('@a:x', entry('t1', '!other:x', 'elsewhere'));
|
||||
expect(renderToStaticMarkup(<RoomOutbox mx={mx} roomId="!r:x" />)).toBe('');
|
||||
});
|
||||
|
||||
it('shows a fresh send as Sending with its text and no Resend', () => {
|
||||
enqueueOutbox('@a:x', entry('t1', '!r:x', 'on its way'), Date.now() + 1000);
|
||||
const html = renderToStaticMarkup(<RoomOutbox mx={mx} roomId="!r:x" />);
|
||||
expect(html).toContain('data-outbox-status="pending"');
|
||||
expect(text(html)).toContain('Sending…');
|
||||
expect(text(html)).toContain('on its way');
|
||||
expect(text(html)).not.toContain('Resend');
|
||||
});
|
||||
|
||||
it('shows a failed send with its error, Resend and Discard', () => {
|
||||
enqueueOutbox('@a:x', entry('t2', '!r:x', 'did not go'));
|
||||
failOutbox('@a:x', 't2', 'ECONNRESET');
|
||||
const html = renderToStaticMarkup(<RoomOutbox mx={mx} roomId="!r:x" />);
|
||||
expect(html).toContain('data-outbox-status="failed"');
|
||||
expect(text(html)).toContain('Not sent: ECONNRESET');
|
||||
expect(text(html)).toContain('Resend');
|
||||
expect(text(html)).toContain('Discard');
|
||||
});
|
||||
|
||||
it('shows a send left over from before this page load as interrupted, resendable', () => {
|
||||
enqueueOutbox('@a:x', entry('t3', '!r:x', 'lost to a reload'), 5);
|
||||
const html = renderToStaticMarkup(<RoomOutbox mx={mx} roomId="!r:x" />);
|
||||
expect(text(html)).toContain('Interrupted by a reload');
|
||||
expect(text(html)).toContain('Resend');
|
||||
});
|
||||
});
|
||||
|
|
@ -1,28 +1,57 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { SLOW_SEND_MS, outboxView } from './RoomOutbox';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { loadOutbox } from '../../state/room/composerStore';
|
||||
import { sendTracked } from './RoomOutbox';
|
||||
|
||||
describe('outboxView', () => {
|
||||
it('walks sending -> still sending (resendable) -> failed', () => {
|
||||
expect(outboxView({ status: 'pending', ts: 100 }, 100, 0)).toMatchObject({
|
||||
label: 'Sending…',
|
||||
canResend: false,
|
||||
});
|
||||
expect(outboxView({ status: 'pending', ts: 100 }, 100 + SLOW_SEND_MS, 0)).toMatchObject({
|
||||
label: expect.stringMatching(/^Still sending/),
|
||||
canResend: true,
|
||||
});
|
||||
expect(outboxView({ status: 'failed', ts: 100, error: 'x' }, 100, 0)).toMatchObject({
|
||||
failed: true,
|
||||
canResend: true,
|
||||
});
|
||||
const stubLocalStorage = () => {
|
||||
const m = new Map<string, string>();
|
||||
vi.stubGlobal('localStorage', {
|
||||
getItem: (k: string) => m.get(k) ?? null,
|
||||
setItem: (k: string, v: string) => {
|
||||
m.set(k, v);
|
||||
},
|
||||
removeItem: (k: string) => {
|
||||
m.delete(k);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const fakeClient = (send: (...a: unknown[]) => Promise<unknown>) =>
|
||||
({ getUserId: () => '@a:x', makeTxnId: () => 'txn-1', sendMessage: send } as never);
|
||||
|
||||
describe('sendTracked', () => {
|
||||
beforeEach(stubLocalStorage);
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
it('offers Resend to a pending send at 30 s and not a millisecond before', () => {
|
||||
const at = (ms: number) => outboxView({ status: 'pending', ts: 100 }, 100 + ms, 0).canResend;
|
||||
expect([at(29_999), at(30_000)]).toEqual([false, true]);
|
||||
const content = { msgtype: 'm.text', body: 'typed before reload' };
|
||||
|
||||
it('holds the message in the outbox while the send is in flight, so a reload keeps it', async () => {
|
||||
let finish!: () => void;
|
||||
const mx = fakeClient(
|
||||
() =>
|
||||
new Promise((r) => {
|
||||
finish = () => r({ event_id: '$e' });
|
||||
})
|
||||
);
|
||||
const done = sendTracked(mx, '!r:x', content);
|
||||
expect(loadOutbox('@a:x')).toMatchObject([{ txnId: 'txn-1', status: 'pending', content }]);
|
||||
finish();
|
||||
await done;
|
||||
expect(loadOutbox('@a:x')).toEqual([]);
|
||||
});
|
||||
|
||||
it('an entry older than this page load reads as interrupted', () => {
|
||||
expect(outboxView({ status: 'pending', ts: 5 }, 6, 10).label).toMatch(/Interrupted/);
|
||||
it('a failed send stays, marked failed, and is not cleared', async () => {
|
||||
const mx = fakeClient(() => Promise.reject(new Error('ECONNRESET')));
|
||||
await sendTracked(mx, '!r:x', content);
|
||||
expect(loadOutbox('@a:x')).toMatchObject([
|
||||
{ txnId: 'txn-1', status: 'failed', error: 'ECONNRESET', content },
|
||||
]);
|
||||
});
|
||||
|
||||
it('sends under the stored txn id, so a resend after an unknown outcome deduplicates', async () => {
|
||||
const send = vi.fn().mockResolvedValue({});
|
||||
await sendTracked(fakeClient(send), '!r:x', content);
|
||||
expect(send).toHaveBeenCalledWith('!r:x', content, 'txn-1');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,44 +3,32 @@ import { MatrixClient } from 'matrix-js-sdk';
|
|||
import { Box, Chip, Text, color, config } from 'folds';
|
||||
import {
|
||||
OutboxEntry,
|
||||
enqueueOutbox,
|
||||
failOutbox,
|
||||
loadOutbox,
|
||||
removeOutbox,
|
||||
retryOutbox,
|
||||
subscribeOutbox,
|
||||
} from '../../state/room/composerStore';
|
||||
import { PAGE_START, resendTracked } from '../../state/room/outboxSend';
|
||||
|
||||
/** A send still unconfirmed after this long is offered Resend: the request may be hung. */
|
||||
export const SLOW_SEND_MS = 30_000;
|
||||
const attempt = (mx: MatrixClient, userId: string, entry: OutboxEntry): Promise<void> =>
|
||||
mx
|
||||
.sendMessage(entry.roomId, entry.content as never, entry.txnId)
|
||||
.then(() => removeOutbox(userId, entry.txnId))
|
||||
.catch((e: unknown) =>
|
||||
failOutbox(userId, entry.txnId, e instanceof Error ? e.message : String(e))
|
||||
);
|
||||
|
||||
export type OutboxView = { label: string; failed: boolean; canResend: boolean };
|
||||
|
||||
export const outboxView = (
|
||||
entry: Pick<OutboxEntry, 'status' | 'ts' | 'error'>,
|
||||
now: number,
|
||||
since: number = PAGE_START
|
||||
): OutboxView => {
|
||||
if (entry.status === 'failed') {
|
||||
return {
|
||||
label: `Not sent${entry.error ? `: ${entry.error}` : ''}`,
|
||||
failed: true,
|
||||
canResend: true,
|
||||
};
|
||||
}
|
||||
if (entry.ts < since) {
|
||||
return {
|
||||
label: 'Interrupted by a reload: may not have been sent',
|
||||
failed: false,
|
||||
canResend: true,
|
||||
};
|
||||
}
|
||||
if (now - entry.ts >= SLOW_SEND_MS) {
|
||||
return {
|
||||
label: 'Still sending: slow connection (Resend may duplicate it if it lands later)',
|
||||
failed: false,
|
||||
canResend: true,
|
||||
};
|
||||
}
|
||||
return { label: 'Sending…', failed: false, canResend: false };
|
||||
/** Send a message, keeping it in the durable outbox until the server confirms it. */
|
||||
export const sendTracked = (
|
||||
mx: MatrixClient,
|
||||
roomId: string,
|
||||
content: Record<string, unknown>
|
||||
): Promise<void> => {
|
||||
const userId = mx.getUserId() ?? '';
|
||||
const entry = { roomId, content, txnId: mx.makeTxnId() };
|
||||
enqueueOutbox(userId, entry);
|
||||
return attempt(mx, userId, { ...entry, status: 'pending', ts: Date.now() });
|
||||
};
|
||||
|
||||
export const useRoomOutbox = (userId: string, roomId: string): OutboxEntry[] => {
|
||||
|
|
@ -54,28 +42,19 @@ export const useRoomOutbox = (userId: string, roomId: string): OutboxEntry[] =>
|
|||
return entries;
|
||||
};
|
||||
|
||||
/** Re-render every few seconds while anything is waiting, so a slow send turns resendable. */
|
||||
const useNow = (active: boolean): number => {
|
||||
const [now, setNow] = useState(Date.now());
|
||||
useEffect(() => {
|
||||
if (!active) return undefined;
|
||||
setNow(Date.now());
|
||||
const id = setInterval(() => setNow(Date.now()), 5000);
|
||||
return () => clearInterval(id);
|
||||
}, [active]);
|
||||
return now;
|
||||
};
|
||||
/** Entries still 'pending' that predate this page load lost their promise in a reload: outcome unknown. */
|
||||
const pageStart = Date.now();
|
||||
|
||||
type RoomOutboxProps = { mx: MatrixClient; roomId: string };
|
||||
|
||||
/**
|
||||
* Messages this client sent that the server has not confirmed: sending, slow, interrupted by a
|
||||
* reload, or failed, each with Resend where one makes sense and Discard.
|
||||
* Messages this client sent that the server has not confirmed: still sending, or failed.
|
||||
* They also appear here after a reload, since the outbox is durable. Resending reuses the
|
||||
* original txn id, so a send that did land the first time is not duplicated.
|
||||
*/
|
||||
export function RoomOutbox({ mx, roomId }: RoomOutboxProps) {
|
||||
const userId = mx.getUserId() ?? '';
|
||||
const entries = useRoomOutbox(userId, roomId);
|
||||
const now = useNow(entries.length > 0);
|
||||
if (entries.length === 0) return null;
|
||||
|
||||
return (
|
||||
|
|
@ -85,32 +64,40 @@ export function RoomOutbox({ mx, roomId }: RoomOutboxProps) {
|
|||
style={{ padding: `${config.space.S200} ${config.space.S300} 0` }}
|
||||
>
|
||||
{entries.map((entry) => {
|
||||
const view = outboxView(entry, now);
|
||||
const failed = entry.status === 'failed';
|
||||
const interrupted = !failed && entry.ts < pageStart;
|
||||
const canResend = failed || interrupted;
|
||||
return (
|
||||
<Box key={entry.txnId} alignItems="Center" gap="200" data-outbox-status={entry.status}>
|
||||
<Box grow="Yes" direction="Column">
|
||||
<Text
|
||||
size="T200"
|
||||
style={{ color: view.failed ? color.Critical.Main : color.Surface.OnContainer }}
|
||||
style={{ color: failed ? color.Critical.Main : color.Surface.OnContainer }}
|
||||
>
|
||||
{view.label}
|
||||
{(() => {
|
||||
if (failed) return `Not sent${entry.error ? `: ${entry.error}` : ''}`;
|
||||
return interrupted ? 'Interrupted by a reload: may not have been sent' : 'Sending…';
|
||||
})()}
|
||||
</Text>
|
||||
<Text size="T300" truncate>
|
||||
{String(entry.content.body ?? '')}
|
||||
</Text>
|
||||
</Box>
|
||||
{view.canResend && (
|
||||
{canResend && (
|
||||
<>
|
||||
<Chip variant="Surface" radii="Pill" onClick={() => resendTracked(mx, entry)}>
|
||||
<Text size="B300">Resend</Text>
|
||||
</Chip>
|
||||
<Chip
|
||||
variant="Surface"
|
||||
radii="Pill"
|
||||
onClick={() => removeOutbox(userId, entry.txnId)}
|
||||
>
|
||||
<Text size="B300">Discard</Text>
|
||||
</Chip>
|
||||
<Chip
|
||||
variant="Surface"
|
||||
radii="Pill"
|
||||
onClick={() => {
|
||||
retryOutbox(userId, entry.txnId);
|
||||
attempt(mx, userId, entry);
|
||||
}}
|
||||
>
|
||||
<Text size="B300">Resend</Text>
|
||||
</Chip>
|
||||
<Chip variant="Surface" radii="Pill" onClick={() => removeOutbox(userId, entry.txnId)}>
|
||||
<Text size="B300">Discard</Text>
|
||||
</Chip>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ import {
|
|||
import { isKeyHotkey } from 'is-hotkey';
|
||||
import { Opts as LinkifyOpts } from 'linkifyjs';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { isUnconfirmedLocalEcho } from './localEcho';
|
||||
import { eventWithShortcode, factoryEventSentBy, getMxIdLocalPart } from '../../utils/matrix';
|
||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||
import { useVirtualPaginator, ItemRange } from '../../hooks/useVirtualPaginator';
|
||||
|
|
@ -390,19 +389,6 @@ const useLiveEventArrive = (room: Room, onArrive: (mEvent: MatrixEvent) => void)
|
|||
}, [room, onArrive]);
|
||||
};
|
||||
|
||||
/** A local echo changes status (or becomes its remote echo) without a Timeline event: redraw. */
|
||||
const useLocalEchoRefresh = (room: Room, onUpdate: () => void) => {
|
||||
useEffect(() => {
|
||||
const handle: RoomEventHandlerMap[RoomEvent.LocalEchoUpdated] = (_evt, r) => {
|
||||
if (r.roomId === room.roomId) onUpdate();
|
||||
};
|
||||
room.on(RoomEvent.LocalEchoUpdated, handle);
|
||||
return () => {
|
||||
room.removeListener(RoomEvent.LocalEchoUpdated, handle);
|
||||
};
|
||||
}, [room, onUpdate]);
|
||||
};
|
||||
|
||||
const useLiveTimelineRefresh = (room: Room, onRefresh: () => void) => {
|
||||
useEffect(() => {
|
||||
const handleTimelineRefresh: RoomEventHandlerMap[RoomEvent.TimelineRefresh] = (r) => {
|
||||
|
|
@ -662,18 +648,6 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
|
|||
)
|
||||
);
|
||||
|
||||
useLocalEchoRefresh(
|
||||
room,
|
||||
useCallback(() => {
|
||||
// the echo was hidden while unconfirmed, so its arrival scrolled to nothing: scroll now
|
||||
if (atBottomRef.current) {
|
||||
scrollToBottomRef.current.count += 1;
|
||||
scrollToBottomRef.current.smooth = true;
|
||||
}
|
||||
setTimeline((ct) => ({ ...ct }));
|
||||
}, [])
|
||||
);
|
||||
|
||||
const handleOpenEvent = useCallback(
|
||||
async (
|
||||
evtId: string,
|
||||
|
|
@ -1672,7 +1646,6 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
|
|||
if (mEvent.isRedacted() && !showHiddenEvents) {
|
||||
return null;
|
||||
}
|
||||
if (isUnconfirmedLocalEcho(mEvent)) return null;
|
||||
|
||||
if (!newDivider && readUptoEventIdRef.current) {
|
||||
newDivider = prevEvent?.getId() === readUptoEventIdRef.current;
|
||||
|
|
|
|||
|
|
@ -72,7 +72,6 @@ import { RoomSettingsPage } from '../../state/roomSettings';
|
|||
import { useCallEmbed, useCallStart } from '../../hooks/useCallEmbed';
|
||||
import { useLivekitSupport } from '../../hooks/useLivekitSupport';
|
||||
import { webRTCSupported } from '../../utils/rtc';
|
||||
import { PhoneHitSpread40 } from '../../styles/PhoneHit.css';
|
||||
|
||||
type RoomMenuProps = {
|
||||
room: Room;
|
||||
|
|
@ -337,7 +336,6 @@ function CallButton() {
|
|||
>
|
||||
{(triggerRef) => (
|
||||
<IconButton
|
||||
className={PhoneHitSpread40}
|
||||
variant="Surface"
|
||||
fill="None"
|
||||
ref={triggerRef}
|
||||
|
|
@ -457,7 +455,7 @@ export function RoomViewHeader({ callView }: { callView?: boolean }) {
|
|||
<BackRouteHandler>
|
||||
{(onBack) => (
|
||||
<Box shrink="No" alignItems="Center">
|
||||
<IconButton className={PhoneHitSpread40} fill="None" onClick={onBack}>
|
||||
<IconButton fill="None" onClick={onBack}>
|
||||
<Icon src={Icons.ArrowLeft} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
@ -533,12 +531,7 @@ export function RoomViewHeader({ callView }: { callView?: boolean }) {
|
|||
}
|
||||
>
|
||||
{(triggerRef) => (
|
||||
<IconButton
|
||||
className={PhoneHitSpread40}
|
||||
fill="None"
|
||||
ref={triggerRef}
|
||||
onClick={handleSearchClick}
|
||||
>
|
||||
<IconButton fill="None" ref={triggerRef} onClick={handleSearchClick}>
|
||||
<Icon size="400" src={Icons.Search} />
|
||||
</IconButton>
|
||||
)}
|
||||
|
|
@ -555,7 +548,6 @@ export function RoomViewHeader({ callView }: { callView?: boolean }) {
|
|||
>
|
||||
{(triggerRef) => (
|
||||
<IconButton
|
||||
className={PhoneHitSpread40}
|
||||
fill="None"
|
||||
style={{ position: 'relative' }}
|
||||
onClick={handleOpenPinMenu}
|
||||
|
|
@ -620,12 +612,7 @@ export function RoomViewHeader({ callView }: { callView?: boolean }) {
|
|||
}
|
||||
>
|
||||
{(triggerRef) => (
|
||||
<IconButton
|
||||
className={PhoneHitSpread40}
|
||||
fill="None"
|
||||
ref={triggerRef}
|
||||
onClick={handleMemberToggle}
|
||||
>
|
||||
<IconButton fill="None" ref={triggerRef} onClick={handleMemberToggle}>
|
||||
<Icon size="400" src={Icons.User} />
|
||||
</IconButton>
|
||||
)}
|
||||
|
|
@ -644,7 +631,6 @@ export function RoomViewHeader({ callView }: { callView?: boolean }) {
|
|||
>
|
||||
{(triggerRef) => (
|
||||
<IconButton
|
||||
className={PhoneHitSpread40}
|
||||
fill="None"
|
||||
onClick={handleOpenMenu}
|
||||
ref={triggerRef}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import { getMxIdLocalPart } from '../../utils/matrix';
|
|||
import * as css from './RoomViewTyping.css';
|
||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||
import { useRoomTypingMember } from '../../hooks/useRoomTypingMembers';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
export type RoomViewTypingProps = {
|
||||
room: Room;
|
||||
|
|
@ -112,13 +111,7 @@ export const RoomViewTyping = as<'div', RoomViewTypingProps>(
|
|||
</>
|
||||
)}
|
||||
</Text>
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
title="Drop Typing Status"
|
||||
size="300"
|
||||
radii="Pill"
|
||||
onClick={handleDropAll}
|
||||
>
|
||||
<IconButton title="Drop Typing Status" size="300" radii="Pill" onClick={handleDropAll}>
|
||||
<Icon size="50" src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ import { getToday, getYesterday, timeDayMonthYear, timeHourMinute } from '../../
|
|||
import { DatePicker, TimePicker } from '../../../components/time-date';
|
||||
import { useSetting } from '../../../state/hooks/settings';
|
||||
import { settingsAtom } from '../../../state/settings';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
type JumpToTimeProps = {
|
||||
onCancel: () => void;
|
||||
|
|
@ -109,7 +108,7 @@ export function JumpToTime({ onCancel, onSubmit }: JumpToTimeProps) {
|
|||
<Box grow="Yes">
|
||||
<Text size="H4">Jump to Time</Text>
|
||||
</Box>
|
||||
<IconButton className={PhoneHit} size="300" onClick={onCancel} radii="300">
|
||||
<IconButton size="300" onClick={onCancel} radii="300">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { EventStatus } from 'matrix-js-sdk';
|
||||
import { isUnconfirmedLocalEcho } from './localEcho';
|
||||
|
||||
describe('isUnconfirmedLocalEcho', () => {
|
||||
it.each([
|
||||
EventStatus.ENCRYPTING,
|
||||
EventStatus.QUEUED,
|
||||
EventStatus.SENDING,
|
||||
EventStatus.NOT_SENT,
|
||||
EventStatus.CANCELLED,
|
||||
])('hides %s', (status) => {
|
||||
expect(isUnconfirmedLocalEcho({ status })).toBe(true);
|
||||
});
|
||||
|
||||
it('shows a server-confirmed event and one the server has accepted (SENT)', () => {
|
||||
expect(isUnconfirmedLocalEcho({ status: null })).toBe(false);
|
||||
expect(isUnconfirmedLocalEcho({ status: EventStatus.SENT })).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
import { EventStatus, MatrixEvent } from 'matrix-js-sdk';
|
||||
|
||||
/**
|
||||
* A local echo the server has not accepted: the SDK adds it to the live timeline the moment
|
||||
* sendMessage is called, marks it NOT_SENT on failure, and drops it on reload. Rendered like
|
||||
* any message it looks delivered and then vanishes. The outbox (RoomOutbox) is the one place
|
||||
* that shows unconfirmed sends, so the timeline hides these until the status is SENT.
|
||||
*/
|
||||
export const isUnconfirmedLocalEcho = (mEvent: Pick<MatrixEvent, 'status'>): boolean =>
|
||||
mEvent.status !== null && mEvent.status !== undefined && mEvent.status !== EventStatus.SENT;
|
||||
|
|
@ -86,7 +86,6 @@ import colorMXID from '../../../../util/colorMXID';
|
|||
import { useSkyInk } from '../../../hooks/useTheme';
|
||||
import { userColorInk } from '../../scene/skyInk';
|
||||
import { getPowerTagIconSrc } from '../../../hooks/useMemberPowerTag';
|
||||
import { PhoneHitRoom26, PhoneHitSpread32 } from '../../../styles/PhoneHit.css';
|
||||
|
||||
export type ReactionHandler = (keyOrMxc: string, shortcode: string) => void;
|
||||
|
||||
|
|
@ -112,7 +111,7 @@ export const MessageQuickReactions = as<'div', MessageQuickReactionsProps>(
|
|||
{recentEmojis.map((emoji) => (
|
||||
<IconButton
|
||||
key={emoji.unicode}
|
||||
className={classNames(css.MessageQuickReaction, PhoneHitSpread32)}
|
||||
className={css.MessageQuickReaction}
|
||||
size="300"
|
||||
variant="SurfaceVariant"
|
||||
radii="Pill"
|
||||
|
|
@ -460,12 +459,7 @@ export const MessageDeleteItem = as<
|
|||
<Box grow="Yes">
|
||||
<Text size="H4">Delete Message</Text>
|
||||
</Box>
|
||||
<IconButton
|
||||
className={PhoneHitSpread32}
|
||||
size="300"
|
||||
onClick={handleClose}
|
||||
radii="300"
|
||||
>
|
||||
<IconButton size="300" onClick={handleClose} radii="300">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
@ -595,12 +589,7 @@ export const MessageReportItem = as<
|
|||
<Box grow="Yes">
|
||||
<Text size="H4">Report Message</Text>
|
||||
</Box>
|
||||
<IconButton
|
||||
className={PhoneHitSpread32}
|
||||
size="300"
|
||||
onClick={handleClose}
|
||||
radii="300"
|
||||
>
|
||||
<IconButton size="300" onClick={handleClose} radii="300">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
@ -961,7 +950,6 @@ export const Message = as<'div', MessageProps>(
|
|||
}
|
||||
>
|
||||
<IconButton
|
||||
className={PhoneHitRoom26}
|
||||
onClick={handleOpenEmojiBoard}
|
||||
variant="SurfaceVariant"
|
||||
size="300"
|
||||
|
|
@ -973,7 +961,6 @@ export const Message = as<'div', MessageProps>(
|
|||
</PopOut>
|
||||
)}
|
||||
<IconButton
|
||||
className={PhoneHitRoom26}
|
||||
onClick={onReplyClick}
|
||||
data-event-id={mEvent.getId()}
|
||||
variant="SurfaceVariant"
|
||||
|
|
@ -984,7 +971,6 @@ export const Message = as<'div', MessageProps>(
|
|||
</IconButton>
|
||||
{!isThreadedMessage && (
|
||||
<IconButton
|
||||
className={PhoneHitRoom26}
|
||||
onClick={(ev) => onReplyClick(ev, true)}
|
||||
data-event-id={mEvent.getId()}
|
||||
variant="SurfaceVariant"
|
||||
|
|
@ -996,7 +982,6 @@ export const Message = as<'div', MessageProps>(
|
|||
)}
|
||||
{canEditEvent(mx, mEvent) && onEditId && (
|
||||
<IconButton
|
||||
className={PhoneHitRoom26}
|
||||
onClick={() => onEditId(mEvent.getId())}
|
||||
variant="SurfaceVariant"
|
||||
size="300"
|
||||
|
|
@ -1162,7 +1147,6 @@ export const Message = as<'div', MessageProps>(
|
|||
}
|
||||
>
|
||||
<IconButton
|
||||
className={PhoneHitRoom26}
|
||||
variant="SurfaceVariant"
|
||||
size="300"
|
||||
radii="300"
|
||||
|
|
@ -1336,7 +1320,6 @@ export const Event = as<'div', EventProps>(
|
|||
}
|
||||
>
|
||||
<IconButton
|
||||
className={PhoneHitRoom26}
|
||||
variant="SurfaceVariant"
|
||||
size="300"
|
||||
radii="300"
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
|||
import { getEditedEvent, getMentionContent, trimReplyFromFormattedBody } from '../../../utils/room';
|
||||
import { mobileOrTablet } from '../../../utils/user-agent';
|
||||
import { useComposingCheck } from '../../../hooks/useComposingCheck';
|
||||
import { PhoneHitSpread32 } from '../../../styles/PhoneHit.css';
|
||||
|
||||
type MessageEditorProps = {
|
||||
roomId: string;
|
||||
|
|
@ -290,7 +289,6 @@ export const MessageEditor = as<'div', MessageEditorProps>(
|
|||
</Box>
|
||||
<Box gap="Inherit">
|
||||
<IconButton
|
||||
className={PhoneHitSpread32}
|
||||
variant="SurfaceVariant"
|
||||
size="300"
|
||||
radii="300"
|
||||
|
|
@ -324,7 +322,6 @@ export const MessageEditor = as<'div', MessageEditorProps>(
|
|||
}
|
||||
>
|
||||
<IconButton
|
||||
className={PhoneHitSpread32}
|
||||
aria-pressed={anchor !== undefined}
|
||||
onClick={
|
||||
((evt) =>
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ import { useMediaAuthentication } from '../../../hooks/useMediaAuthentication';
|
|||
import { useOpenUserRoomProfile } from '../../../state/hooks/userRoomProfile';
|
||||
import { useSpaceOptionally } from '../../../hooks/useSpace';
|
||||
import { getMouseEventCords } from '../../../utils/dom';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
export type ReactionViewerProps = {
|
||||
room: Room;
|
||||
|
|
@ -101,7 +100,7 @@ export const ReactionViewer = as<'div', ReactionViewerProps>(
|
|||
<Box grow="Yes">
|
||||
<Text size="H3" truncate>{`Reacted with :${selectedShortcode}:`}</Text>
|
||||
</Box>
|
||||
<IconButton className={PhoneHit} size="300" onClick={requestClose}>
|
||||
<IconButton size="300" onClick={requestClose}>
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
|
|||
|
|
@ -86,7 +86,6 @@ import {
|
|||
useGetMemberPowerTag,
|
||||
} from '../../../hooks/useMemberPowerTag';
|
||||
import { useRoomCreatorsTag } from '../../../hooks/useRoomCreatorsTag';
|
||||
import { PhoneHit, PhoneHitSpread26 } from '../../../styles/PhoneHit.css';
|
||||
|
||||
type PinnedMessageProps = {
|
||||
room: Room;
|
||||
|
|
@ -147,7 +146,6 @@ function PinnedMessage({
|
|||
</Chip>
|
||||
{canPinEvent && (
|
||||
<IconButton
|
||||
className={PhoneHitSpread26}
|
||||
data-event-id={eventId}
|
||||
variant="Secondary"
|
||||
size="300"
|
||||
|
|
@ -459,7 +457,7 @@ export const RoomPinMenu = forwardRef<HTMLDivElement, RoomPinMenuProps>(
|
|||
<Text size="H5">Pinned Messages</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} size="300" onClick={requestClose} radii="300">
|
||||
<IconButton size="300" onClick={requestClose} radii="300">
|
||||
<Icon src={Icons.Cross} size="400" />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ import {
|
|||
setSceneStyle,
|
||||
type ServedSceneStyle,
|
||||
} from './sceneStyle';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
const STYLE_LABEL: Record<ServedSceneStyle, string> = { terrain: 'Terrain', ridge: 'Ridges' };
|
||||
|
||||
|
|
@ -150,7 +149,6 @@ export function SkyStateControl() {
|
|||
}
|
||||
>
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
variant="Background"
|
||||
aria-label={`Sky: ${LABEL[state]}`}
|
||||
title={`Sky: ${LABEL[state]}`}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ import { About } from './about';
|
|||
import { UseStateProvider } from '../../components/UseStateProvider';
|
||||
import { stopPropagation } from '../../utils/keyboard';
|
||||
import { LogoutDialog } from '../../components/LogoutDialog';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
export enum SettingsPages {
|
||||
GeneralPage,
|
||||
|
|
@ -142,7 +141,7 @@ export function Settings({ initialPage, requestClose }: SettingsProps) {
|
|||
</Box>
|
||||
<Box shrink="No">
|
||||
{screenSize === ScreenSize.Mobile && (
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Background">
|
||||
<IconButton onClick={requestClose} variant="Background">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import { LogoMark } from '../../../components/logo/logoMark.css';
|
|||
import RatatoskrSVG from '../../../../../public/res/svg/ratatoskr.svg';
|
||||
import { clearCacheAndReload } from '../../../../client/initMatrix';
|
||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
type AboutProps = {
|
||||
requestClose: () => void;
|
||||
|
|
@ -26,7 +25,7 @@ export function About({ requestClose }: AboutProps) {
|
|||
</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Surface">
|
||||
<IconButton onClick={requestClose} variant="Surface">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import { MatrixId } from './MatrixId';
|
|||
import { Profile } from './Profile';
|
||||
import { ContactInformation } from './ContactInfo';
|
||||
import { IgnoredUserList } from './IgnoredUserList';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
type AccountProps = {
|
||||
requestClose: () => void;
|
||||
|
|
@ -21,7 +20,7 @@ export function Account({ requestClose }: AccountProps) {
|
|||
</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Surface">
|
||||
<IconButton onClick={requestClose} variant="Surface">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
|
|||
import { isUserId } from '../../../utils/matrix';
|
||||
import { useIgnoredUsers } from '../../../hooks/useIgnoredUsers';
|
||||
import { useAlive } from '../../../hooks/useAlive';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
function IgnoreUserInput({ userList }: { userList: string[] }) {
|
||||
const mx = useMatrixClient();
|
||||
|
|
@ -68,7 +67,6 @@ function IgnoreUserInput({ userList }: { userList: string[] }) {
|
|||
userId &&
|
||||
!ignoring && (
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
type="reset"
|
||||
onClick={handleReset}
|
||||
size="300"
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ import { ModalWide } from '../../../styles/Modal.css';
|
|||
import { createUploadAtom, UploadSuccess } from '../../../state/upload';
|
||||
import { CompactUploadCardRenderer } from '../../../components/upload-card';
|
||||
import { useCapabilities } from '../../../hooks/useCapabilities';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
type ProfileProps = {
|
||||
profile: UserProfile;
|
||||
|
|
@ -186,12 +185,7 @@ function ProfileAvatar({ profile, userId }: ProfileProps) {
|
|||
<Box grow="Yes">
|
||||
<Text size="H4">Remove Avatar</Text>
|
||||
</Box>
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
size="300"
|
||||
onClick={() => setAlertRemove(false)}
|
||||
radii="300"
|
||||
>
|
||||
<IconButton size="300" onClick={() => setAlertRemove(false)} radii="300">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
@ -279,7 +273,6 @@ function ProfileDisplayName({ profile, userId }: ProfileProps) {
|
|||
hasChanges &&
|
||||
!changingDisplayName && (
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
type="reset"
|
||||
onClick={handleReset}
|
||||
size="300"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import {
|
|||
} from '../../../components/AccountDataEditor';
|
||||
import { copyToClipboard } from '../../../utils/dom';
|
||||
import { AccountData } from './AccountData';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
type DeveloperToolsProps = {
|
||||
requestClose: () => void;
|
||||
|
|
@ -52,7 +51,7 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
|||
</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Surface">
|
||||
<IconButton onClick={requestClose} variant="Surface">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ import { LogoutDialog } from '../../../components/LogoutDialog';
|
|||
import { stopPropagation } from '../../../utils/keyboard';
|
||||
import { useSetting } from '../../../state/hooks/settings';
|
||||
import { settingsAtom } from '../../../state/settings';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
export function DeviceTilePlaceholder() {
|
||||
return (
|
||||
|
|
@ -289,7 +288,6 @@ export function DeviceTile({
|
|||
<SettingTile
|
||||
before={
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
variant={deleted ? 'Critical' : 'Secondary'}
|
||||
outlined={deleted}
|
||||
radii="300"
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import {
|
|||
} from '../../../hooks/useSecretStorage';
|
||||
import { useCrossSigningActive } from '../../../hooks/useCrossSigning';
|
||||
import { BackupRestoreTile } from '../../../components/BackupRestore';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
function DevicesPlaceholder() {
|
||||
return (
|
||||
|
|
@ -75,7 +74,7 @@ export function Devices({ requestClose }: DevicesProps) {
|
|||
</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Surface">
|
||||
<IconButton onClick={requestClose} variant="Surface">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ import { stopPropagation } from '../../../utils/keyboard';
|
|||
import { useAuthMetadata } from '../../../hooks/useAuthMetadata';
|
||||
import { withSearchParam } from '../../../pages/pathUtils';
|
||||
import { useAccountManagementActions } from '../../../hooks/useAccountManagement';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
type VerificationStatusBadgeProps = {
|
||||
verificationStatus: VerificationStatus;
|
||||
|
|
@ -289,7 +288,6 @@ export function DeviceVerificationOptions() {
|
|||
return (
|
||||
<>
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
aria-pressed={!!menuCords}
|
||||
variant="SurfaceVariant"
|
||||
size="300"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import { GlobalPacks } from './GlobalPacks';
|
|||
import { UserPack } from './UserPack';
|
||||
import { ImagePack } from '../../../plugins/custom-emoji';
|
||||
import { ImagePackView } from '../../../components/image-pack-view';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
type EmojisStickersProps = {
|
||||
requestClose: () => void;
|
||||
|
|
@ -31,7 +30,7 @@ export function EmojisStickers({ requestClose }: EmojisStickersProps) {
|
|||
</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Surface">
|
||||
<IconButton onClick={requestClose} variant="Surface">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ import { allRoomsAtom } from '../../../state/room-list/roomList';
|
|||
import { AccountDataEvent } from '../../../../types/matrix/accountData';
|
||||
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
|
||||
import { stopPropagation } from '../../../utils/keyboard';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
function GlobalPackSelector({
|
||||
packs,
|
||||
|
|
@ -369,7 +368,6 @@ export function GlobalPacks({ onViewPack }: GlobalPacksProps) {
|
|||
<Box alignItems="Center" gap="300">
|
||||
{removed ? (
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
size="300"
|
||||
radii="Pill"
|
||||
variant="Critical"
|
||||
|
|
@ -380,7 +378,6 @@ export function GlobalPacks({ onViewPack }: GlobalPacksProps) {
|
|||
</IconButton>
|
||||
) : (
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
size="300"
|
||||
radii="Pill"
|
||||
variant="Secondary"
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ import { useMessageLayoutItems } from '../../../hooks/useMessageLayout';
|
|||
import { useMessageSpacingItems } from '../../../hooks/useMessageSpacing';
|
||||
import { useDateFormatItems } from '../../../hooks/useDateFormat';
|
||||
import { SequenceCardStyle } from '../styles.css';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
type ThemeSelectorProps = {
|
||||
themeNames: Record<string, string>;
|
||||
|
|
@ -498,7 +497,6 @@ function DateHint({ hasChanges, handleReset }: DateHintProps) {
|
|||
>
|
||||
{hasChanges ? (
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
tabIndex={-1}
|
||||
onClick={handleReset}
|
||||
type="reset"
|
||||
|
|
@ -510,7 +508,6 @@ function DateHint({ hasChanges, handleReset }: DateHintProps) {
|
|||
</IconButton>
|
||||
) : (
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
tabIndex={-1}
|
||||
onClick={handleOpenMenu}
|
||||
type="button"
|
||||
|
|
@ -1018,7 +1015,7 @@ export function General({ requestClose }: GeneralProps) {
|
|||
</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Surface">
|
||||
<IconButton onClick={requestClose} variant="Surface">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import {
|
|||
} from '../../../hooks/useNotificationMode';
|
||||
import { NotificationModeSwitcher } from './NotificationModeSwitcher';
|
||||
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
const NOTIFY_MODE_OPS: NotificationModeOptions = {
|
||||
highlight: true,
|
||||
|
|
@ -76,7 +75,6 @@ function KeywordInput() {
|
|||
keyword &&
|
||||
!addingKeyword && (
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
type="reset"
|
||||
onClick={handleReset}
|
||||
size="300"
|
||||
|
|
@ -120,14 +118,7 @@ function KeywordCross({ pushRule }: PushRulesProps) {
|
|||
|
||||
const removing = removeState.status === AsyncStatus.Loading;
|
||||
return (
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
onClick={remove}
|
||||
size="300"
|
||||
radii="Pill"
|
||||
variant="Secondary"
|
||||
disabled={removing}
|
||||
>
|
||||
<IconButton onClick={remove} size="300" radii="Pill" variant="Secondary" disabled={removing}>
|
||||
{removing ? <Spinner size="100" /> : <Icon src={Icons.Cross} size="100" />}
|
||||
</IconButton>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import { KeywordMessagesNotifications } from './KeywordMessages';
|
|||
import { SequenceCard } from '../../../components/sequence-card';
|
||||
import { SequenceCardStyle } from '../styles.css';
|
||||
import { SettingTile } from '../../../components/setting-tile';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
type NotificationsProps = {
|
||||
requestClose: () => void;
|
||||
|
|
@ -24,7 +23,7 @@ export function Notifications({ requestClose }: NotificationsProps) {
|
|||
</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Surface">
|
||||
<IconButton onClick={requestClose} variant="Surface">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import { Members } from '../common-settings/members';
|
|||
import { DeveloperTools } from '../common-settings/developer-tools';
|
||||
import { General } from './general';
|
||||
import { Permissions } from './permissions';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
type SpaceSettingsMenuItem = {
|
||||
page: SpaceSettingsPage;
|
||||
|
|
@ -118,7 +117,7 @@ export function SpaceSettings({ initialPage, requestClose }: SpaceSettingsProps)
|
|||
</Box>
|
||||
<Box shrink="No">
|
||||
{screenSize === ScreenSize.Mobile && (
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Background">
|
||||
<IconButton onClick={requestClose} variant="Background">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import {
|
|||
} from '../../common-settings/general';
|
||||
import { useRoomCreators } from '../../../hooks/useRoomCreators';
|
||||
import { useRoomPermissions } from '../../../hooks/useRoomPermissions';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
type GeneralProps = {
|
||||
requestClose: () => void;
|
||||
|
|
@ -34,7 +33,7 @@ export function General({ requestClose }: GeneralProps) {
|
|||
</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Surface">
|
||||
<IconButton onClick={requestClose} variant="Surface">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import { usePermissionGroups } from './usePermissionItems';
|
|||
import { PermissionGroups, Powers, PowersEditor } from '../../common-settings/permissions';
|
||||
import { useRoomCreators } from '../../../hooks/useRoomCreators';
|
||||
import { useRoomPermissions } from '../../../hooks/useRoomPermissions';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
type PermissionsProps = {
|
||||
requestClose: () => void;
|
||||
|
|
@ -46,7 +45,7 @@ export function Permissions({ requestClose }: PermissionsProps) {
|
|||
</Text>
|
||||
</Box>
|
||||
<Box shrink="No">
|
||||
<IconButton className={PhoneHit} onClick={requestClose} variant="Surface">
|
||||
<IconButton onClick={requestClose} variant="Surface">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import FocusTrap from 'focus-trap-react';
|
|||
|
||||
import { useDebounce } from '../../hooks/useDebounce';
|
||||
import { stopPropagation } from '../../utils/keyboard';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
export function ServerPicker({
|
||||
server,
|
||||
|
|
@ -130,7 +129,6 @@ export function ServerPicker({
|
|||
}
|
||||
>
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
onClick={handleOpenServerMenu}
|
||||
variant={allowCustomServer ? 'Background' : 'Surface'}
|
||||
size="300"
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ import { loginErrorMessage } from '../authMessages';
|
|||
import { ForgotLink } from '../styles.css';
|
||||
import { getResetPasswordPath } from '../../pathUtils';
|
||||
import { stopPropagation } from '../../../utils/keyboard';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
function UsernameHint({ server }: { server: string }) {
|
||||
const [anchor, setAnchor] = useState<RectCords>();
|
||||
|
|
@ -95,7 +94,6 @@ function UsernameHint({ server }: { server: string }) {
|
|||
}
|
||||
>
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
tabIndex={-1}
|
||||
onClick={handleOpenMenu}
|
||||
type="button"
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ import { SyncStatus } from './SyncStatus';
|
|||
import { AuthMetadataProvider } from '../../hooks/useAuthMetadata';
|
||||
import { getFallbackSession } from '../../state/sessions';
|
||||
import { AutoDiscovery } from './AutoDiscovery';
|
||||
import { PhoneHit } from '../../styles/PhoneHit.css';
|
||||
|
||||
function ClientRootLoading() {
|
||||
return (
|
||||
|
|
@ -62,7 +61,6 @@ function ClientRootOptions({ mx }: { mx?: MatrixClient }) {
|
|||
|
||||
return (
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: config.space.S100,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import {
|
|||
} from '../../../components/page';
|
||||
import { BackRouteHandler } from '../../../components/BackRouteHandler';
|
||||
import { CreateChat } from '../../../features/create-chat';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
export function DirectCreate() {
|
||||
const mx = useMatrixClient();
|
||||
|
|
@ -45,7 +44,7 @@ export function DirectCreate() {
|
|||
<Box grow="Yes" alignItems="Center" gap="200">
|
||||
<BackRouteHandler>
|
||||
{(onBack) => (
|
||||
<IconButton className={PhoneHit} onClick={onBack}>
|
||||
<IconButton onClick={onBack}>
|
||||
<Icon src={Icons.ArrowLeft} />
|
||||
</IconButton>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
|
|||
import { useNavToActivePathMapper } from '../../../hooks/useNavToActivePathMapper';
|
||||
import { PageNav, PageNavContent, PageNavHeader } from '../../../components/page';
|
||||
import { stopPropagation } from '../../../utils/keyboard';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
export function AddServer() {
|
||||
const mx = useMatrixClient();
|
||||
|
|
@ -97,12 +96,7 @@ export function AddServer() {
|
|||
<Box grow="Yes">
|
||||
<Text size="H4">Add Server</Text>
|
||||
</Box>
|
||||
<IconButton
|
||||
className={PhoneHit}
|
||||
size="300"
|
||||
onClick={() => setDialog(false)}
|
||||
radii="300"
|
||||
>
|
||||
<IconButton size="300" onClick={() => setDialog(false)} radii="300">
|
||||
<Icon src={Icons.Cross} />
|
||||
</IconButton>
|
||||
</Header>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import * as css from './style.css';
|
|||
import { useRoomNavigate } from '../../../hooks/useRoomNavigate';
|
||||
import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize';
|
||||
import { BackRouteHandler } from '../../../components/BackRouteHandler';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
export function FeaturedRooms() {
|
||||
const { featuredCommunities } = useClientConfig();
|
||||
|
|
@ -34,7 +33,7 @@ export function FeaturedRooms() {
|
|||
<Box shrink="No">
|
||||
<BackRouteHandler>
|
||||
{(onBack) => (
|
||||
<IconButton className={PhoneHit} onClick={onBack}>
|
||||
<IconButton onClick={onBack}>
|
||||
<Icon src={Icons.ArrowLeft} />
|
||||
</IconButton>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ import { getMxIdServer } from '../../../utils/matrix';
|
|||
import { stopPropagation } from '../../../utils/keyboard';
|
||||
import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize';
|
||||
import { BackRouteHandler } from '../../../components/BackRouteHandler';
|
||||
import { PhoneHit } from '../../../styles/PhoneHit.css';
|
||||
|
||||
const useServerSearchParams = (searchParams: URLSearchParams): ExploreServerPathSearchParams =>
|
||||
useMemo(
|
||||
|
|
@ -500,7 +499,7 @@ export function PublicRooms() {
|
|||
{screenSize === ScreenSize.Mobile && (
|
||||
<BackRouteHandler>
|
||||
{(onBack) => (
|
||||
<IconButton className={PhoneHit} onClick={onBack}>
|
||||
<IconButton onClick={onBack}>
|
||||
<Icon src={Icons.ArrowLeft} />
|
||||
</IconButton>
|
||||
)}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue