fix(frontend): session cookie path, browser-language default, avatar crop, EN link previews, topbar logo
- nginx: rewrite the refresh cookie's Path=/auth to /api/auth on the production proxy — without this the browser never sent the cookie back on POST /api/auth/refresh and the session was lost on reload - i18n: fallbackLng ru -> en, so only an actual ru browser locale defaults to Russian, everything else defaults to English - index.html: explicit English og:*/twitter:* tags so link previews in Discord/etc. don't fall back to the (Russian) meta description - Avatar upload: pick -> circular crop/reposition/zoom preview -> confirm -> upload, instead of uploading the raw file blind - Topbar: logo pill background removed, pixel-heart mark added next to the LoVisual wordmark - Fixed two tests left stale by the earlier tagline copy change Claude-Session: https://claude.ai/code/session_01F1M1Jic1wTSn4igUENynmZ
This commit is contained in:
parent
fc0e125e62
commit
e0531eda5e
13 changed files with 383 additions and 16 deletions
54
frontend/src/features/account/tests/cropMath.test.ts
Normal file
54
frontend/src/features/account/tests/cropMath.test.ts
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import { expect, test } from 'vitest'
|
||||
import { clampPan, clampZoom, coverScale, sourceRect } from '../components/cropMath'
|
||||
|
||||
test('coverScale scales the shorter side to fill the viewport', () => {
|
||||
expect(coverScale(1000, 2000, 200)).toBeCloseTo(0.2)
|
||||
expect(coverScale(2000, 1000, 200)).toBeCloseTo(0.2)
|
||||
})
|
||||
|
||||
test('clampZoom keeps zoom within [1, 4]', () => {
|
||||
expect(clampZoom(0.5)).toBe(1)
|
||||
expect(clampZoom(10)).toBe(4)
|
||||
expect(clampZoom(2)).toBe(2)
|
||||
})
|
||||
|
||||
test('clampPan keeps a square image centered at zoom 1 (no room to pan)', () => {
|
||||
const clamped = clampPan({ x: 50, y: 50 }, 400, 400, 200, 1)
|
||||
expect(clamped).toEqual({ x: 0, y: 0 })
|
||||
})
|
||||
|
||||
test('clampPan allows panning up to the overflow at higher zoom', () => {
|
||||
// 400x400 image, viewport 200, zoom 2 -> scale = 0.5*2 = 1, scaledSize 400, overflow (400-200)/2=100
|
||||
const clamped = clampPan({ x: 1000, y: -1000 }, 400, 400, 200, 2)
|
||||
expect(clamped).toEqual({ x: 100, y: -100 })
|
||||
})
|
||||
|
||||
test('clampPan never lets the image show empty space (overflow stays >= 0)', () => {
|
||||
const clamped = clampPan({ x: 5, y: 5 }, 300, 900, 240, 1)
|
||||
// shorter side (300) covers the viewport exactly at zoom 1, so no pan room on x
|
||||
expect(clamped.x).toBe(0)
|
||||
// long side has plenty of room
|
||||
expect(Math.abs(clamped.y)).toBeLessThanOrEqual(5)
|
||||
})
|
||||
|
||||
test('sourceRect at zoom 1 with no offset centers the full covering square', () => {
|
||||
const rect = sourceRect(400, 400, 200, 1, { x: 0, y: 0 })
|
||||
expect(rect.sx).toBeCloseTo(0)
|
||||
expect(rect.sy).toBeCloseTo(0)
|
||||
expect(rect.sw).toBeCloseTo(400)
|
||||
expect(rect.sh).toBeCloseTo(400)
|
||||
})
|
||||
|
||||
test('sourceRect shrinks the source square as zoom increases', () => {
|
||||
const rect = sourceRect(400, 400, 200, 2, { x: 0, y: 0 })
|
||||
expect(rect.sw).toBeCloseTo(200)
|
||||
expect(rect.sh).toBeCloseTo(200)
|
||||
expect(rect.sx).toBeCloseTo(100)
|
||||
expect(rect.sy).toBeCloseTo(100)
|
||||
})
|
||||
|
||||
test('sourceRect shifts opposite the pan offset', () => {
|
||||
const zoomed = sourceRect(400, 400, 200, 2, { x: 50, y: 0 })
|
||||
// positive offset.x pans the image right on screen -> source window moves left
|
||||
expect(zoomed.sx).toBeLessThan(100)
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue