perf(movimento): uma transição, 3D leve e vídeo certo por aparelho
Passagens com fade e 32 px, cena anterior termina em opacidade 0, sem visibility nem clip-path. 3D do hero como fundo ambiente, sob demanda e desligado em toque, aparelho fraco, saveData e movimento reduzido. Lenis fora do toque e salto direto em âncoras distantes. Vitrine só de clientes, até 3 capítulos, fixa só no desktop e carrossel no celular; vídeo só do projeto em cena com preload metadata. Rótulos mono a partir de 12 px e limão só no contato.
This commit is contained in:
1 parent
8d07b8c6bb
commit
c9a0b80656
48 files changed
+7210
-1241
No files matched your search
@@ -0,0 +1,74 @@
|
||||
import {
|
||||
isCoarsePointer,
|
||||
isLowPowerDevice,
|
||||
isMobileViewport,
|
||||
isSaveData,
|
||||
MOBILE_QUERY,
|
||||
} from "./device";
|
||||
|
||||
const originalMatchMedia = window.matchMedia;
|
||||
|
||||
function mockMedia(active: string[]) {
|
||||
window.matchMedia = jest.fn().mockImplementation((query: string) => ({
|
||||
matches: active.includes(query),
|
||||
media: query,
|
||||
addEventListener() {},
|
||||
removeEventListener() {},
|
||||
}));
|
||||
}
|
||||
|
||||
function mockNavigator(values: Record<string, unknown>) {
|
||||
for (const [key, value] of Object.entries(values))
|
||||
Object.defineProperty(navigator, key, { configurable: true, value });
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
mockMedia([]);
|
||||
mockNavigator({
|
||||
hardwareConcurrency: 8,
|
||||
deviceMemory: undefined,
|
||||
connection: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
window.matchMedia = originalMatchMedia;
|
||||
});
|
||||
|
||||
describe("device hints", () => {
|
||||
it("treats a capable desktop as full power", () => {
|
||||
expect(isLowPowerDevice()).toBe(false);
|
||||
expect(isCoarsePointer()).toBe(false);
|
||||
expect(isSaveData()).toBe(false);
|
||||
expect(isMobileViewport()).toBe(false);
|
||||
});
|
||||
|
||||
it("reads the phone breakpoint from the shared query", () => {
|
||||
mockMedia([MOBILE_QUERY]);
|
||||
expect(isMobileViewport()).toBe(true);
|
||||
expect(MOBILE_QUERY).toBe("(max-width: 767px)");
|
||||
});
|
||||
|
||||
it.each([
|
||||
["a touch pointer", () => mockMedia(["(pointer: coarse)"])],
|
||||
["reduced motion", () => mockMedia(["(prefers-reduced-motion: reduce)"])],
|
||||
["the data saver", () => mockNavigator({ connection: { saveData: true } })],
|
||||
["four cores", () => mockNavigator({ hardwareConcurrency: 4 })],
|
||||
["two cores", () => mockNavigator({ hardwareConcurrency: 2 })],
|
||||
["4 GB of memory", () => mockNavigator({ deviceMemory: 4 })],
|
||||
["2 GB of memory", () => mockNavigator({ deviceMemory: 2 })],
|
||||
])("is low power with %s", (_label, arrange) => {
|
||||
arrange();
|
||||
expect(isLowPowerDevice()).toBe(true);
|
||||
});
|
||||
|
||||
it("does not penalize a browser that hides the hardware hints", () => {
|
||||
mockNavigator({ hardwareConcurrency: undefined, deviceMemory: undefined });
|
||||
expect(isLowPowerDevice()).toBe(false);
|
||||
});
|
||||
|
||||
it("keeps 8 GB and 6 cores on the full path", () => {
|
||||
mockNavigator({ hardwareConcurrency: 6, deviceMemory: 8 });
|
||||
expect(isLowPowerDevice()).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user