feat: Add deafen to pc, fix mobiel view, fix freeze on startup
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
import {
|
||||
describe,
|
||||
expect,
|
||||
it
|
||||
} from 'vitest';
|
||||
|
||||
import { buildChatMessageImageGridLayout, formatChatMessageImageOverflowLabel } from './chat-message-image-grid.rules';
|
||||
|
||||
describe('chat-message-image-grid rules', () => {
|
||||
it('keeps a single image outside the grid', () => {
|
||||
expect(buildChatMessageImageGridLayout(1)).toEqual({
|
||||
useGrid: false,
|
||||
variant: 'none',
|
||||
cells: []
|
||||
});
|
||||
});
|
||||
|
||||
it('lays out two images in a pair grid', () => {
|
||||
expect(buildChatMessageImageGridLayout(2)).toEqual({
|
||||
useGrid: true,
|
||||
variant: 'pair',
|
||||
cells: [{ kind: 'image', index: 0 }, { kind: 'image', index: 1 }]
|
||||
});
|
||||
});
|
||||
|
||||
it('lays out three images in a triple grid', () => {
|
||||
expect(buildChatMessageImageGridLayout(3)).toEqual({
|
||||
useGrid: true,
|
||||
variant: 'triple',
|
||||
cells: [
|
||||
{ kind: 'image', index: 0 },
|
||||
{ kind: 'image', index: 1 },
|
||||
{ kind: 'image', index: 2 }
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
it('lays out four images in a quad grid', () => {
|
||||
expect(buildChatMessageImageGridLayout(4)).toEqual({
|
||||
useGrid: true,
|
||||
variant: 'quad',
|
||||
cells: [
|
||||
{ kind: 'image', index: 0 },
|
||||
{ kind: 'image', index: 1 },
|
||||
{ kind: 'image', index: 2 },
|
||||
{ kind: 'image', index: 3 }
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
it('replaces the last grid cell with an overflow tile when more than four images exist', () => {
|
||||
expect(buildChatMessageImageGridLayout(7)).toEqual({
|
||||
useGrid: true,
|
||||
variant: 'quad',
|
||||
cells: [
|
||||
{ kind: 'image', index: 0 },
|
||||
{ kind: 'image', index: 1 },
|
||||
{ kind: 'image', index: 2 },
|
||||
{ kind: 'overflow', hiddenCount: 4 }
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
it('formats overflow labels as amount plus', () => {
|
||||
expect(formatChatMessageImageOverflowLabel(4)).toBe('+4');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,83 @@
|
||||
export const CHAT_MESSAGE_IMAGE_GRID_MIN_COUNT = 2;
|
||||
export const CHAT_MESSAGE_IMAGE_GRID_MAX_VISIBLE = 4;
|
||||
|
||||
export type ChatMessageImageGridVariant = 'none' | 'pair' | 'triple' | 'quad';
|
||||
|
||||
export interface ChatMessageImageGridImageCell {
|
||||
kind: 'image';
|
||||
index: number;
|
||||
}
|
||||
|
||||
export interface ChatMessageImageGridOverflowCell {
|
||||
kind: 'overflow';
|
||||
hiddenCount: number;
|
||||
}
|
||||
|
||||
export type ChatMessageImageGridCell = ChatMessageImageGridImageCell | ChatMessageImageGridOverflowCell;
|
||||
|
||||
export interface ChatMessageImageGridLayout {
|
||||
useGrid: boolean;
|
||||
variant: ChatMessageImageGridVariant;
|
||||
cells: ChatMessageImageGridCell[];
|
||||
}
|
||||
|
||||
export function buildChatMessageImageGridLayout(imageCount: number): ChatMessageImageGridLayout {
|
||||
if (imageCount < CHAT_MESSAGE_IMAGE_GRID_MIN_COUNT) {
|
||||
return {
|
||||
useGrid: false,
|
||||
variant: 'none',
|
||||
cells: []
|
||||
};
|
||||
}
|
||||
|
||||
if (imageCount === 2) {
|
||||
return {
|
||||
useGrid: true,
|
||||
variant: 'pair',
|
||||
cells: [{ kind: 'image', index: 0 }, { kind: 'image', index: 1 }]
|
||||
};
|
||||
}
|
||||
|
||||
if (imageCount === 3) {
|
||||
return {
|
||||
useGrid: true,
|
||||
variant: 'triple',
|
||||
cells: [
|
||||
{ kind: 'image', index: 0 },
|
||||
{ kind: 'image', index: 1 },
|
||||
{ kind: 'image', index: 2 }
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
if (imageCount === CHAT_MESSAGE_IMAGE_GRID_MAX_VISIBLE) {
|
||||
return {
|
||||
useGrid: true,
|
||||
variant: 'quad',
|
||||
cells: [
|
||||
{ kind: 'image', index: 0 },
|
||||
{ kind: 'image', index: 1 },
|
||||
{ kind: 'image', index: 2 },
|
||||
{ kind: 'image', index: 3 }
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
useGrid: true,
|
||||
variant: 'quad',
|
||||
cells: [
|
||||
{ kind: 'image', index: 0 },
|
||||
{ kind: 'image', index: 1 },
|
||||
{ kind: 'image', index: 2 },
|
||||
{
|
||||
kind: 'overflow',
|
||||
hiddenCount: imageCount - 3
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
export function formatChatMessageImageOverflowLabel(hiddenCount: number): string {
|
||||
return `+${hiddenCount}`;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import {
|
||||
describe,
|
||||
expect,
|
||||
it
|
||||
} from 'vitest';
|
||||
|
||||
import { canStepLightbox, stepLightboxIndex } from './chat-message-lightbox.rules';
|
||||
|
||||
describe('chat-message-lightbox rules', () => {
|
||||
it('steps forward and backward within bounds', () => {
|
||||
expect(stepLightboxIndex(1, 1, 3)).toBe(2);
|
||||
expect(stepLightboxIndex(1, -1, 3)).toBe(0);
|
||||
});
|
||||
|
||||
it('returns null when stepping past the ends', () => {
|
||||
expect(stepLightboxIndex(0, -1, 3)).toBeNull();
|
||||
expect(stepLightboxIndex(2, 1, 3)).toBeNull();
|
||||
});
|
||||
|
||||
it('returns null when there is only one image', () => {
|
||||
expect(stepLightboxIndex(0, 1, 1)).toBeNull();
|
||||
});
|
||||
|
||||
it('reports whether a step is available', () => {
|
||||
expect(canStepLightbox(0, -1, 3)).toBe(false);
|
||||
expect(canStepLightbox(0, 1, 3)).toBe(true);
|
||||
expect(canStepLightbox(2, 1, 3)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
export function stepLightboxIndex(currentIndex: number, delta: number, total: number): number | null {
|
||||
if (total <= 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const nextIndex = currentIndex + delta;
|
||||
|
||||
if (nextIndex < 0 || nextIndex >= total) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return nextIndex;
|
||||
}
|
||||
|
||||
export function canStepLightbox(currentIndex: number, delta: number, total: number): boolean {
|
||||
return stepLightboxIndex(currentIndex, delta, total) !== null;
|
||||
}
|
||||
Reference in New Issue
Block a user