Add labeled file materials with format badge

- Store human-readable label in LessonFile.name via optional label field on upload
- Add PATCH endpoint to rename existing files inline
- Admin: label input before upload, click-to-edit inline rename
- Student: colored format badge (PDF/DOCX/XLSX/ZIP/etc) replaces paperclip emoji

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-26 11:55:07 +05:00
co-authored by Claude Sonnet 4.6
parent 15df731e37
commit 39d84a3db2
4 changed files with 182 additions and 19 deletions
@@ -0,0 +1,40 @@
const FORMAT_MAP: Record<string, { label: string; bg: string }> = {
pdf: { label: "PDF", bg: "#DC2626" },
zip: { label: "ZIP", bg: "#D97706" },
docx: { label: "DOCX", bg: "#2563EB" },
doc: { label: "DOC", bg: "#2563EB" },
xlsx: { label: "XLSX", bg: "#16A34A" },
xls: { label: "XLS", bg: "#16A34A" },
pptx: { label: "PPTX", bg: "#EA580C" },
ppt: { label: "PPT", bg: "#EA580C" },
mp4: { label: "MP4", bg: "#7C3AED" },
mp3: { label: "MP3", bg: "#7C3AED" },
};
export function getFileFormatInfo(url: string): { label: string; bg: string } {
const ext = url.split("?")[0].split(".").pop()?.toLowerCase() ?? "";
return FORMAT_MAP[ext] ?? { label: ext.toUpperCase().slice(0, 4) || "FILE", bg: "#6B7280" };
}
export function FileFormatBadge({ url }: { url: string }) {
const { label, bg } = getFileFormatInfo(url);
return (
<span
style={{
display: "inline-flex",
alignItems: "center",
justifyContent: "center",
minWidth: "44px",
padding: "2px 6px",
fontSize: "10px",
fontWeight: "800",
letterSpacing: "0.06em",
background: bg,
color: "#fff",
flexShrink: 0,
}}
>
{label}
</span>
);
}