mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-23 13:26:42 +02:00
feat: integrate uload and picture, unify package naming
- Add uload project with apps/web structure
- Reorganize from flat to monorepo structure
- Remove PocketBase binary and local data
- Update to pnpm and @uload/web namespace
- Add picture project to monorepo
- Remove embedded git repository
- Unify all package names to @{project}/{app} schema:
- @maerchenzauber/* (was @storyteller/*)
- @manacore/* (was manacore-*, manacore)
- @manadeck/* (was web, backend, manadeck)
- @memoro/* (was memoro-web, landing, memoro)
- @picture/* (already unified)
- @uload/web
- Add convenient dev scripts for all apps:
- pnpm dev:{project}:web
- pnpm dev:{project}:landing
- pnpm dev:{project}:mobile
- pnpm dev:{project}:backend
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
c6c4c5a552
commit
c712a2504a
1031 changed files with 189301 additions and 290 deletions
203
uload/apps/web/src/lib/actions/touch.test.ts
Normal file
203
uload/apps/web/src/lib/actions/touch.test.ts
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
import { describe, test, expect, beforeEach, vi } from 'vitest';
|
||||
import { isTouchDevice, isOptimalTouchTarget } from './touch';
|
||||
|
||||
// Mock DOM APIs für Tests
|
||||
const mockEventListener = vi.fn();
|
||||
const mockRemoveEventListener = vi.fn();
|
||||
|
||||
const createMockElement = (width = 44, height = 44) => ({
|
||||
addEventListener: mockEventListener,
|
||||
removeEventListener: mockRemoveEventListener,
|
||||
getBoundingClientRect: () => ({ width, height, top: 0, left: 0, right: width, bottom: height }),
|
||||
style: {},
|
||||
appendChild: vi.fn(),
|
||||
remove: vi.fn()
|
||||
});
|
||||
|
||||
// Mock global objects
|
||||
Object.defineProperty(window, 'navigator', {
|
||||
value: {
|
||||
maxTouchPoints: 0,
|
||||
userAgent: 'Mozilla/5.0 (Test Browser)'
|
||||
},
|
||||
writable: true
|
||||
});
|
||||
|
||||
describe('Touch Utilities', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
// Reset touch support
|
||||
delete (window as any).ontouchstart;
|
||||
(window.navigator as any).maxTouchPoints = 0;
|
||||
});
|
||||
|
||||
describe('isTouchDevice', () => {
|
||||
test('should detect touch support via ontouchstart', () => {
|
||||
(window as any).ontouchstart = true;
|
||||
expect(isTouchDevice()).toBe(true);
|
||||
});
|
||||
|
||||
test('should detect touch support via maxTouchPoints', () => {
|
||||
(window.navigator as any).maxTouchPoints = 1;
|
||||
expect(isTouchDevice()).toBe(true);
|
||||
});
|
||||
|
||||
test('should return false for non-touch devices', () => {
|
||||
expect(isTouchDevice()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isOptimalTouchTarget', () => {
|
||||
test('should return true for 44x44 elements', () => {
|
||||
const element = createMockElement(44, 44);
|
||||
expect(isOptimalTouchTarget(element as any)).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true for larger elements', () => {
|
||||
const element = createMockElement(50, 60);
|
||||
expect(isOptimalTouchTarget(element as any)).toBe(true);
|
||||
});
|
||||
|
||||
test('should return false for small width', () => {
|
||||
const element = createMockElement(30, 44);
|
||||
expect(isOptimalTouchTarget(element as any)).toBe(false);
|
||||
});
|
||||
|
||||
test('should return false for small height', () => {
|
||||
const element = createMockElement(44, 30);
|
||||
expect(isOptimalTouchTarget(element as any)).toBe(false);
|
||||
});
|
||||
|
||||
test('should return false for small elements', () => {
|
||||
const element = createMockElement(20, 20);
|
||||
expect(isOptimalTouchTarget(element as any)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Touch Actions (Integration)', () => {
|
||||
let mockElement: any;
|
||||
|
||||
beforeEach(() => {
|
||||
mockElement = createMockElement();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('Event Registration', () => {
|
||||
test('should register touch and pointer events', () => {
|
||||
// Diese Tests würden die tatsächlichen Touch-Actions testen
|
||||
// Für jetzt testen wir nur die Utility-Funktionen
|
||||
expect(mockEventListener).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Gesture Recognition', () => {
|
||||
test('should calculate touch distances correctly', () => {
|
||||
const touch1 = { clientX: 0, clientY: 0 };
|
||||
const touch2 = { clientX: 100, clientY: 100 };
|
||||
|
||||
// Math.sqrt(100^2 + 100^2) = Math.sqrt(20000) ≈ 141.42
|
||||
const expectedDistance = Math.sqrt(20000);
|
||||
const actualDistance = Math.sqrt(
|
||||
Math.pow(touch2.clientX - touch1.clientX, 2) +
|
||||
Math.pow(touch2.clientY - touch1.clientY, 2)
|
||||
);
|
||||
|
||||
expect(actualDistance).toBeCloseTo(expectedDistance, 2);
|
||||
});
|
||||
|
||||
test('should detect horizontal swipes', () => {
|
||||
const startTouch = { clientX: 0, clientY: 100 };
|
||||
const endTouch = { clientX: 100, clientY: 100 };
|
||||
|
||||
const deltaX = endTouch.clientX - startTouch.clientX;
|
||||
const deltaY = endTouch.clientY - startTouch.clientY;
|
||||
const absDeltaX = Math.abs(deltaX);
|
||||
const absDeltaY = Math.abs(deltaY);
|
||||
|
||||
// Horizontal swipe: |deltaX| > |deltaY|
|
||||
expect(absDeltaX).toBeGreaterThan(absDeltaY);
|
||||
expect(deltaX).toBeGreaterThan(0); // Right swipe
|
||||
});
|
||||
|
||||
test('should detect vertical swipes', () => {
|
||||
const startTouch = { clientX: 100, clientY: 0 };
|
||||
const endTouch = { clientX: 100, clientY: 100 };
|
||||
|
||||
const deltaX = endTouch.clientX - startTouch.clientX;
|
||||
const deltaY = endTouch.clientY - startTouch.clientY;
|
||||
const absDeltaX = Math.abs(deltaX);
|
||||
const absDeltaY = Math.abs(deltaY);
|
||||
|
||||
// Vertical swipe: |deltaY| > |deltaX|
|
||||
expect(absDeltaY).toBeGreaterThan(absDeltaX);
|
||||
expect(deltaY).toBeGreaterThan(0); // Down swipe
|
||||
});
|
||||
});
|
||||
|
||||
describe('Touch Target Validation', () => {
|
||||
test('should validate minimum touch target sizes', () => {
|
||||
const sizes = [
|
||||
{ width: 44, height: 44, expected: true },
|
||||
{ width: 48, height: 48, expected: true },
|
||||
{ width: 40, height: 40, expected: false },
|
||||
{ width: 44, height: 40, expected: false },
|
||||
{ width: 40, height: 44, expected: false }
|
||||
];
|
||||
|
||||
sizes.forEach(({ width, height, expected }) => {
|
||||
const element = createMockElement(width, height);
|
||||
expect(isOptimalTouchTarget(element as any)).toBe(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Performance Considerations', () => {
|
||||
test('should handle rapid touch events', () => {
|
||||
// Simuliere viele schnelle Touch-Events
|
||||
const events = Array.from({ length: 100 }, (_, i) => ({
|
||||
clientX: i,
|
||||
clientY: i,
|
||||
timestamp: Date.now() + i
|
||||
}));
|
||||
|
||||
// In einer echten Implementation würden wir Throttling/Debouncing testen
|
||||
expect(events).toHaveLength(100);
|
||||
|
||||
// Teste dass Events innerhalb vernünftiger Zeit verarbeitet werden können
|
||||
const startTime = Date.now();
|
||||
events.forEach(event => {
|
||||
// Simuliere Event-Verarbeitung
|
||||
const deltaX = event.clientX;
|
||||
const deltaY = event.clientY;
|
||||
Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||
});
|
||||
const endTime = Date.now();
|
||||
|
||||
expect(endTime - startTime).toBeLessThan(100); // Sollte sehr schnell sein
|
||||
});
|
||||
});
|
||||
|
||||
describe('Accessibility Considerations', () => {
|
||||
test('should maintain focus accessibility', () => {
|
||||
// Touch-Actions sollten Keyboard-Navigation nicht beeinträchtigen
|
||||
const element = createMockElement();
|
||||
|
||||
// Simuliere dass Element fokussierbar bleibt
|
||||
element.tabIndex = 0;
|
||||
element.setAttribute = vi.fn();
|
||||
|
||||
expect(element.tabIndex).toBe(0);
|
||||
});
|
||||
|
||||
test('should work with screen readers', () => {
|
||||
// Touch-Targets sollten Screen-Reader-kompatibel bleiben
|
||||
const element = createMockElement();
|
||||
element.getAttribute = vi.fn().mockReturnValue('button');
|
||||
element.textContent = 'Touch Button';
|
||||
|
||||
expect(element.getAttribute('role')).toBe('button');
|
||||
expect(element.textContent).toBe('Touch Button');
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue