feat(değerlendirme): ay sonu değerlendirmesi sayfası

- Kakeibo'nun 4 sorusu, nasıl hesaplandığıyla birlikte
- Grup bazında planlanan/gerçekleşen, en çok harcanan kategoriler, haftalık dağılım
- "Nasıl daha iyi yapabilirim?" (Markdown) ve yalnızca başlıkları listelenen notlar

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-12 12:31:35 +03:00
parent 62e92f552a
commit 311cfc8c60
16 changed files with 627 additions and 56 deletions
+67
View File
@@ -0,0 +1,67 @@
import { useId, useState, type ReactNode } from 'react'
import { Markdown } from '@/components/markdown'
import { t } from '@/lib/strings'
import { cn } from '@/lib/utils'
/**
* Markdown alanı için "Yaz / Önizle" sekmeleri. `children` = yazma paneli (genelde `Textarea`).
* Kimlikler `useId` ile üretilir → aynı sayfada birden çok editör olabilir.
*/
export function MarkdownTabs({
label,
value,
children,
}: {
/** Sekme listesinin erişilebilir adı */
label: string
/** Önizlenecek metin */
value: string
children: ReactNode
}) {
const id = useId()
const [tab, setTab] = useState<'write' | 'preview'>('write')
const tabButton = (v: typeof tab, text: string) => (
<button
type="button"
role="tab"
id={`${id}-tab-${v}`}
aria-selected={tab === v}
aria-controls={`${id}-panel-${v}`}
onClick={() => setTab(v)}
className={cn(
'h-11 rounded-md px-4 text-sm font-medium transition-colors',
tab === v ? 'bg-background shadow-sm' : 'text-muted-foreground hover:text-foreground',
)}
>
{text}
</button>
)
return (
<div className="space-y-2">
<div role="tablist" aria-label={label} className="inline-flex rounded-lg bg-muted p-1">
{tabButton('write', t.notes.write)}
{tabButton('preview', t.notes.preview)}
</div>
{tab === 'write' ? (
<div id={`${id}-panel-write`} role="tabpanel" aria-labelledby={`${id}-tab-write`}>
{children}
</div>
) : (
<div
id={`${id}-panel-preview`}
role="tabpanel"
aria-labelledby={`${id}-tab-preview`}
className="min-h-40 rounded-lg border p-3"
>
{value.trim() ? (
<Markdown>{value}</Markdown>
) : (
<p className="text-sm text-muted-foreground">{t.notes.previewEmpty}</p>
)}
</div>
)}
</div>
)
}