feat(arayüz): Tailwind + shadcn/ui tasarım sistemi, tema ve biçimlendirme

- Tailwind v4 + shadcn/ui (Radix), Inter yazı tipi (yerel)
- Tasarım token'ları: 4 ana grup (renk körlüğüne uygun) ve durum renkleri, WCAG AA
- Aydınlık / Karanlık / Sistem teması (ilk açılışta parlama yok)
- lib/format.ts: para (1.250,00 ₺), miktar, yüzde, tarih (GG.AA.YYYY), tutar ayrıştırma
- Vitest: 22 biçimlendirme testi; npm test artık frontend'i de çalıştırır
- Butonlar mobil dokunma alanına (≥44 px) göre büyütüldü

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-12 00:06:27 +03:00
parent 6eb5440d4d
commit 440523b176
22 changed files with 6051 additions and 115 deletions
+69
View File
@@ -0,0 +1,69 @@
import { describe, expect, it } from 'vitest'
import {
formatDate,
formatMoney,
formatNumber,
formatPercent,
formatQuantity,
parseMoney,
toIsoDate,
} from './format'
describe('formatMoney', () => {
it('kuruşu Türkçe biçimde, para birimi sağda ve boşluklu yazar', () => {
expect(formatMoney(125000)).toBe('1.250,00 ₺')
expect(formatMoney(30000, 'EUR')).toBe('300,00 €')
expect(formatMoney(15000, 'USD')).toBe('150,00 $')
expect(formatMoney(0)).toBe('0,00 ₺')
expect(formatMoney(5)).toBe('0,05 ₺')
expect(formatMoney(123456789)).toBe('1.234.567,89 ₺')
})
it('negatif ve işaretli', () => {
expect(formatMoney(-125000)).toBe('-1.250,00 ₺')
expect(formatMoney(125000, 'TRY', { signed: true })).toBe('+1.250,00 ₺')
expect(formatMoney(-500, 'TRY', { signed: true })).toBe('-5,00 ₺')
})
})
describe('diğer biçimler', () => {
it('miktar, sayı, yüzde', () => {
expect(formatQuantity(12_500_000, 'gr')).toBe('12,50 gr')
expect(formatQuantity(1_234_567, 'gr', 3)).toBe('1,235 gr')
expect(formatNumber(1250.5)).toBe('1.250,50')
expect(formatPercent(0.123)).toBe('%12,3')
})
it('tarih GG.AA.YYYY', () => {
expect(formatDate('2026-12-09')).toBe('09.12.2026')
expect(formatDate(new Date(2027, 0, 1))).toBe('01.01.2027')
expect(toIsoDate(new Date(2026, 11, 9))).toBe('2026-12-09')
})
})
describe('parseMoney', () => {
it.each([
['1250', 125000],
['1.250', 125000],
['1250,5', 125050],
['1.250,50', 125050],
['1250.50', 125050], // telefon klavyesindeki nokta
['1250.5', 125050],
[' 1.250,00 ₺ ', 125000],
[',99', 99],
['0,1', 10],
['1.234.567,89', 123456789],
['-45,5', -4550],
])('%s → %i kuruş', (input, expected) => {
expect(parseMoney(input)).toBe(expected)
})
it.each(['', 'abc', '1,2,3', '12,345', '1.250,5.0', '₺'])('geçersiz: "%s"', (input) => {
expect(parseMoney(input)).toBeNull()
})
it('kayan nokta hatası yok (0,1 + 0,2 gibi değerler tam)', () => {
expect(parseMoney('0,29')).toBe(29)
expect(parseMoney('19,99')).toBe(1999)
})
})