@hed-hog/lms 0.0.306 → 0.0.310

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/dist/course/course-structure.controller.d.ts +60 -0
  2. package/dist/course/course-structure.controller.d.ts.map +1 -1
  3. package/dist/course/course-structure.controller.js +79 -0
  4. package/dist/course/course-structure.controller.js.map +1 -1
  5. package/dist/course/course-structure.service.d.ts +61 -1
  6. package/dist/course/course-structure.service.d.ts.map +1 -1
  7. package/dist/course/course-structure.service.js +326 -1
  8. package/dist/course/course-structure.service.js.map +1 -1
  9. package/dist/course/course.controller.d.ts +52 -4
  10. package/dist/course/course.controller.d.ts.map +1 -1
  11. package/dist/course/course.service.d.ts +52 -5
  12. package/dist/course/course.service.d.ts.map +1 -1
  13. package/dist/course/course.service.js +78 -57
  14. package/dist/course/course.service.js.map +1 -1
  15. package/dist/course/dto/create-course-structure-lesson.dto.d.ts.map +1 -1
  16. package/dist/course/dto/create-course-structure-lesson.dto.js +5 -1
  17. package/dist/course/dto/create-course-structure-lesson.dto.js.map +1 -1
  18. package/dist/course/dto/create-course.dto.d.ts +1 -1
  19. package/dist/course/dto/create-course.dto.d.ts.map +1 -1
  20. package/dist/course/dto/create-course.dto.js +4 -1
  21. package/dist/course/dto/create-course.dto.js.map +1 -1
  22. package/dist/course/dto/move-lesson.dto.d.ts +10 -0
  23. package/dist/course/dto/move-lesson.dto.d.ts.map +1 -0
  24. package/dist/course/dto/move-lesson.dto.js +28 -0
  25. package/dist/course/dto/move-lesson.dto.js.map +1 -0
  26. package/dist/course/dto/paste-lessons.dto.d.ts +4 -0
  27. package/dist/course/dto/paste-lessons.dto.d.ts.map +1 -0
  28. package/dist/course/dto/paste-lessons.dto.js +24 -0
  29. package/dist/course/dto/paste-lessons.dto.js.map +1 -0
  30. package/dist/course/dto/reorder-lessons.dto.d.ts +5 -0
  31. package/dist/course/dto/reorder-lessons.dto.d.ts.map +1 -0
  32. package/dist/course/dto/reorder-lessons.dto.js +24 -0
  33. package/dist/course/dto/reorder-lessons.dto.js.map +1 -0
  34. package/dist/course/dto/reorder-sessions.dto.d.ts +5 -0
  35. package/dist/course/dto/reorder-sessions.dto.d.ts.map +1 -0
  36. package/dist/course/dto/reorder-sessions.dto.js +24 -0
  37. package/dist/course/dto/reorder-sessions.dto.js.map +1 -0
  38. package/dist/training/training.controller.js +1 -1
  39. package/dist/training/training.controller.js.map +1 -1
  40. package/hedhog/data/image_type.yaml +20 -0
  41. package/hedhog/data/menu.yaml +2 -2
  42. package/hedhog/data/route.yaml +60 -6
  43. package/hedhog/frontend/app/_components/class-form-sheet.tsx.ejs +146 -165
  44. package/hedhog/frontend/app/_components/course-avatar.tsx.ejs +70 -0
  45. package/hedhog/frontend/app/_components/course-form-sheet.tsx.ejs +372 -22
  46. package/hedhog/frontend/app/certificates/models/CanvasStage.tsx.ejs +10 -1
  47. package/hedhog/frontend/app/certificates/models/TopBar.tsx.ejs +44 -3
  48. package/hedhog/frontend/app/certificates/models/page.tsx.ejs +32 -0
  49. package/hedhog/frontend/app/classes/[id]/page.tsx.ejs +437 -77
  50. package/hedhog/frontend/app/classes/page.tsx.ejs +311 -289
  51. package/hedhog/frontend/app/courses/[id]/_components/CourseCertificateCard.tsx.ejs +10 -7
  52. package/hedhog/frontend/app/courses/[id]/_components/CourseClassificationCard.tsx.ejs +23 -32
  53. package/hedhog/frontend/app/courses/[id]/_components/CourseContentCard.tsx.ejs +3 -9
  54. package/hedhog/frontend/app/courses/[id]/_components/CourseDangerZoneCard.tsx.ejs +26 -16
  55. package/hedhog/frontend/app/courses/[id]/_components/CourseFlagsCard.tsx.ejs +19 -5
  56. package/hedhog/frontend/app/courses/[id]/_components/CourseMainInfoCard.tsx.ejs +10 -14
  57. package/hedhog/frontend/app/courses/[id]/_components/CourseMediaCard.tsx.ejs +131 -107
  58. package/hedhog/frontend/app/courses/[id]/_components/CourseRelationsCard.tsx.ejs +10 -7
  59. package/hedhog/frontend/app/courses/[id]/_components/CourseSectionCard.tsx.ejs +38 -19
  60. package/hedhog/frontend/app/courses/[id]/_components/CourseSummaryCard.tsx.ejs +1 -1
  61. package/hedhog/frontend/app/courses/[id]/_components/course-edit-types.ts.ejs +1 -1
  62. package/hedhog/frontend/app/courses/[id]/page.tsx.ejs +336 -1057
  63. package/hedhog/frontend/app/courses/[id]/structure/_components/confirm-dialog.tsx.ejs +45 -0
  64. package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-dnd.tsx.ejs +362 -0
  65. package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-panel.tsx.ejs +111 -0
  66. package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-skeleton.tsx.ejs +64 -0
  67. package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree.tsx.ejs +134 -0
  68. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-course.tsx.ejs +113 -0
  69. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-lesson.tsx.ejs +314 -0
  70. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-panel.tsx.ejs +62 -0
  71. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-session.tsx.ejs +174 -0
  72. package/hedhog/frontend/app/courses/[id]/structure/_components/drag-handle.tsx.ejs +58 -0
  73. package/hedhog/frontend/app/courses/[id]/structure/_components/drag-overlay.tsx.ejs +52 -0
  74. package/hedhog/frontend/app/courses/[id]/structure/_components/editor-bulk.tsx.ejs +276 -0
  75. package/hedhog/frontend/app/courses/[id]/structure/_components/editor-course.tsx.ejs +1216 -0
  76. package/hedhog/frontend/app/courses/[id]/structure/_components/editor-lesson.tsx.ejs +1827 -0
  77. package/hedhog/frontend/app/courses/[id]/structure/_components/editor-session.tsx.ejs +443 -0
  78. package/hedhog/frontend/app/courses/[id]/structure/_components/highlighted-text.tsx.ejs +41 -0
  79. package/hedhog/frontend/app/courses/[id]/structure/_components/mock-data.ts.ejs +184 -0
  80. package/hedhog/frontend/app/courses/[id]/structure/_components/multi-select-bar.tsx.ejs +264 -0
  81. package/hedhog/frontend/app/courses/[id]/structure/_components/search-filter.tsx.ejs +96 -0
  82. package/hedhog/frontend/app/courses/[id]/structure/_components/session-picker-dialog.tsx.ejs +74 -0
  83. package/hedhog/frontend/app/courses/[id]/structure/_components/shortcuts-help.tsx.ejs +136 -0
  84. package/hedhog/frontend/app/courses/[id]/structure/_components/sortable-tree-row.tsx.ejs +80 -0
  85. package/hedhog/frontend/app/courses/[id]/structure/_components/store.ts.ejs +948 -0
  86. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-context-menu.tsx.ejs +525 -0
  87. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-display-settings-popover.tsx.ejs +150 -0
  88. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-helpers.ts.ejs +182 -0
  89. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-course.tsx.ejs +52 -0
  90. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-lesson.tsx.ejs +271 -0
  91. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-session.tsx.ejs +167 -0
  92. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row.tsx.ejs +108 -0
  93. package/hedhog/frontend/app/courses/[id]/structure/_components/types.ts.ejs +122 -0
  94. package/hedhog/frontend/app/courses/[id]/structure/_components/use-course-structure-shortcuts.ts.ejs +318 -0
  95. package/hedhog/frontend/app/courses/[id]/structure/_components/use-tree-display-settings.ts.ejs +97 -0
  96. package/hedhog/frontend/app/courses/[id]/structure/_data/adapters/course-structure.adapter.ts.ejs +347 -0
  97. package/hedhog/frontend/app/courses/[id]/structure/_data/course-structure-contract.ts.ejs +195 -0
  98. package/hedhog/frontend/app/courses/[id]/structure/_data/services/course-structure.service.ts.ejs +420 -0
  99. package/hedhog/frontend/app/courses/[id]/structure/_data/types/api-course.types.ts.ejs +254 -0
  100. package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure-mutations.ts.ejs +987 -0
  101. package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure-query.ts.ejs +86 -0
  102. package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure.ts.ejs +160 -0
  103. package/hedhog/frontend/app/courses/[id]/structure/page.tsx.ejs +10 -3212
  104. package/hedhog/frontend/app/courses/page.tsx.ejs +45 -26
  105. package/hedhog/frontend/app/{training → paths}/page.tsx.ejs +29 -7
  106. package/hedhog/frontend/messages/en.json +91 -11
  107. package/hedhog/frontend/messages/pt.json +91 -11
  108. package/hedhog/table/course.yaml +1 -1
  109. package/hedhog/table/image_type.yaml +14 -0
  110. package/package.json +7 -7
  111. package/src/course/course-structure.controller.ts +63 -0
  112. package/src/course/course-structure.service.ts +390 -3
  113. package/src/course/course.service.ts +59 -27
  114. package/src/course/dto/create-course-structure-lesson.dto.ts +3 -2
  115. package/src/course/dto/create-course.dto.ts +4 -1
  116. package/src/course/dto/move-lesson.dto.ts +17 -0
  117. package/src/course/dto/paste-lessons.dto.ts +9 -0
  118. package/src/course/dto/reorder-lessons.dto.ts +10 -0
  119. package/src/course/dto/reorder-sessions.dto.ts +10 -0
  120. package/src/training/training.controller.ts +1 -1
@@ -1,11 +1,16 @@
1
1
  import { Button } from '@/components/ui/button';
2
- import { Progress } from '@/components/ui/progress';
3
- import { cn } from '@/lib/utils';
2
+ import {
3
+ Tooltip,
4
+ TooltipContent,
5
+ TooltipProvider,
6
+ TooltipTrigger,
7
+ } from '@/components/ui/tooltip';
4
8
  import {
5
9
  Eye,
6
10
  FileImage,
7
11
  ImagePlus,
8
12
  Loader2,
13
+ Trash2,
9
14
  UploadCloud,
10
15
  } from 'lucide-react';
11
16
  import { type ChangeEvent, useRef } from 'react';
@@ -18,35 +23,58 @@ type MediaFile = {
18
23
  name: string;
19
24
  };
20
25
 
21
- type MediaPaneProps = {
26
+ type ImageTypeSpec = {
27
+ suggestedWidth: number | null;
28
+ suggestedHeight: number | null;
29
+ allowedExtensions: string | null;
30
+ aspectRatio: string | null;
31
+ };
32
+
33
+ type MediaRowProps = {
22
34
  label: string;
23
- description: string;
24
- ratioClassName: string;
25
35
  preview: string | null;
26
36
  file?: MediaFile;
27
37
  loading: boolean;
38
+ imageType?: ImageTypeSpec | null;
28
39
  onSelect: (event: ChangeEvent<HTMLInputElement>) => void;
29
40
  onOpenFile?: () => void;
41
+ onRemoveFile?: () => void;
30
42
  };
31
43
 
32
- function MediaPane({
44
+ function MediaRow({
33
45
  label,
34
- description,
35
- ratioClassName,
36
46
  preview,
37
47
  file,
38
48
  loading,
49
+ imageType,
39
50
  onSelect,
40
51
  onOpenFile,
41
- }: MediaPaneProps) {
52
+ onRemoveFile,
53
+ }: MediaRowProps) {
42
54
  const inputRef = useRef<HTMLInputElement>(null);
43
55
 
56
+ const specParts: string[] = [];
57
+ if (imageType?.suggestedWidth && imageType?.suggestedHeight) {
58
+ specParts.push(
59
+ `${imageType.suggestedWidth}×${imageType.suggestedHeight}px`
60
+ );
61
+ }
62
+ if (imageType?.aspectRatio) {
63
+ specParts.push(imageType.aspectRatio);
64
+ }
65
+ if (imageType?.allowedExtensions) {
66
+ specParts.push(
67
+ imageType.allowedExtensions
68
+ .split(',')
69
+ .map((ext) => ext.trim().toUpperCase())
70
+ .join(' / ')
71
+ );
72
+ }
73
+ const specText = specParts.join(' · ');
74
+
44
75
  return (
45
- <div className="space-y-3">
46
- <div className="space-y-1">
47
- <p className="text-sm font-medium text-foreground">{label}</p>
48
- <p className="text-xs leading-5 text-muted-foreground">{description}</p>
49
- </div>
76
+ <div className="space-y-1.5">
77
+ <p className="text-xs font-medium text-muted-foreground">{label}</p>
50
78
 
51
79
  <input
52
80
  ref={inputRef}
@@ -56,99 +84,87 @@ function MediaPane({
56
84
  onChange={onSelect}
57
85
  />
58
86
 
59
- <button
60
- type="button"
61
- className={cn(
62
- 'group relative block w-full overflow-hidden rounded-2xl border border-border/70 bg-gradient-to-br from-muted/40 to-background text-left transition-all hover:border-border hover:shadow-sm',
63
- ratioClassName
64
- )}
65
- onClick={() => inputRef.current?.click()}
66
- >
87
+ <div className="relative h-40 w-full overflow-hidden rounded-xl border border-border/70 bg-muted/30">
67
88
  {preview ? (
68
- <>
69
- <img
70
- src={preview}
71
- alt={label}
72
- className="h-full w-full object-cover transition-transform duration-200 group-hover:scale-[1.02]"
73
- />
74
- <div className="absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/70 via-black/10 to-transparent p-4">
75
- <div className="flex flex-wrap gap-2">
76
- <span className="rounded-full bg-white/15 px-2.5 py-1 text-xs font-medium text-white backdrop-blur">
77
- Preview pronta
78
- </span>
79
- <span className="rounded-full bg-white/15 px-2.5 py-1 text-xs font-medium text-white backdrop-blur">
80
- Clique para substituir
81
- </span>
82
- </div>
83
- </div>
84
- </>
89
+ <img
90
+ src={preview}
91
+ alt={label}
92
+ className="h-full w-full object-contain"
93
+ />
85
94
  ) : (
86
- <div className="flex h-full flex-col items-center justify-center gap-3 px-6 text-center">
87
- <div className="flex h-12 w-12 items-center justify-center rounded-2xl border border-border/70 bg-background/80 text-muted-foreground">
88
- <ImagePlus className="h-5 w-5" />
89
- </div>
90
- <div className="space-y-1">
91
- <p className="text-sm font-medium text-foreground">
92
- Enviar {label.toLowerCase()}
93
- </p>
94
- <p className="text-xs leading-5 text-muted-foreground">
95
- Clique para selecionar uma imagem.
96
- </p>
97
- </div>
95
+ <div className="flex h-full flex-col items-center justify-center gap-2 text-center">
96
+ <ImagePlus className="h-5 w-5 text-muted-foreground" />
97
+ <p className="text-xs text-muted-foreground">Sem imagem</p>
98
98
  </div>
99
99
  )}
100
-
101
- {loading ? (
102
- <div className="absolute inset-0 flex flex-col items-center justify-center gap-3 bg-background/85">
103
- <Loader2 className="h-5 w-5 animate-spin text-foreground" />
104
- <div className="w-full max-w-[180px] space-y-2">
105
- <Progress value={72} className="h-2" />
106
- <p className="text-xs text-muted-foreground">Enviando arquivo...</p>
107
- </div>
100
+ {loading && (
101
+ <div className="absolute inset-0 flex items-center justify-center bg-background/70">
102
+ <Loader2 className="h-5 w-5 animate-spin" />
108
103
  </div>
104
+ )}
105
+ </div>
106
+
107
+ {specText ? (
108
+ <p className="text-[11px] text-muted-foreground/70">{specText}</p>
109
+ ) : null}
110
+
111
+ <div className="flex items-center justify-end gap-1">
112
+ <TooltipProvider>
113
+ <Tooltip>
114
+ <TooltipTrigger asChild>
115
+ <Button
116
+ type="button"
117
+ variant="outline"
118
+ size="icon"
119
+ className="h-7 w-7"
120
+ onClick={() => inputRef.current?.click()}
121
+ >
122
+ <UploadCloud className="h-3.5 w-3.5" />
123
+ </Button>
124
+ </TooltipTrigger>
125
+ <TooltipContent>
126
+ {preview ? 'Substituir imagem' : 'Enviar imagem'}
127
+ </TooltipContent>
128
+ </Tooltip>
129
+ </TooltipProvider>
130
+
131
+ {file && onOpenFile ? (
132
+ <TooltipProvider>
133
+ <Tooltip>
134
+ <TooltipTrigger asChild>
135
+ <Button
136
+ type="button"
137
+ variant="outline"
138
+ size="icon"
139
+ className="h-7 w-7"
140
+ onClick={onOpenFile}
141
+ >
142
+ <Eye className="h-3.5 w-3.5" />
143
+ </Button>
144
+ </TooltipTrigger>
145
+ <TooltipContent>Visualizar imagem original</TooltipContent>
146
+ </Tooltip>
147
+ </TooltipProvider>
109
148
  ) : null}
110
- </button>
111
149
 
112
- <div className="rounded-2xl border border-border/60 bg-muted/20 p-3">
113
- <div className="flex items-start gap-3">
114
- <div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-xl border border-border/60 bg-background text-muted-foreground">
115
- <FileImage className="h-4 w-4" />
116
- </div>
117
- <div className="min-w-0 flex-1">
118
- <p className="truncate text-sm font-medium text-foreground">
119
- {file?.name || 'Nenhum arquivo vinculado'}
120
- </p>
121
- <p className="text-xs text-muted-foreground">
122
- {file ? 'Arquivo pronto para uso.' : 'Ainda sem mídia vinculada.'}
123
- </p>
124
- </div>
125
- </div>
126
-
127
- <div className="mt-3 flex flex-wrap gap-2">
128
- <Button
129
- type="button"
130
- variant="outline"
131
- size="sm"
132
- className="gap-2"
133
- onClick={() => inputRef.current?.click()}
134
- >
135
- <UploadCloud className="h-4 w-4" />
136
- {preview ? 'Substituir' : 'Enviar'}
137
- </Button>
138
-
139
- {file && onOpenFile ? (
140
- <Button
141
- type="button"
142
- variant="ghost"
143
- size="sm"
144
- className="gap-2"
145
- onClick={onOpenFile}
146
- >
147
- <Eye className="h-4 w-4" />
148
- Visualizar
149
- </Button>
150
- ) : null}
151
- </div>
150
+ {file && onRemoveFile ? (
151
+ <TooltipProvider>
152
+ <Tooltip>
153
+ <TooltipTrigger asChild>
154
+ <Button
155
+ type="button"
156
+ variant="outline"
157
+ size="icon"
158
+ className="h-7 w-7 text-destructive hover:text-destructive"
159
+ onClick={onRemoveFile}
160
+ >
161
+ <Trash2 className="h-3.5 w-3.5" />
162
+ </Button>
163
+ </TooltipTrigger>
164
+ <TooltipContent>Remover imagem</TooltipContent>
165
+ </Tooltip>
166
+ </TooltipProvider>
167
+ ) : null}
152
168
  </div>
153
169
  </div>
154
170
  );
@@ -165,6 +181,10 @@ type CourseMediaCardProps = {
165
181
  bannerFile?: MediaFile;
166
182
  onOpenLogoFile?: () => void;
167
183
  onOpenBannerFile?: () => void;
184
+ onRemoveLogoFile?: () => void;
185
+ onRemoveBannerFile?: () => void;
186
+ logoImageType?: ImageTypeSpec | null;
187
+ bannerImageType?: ImageTypeSpec | null;
168
188
  t: TranslationFn;
169
189
  };
170
190
 
@@ -179,6 +199,10 @@ export function CourseMediaCard({
179
199
  bannerFile,
180
200
  onOpenLogoFile,
181
201
  onOpenBannerFile,
202
+ onRemoveLogoFile,
203
+ onRemoveBannerFile,
204
+ logoImageType,
205
+ bannerImageType,
182
206
  t,
183
207
  }: CourseMediaCardProps) {
184
208
  return (
@@ -187,27 +211,27 @@ export function CourseMediaCard({
187
211
  description="Gerencie os ativos visuais do curso com preview e ações rápidas."
188
212
  icon={FileImage}
189
213
  >
190
- <div className="space-y-5">
191
- <MediaPane
214
+ <div className="space-y-4">
215
+ <MediaRow
192
216
  label={t('form.fields.banner.label')}
193
- description={t('form.fields.banner.description')}
194
- ratioClassName="aspect-[16/9]"
195
217
  preview={bannerPreview}
196
218
  file={bannerFile}
197
219
  loading={uploadingBanner}
220
+ imageType={bannerImageType}
198
221
  onSelect={onBannerSelect}
199
222
  onOpenFile={onOpenBannerFile}
223
+ onRemoveFile={onRemoveBannerFile}
200
224
  />
201
225
 
202
- <MediaPane
226
+ <MediaRow
203
227
  label={t('form.fields.logo.label')}
204
- description={t('form.fields.logo.description')}
205
- ratioClassName="aspect-square max-w-[220px]"
206
228
  preview={logoPreview}
207
229
  file={logoFile}
208
230
  loading={uploadingLogo}
231
+ imageType={logoImageType}
209
232
  onSelect={onLogoSelect}
210
233
  onOpenFile={onOpenLogoFile}
234
+ onRemoveFile={onRemoveLogoFile}
211
235
  />
212
236
  </div>
213
237
  </CourseSectionCard>
@@ -22,7 +22,9 @@ type CourseRelationsCardProps = {
22
22
  t: TranslationFn;
23
23
  categoryOptions: PickerOption[];
24
24
  instructorOptions: PickerOption[];
25
- onCreateCategory: (values: Record<string, string>) => Promise<PickerOption | null>;
25
+ onCreateCategory: (
26
+ values: Record<string, string>
27
+ ) => Promise<PickerOption | null>;
26
28
  onCreateInstructor: () => void;
27
29
  };
28
30
 
@@ -40,7 +42,7 @@ export function CourseRelationsCard({
40
42
  description="Agrupe os vínculos que ajudam a encontrar, operar e ensinar este curso."
41
43
  icon={Network}
42
44
  >
43
- <div className="space-y-5">
45
+ <div className="space-y-3">
44
46
  <FormField
45
47
  control={form.control}
46
48
  name="categorias"
@@ -52,7 +54,9 @@ export function CourseRelationsCard({
52
54
  onChange={field.onChange}
53
55
  options={categoryOptions}
54
56
  placeholder={t('form.fields.categories.selectPlaceholder')}
55
- searchPlaceholder={t('form.fields.categories.searchPlaceholder')}
57
+ searchPlaceholder={t(
58
+ 'form.fields.categories.searchPlaceholder'
59
+ )}
56
60
  entityLabel="categoria"
57
61
  emptyStateDescription={t('form.fields.categories.noResults')}
58
62
  emptyHint="Nenhuma categoria vinculada ainda."
@@ -101,7 +105,9 @@ export function CourseRelationsCard({
101
105
  onChange={field.onChange}
102
106
  options={instructorOptions}
103
107
  placeholder={t('form.fields.instructors.selectPlaceholder')}
104
- searchPlaceholder={t('form.fields.instructors.searchPlaceholder')}
108
+ searchPlaceholder={t(
109
+ 'form.fields.instructors.searchPlaceholder'
110
+ )}
105
111
  entityLabel="instrutor"
106
112
  emptyStateDescription={t('form.fields.instructors.noResults')}
107
113
  emptyHint="Nenhum instrutor vinculado ainda."
@@ -128,9 +134,6 @@ export function CourseRelationsCard({
128
134
  placeholder={t('form.fields.prerequisites.placeholder')}
129
135
  />
130
136
  </FormControl>
131
- <p className="text-sm text-muted-foreground">
132
- {t('form.fields.prerequisites.description')}
133
- </p>
134
137
  <FormMessage />
135
138
  </FormItem>
136
139
  )}
@@ -1,4 +1,10 @@
1
1
  import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
2
+ import {
3
+ Tooltip,
4
+ TooltipContent,
5
+ TooltipProvider,
6
+ TooltipTrigger,
7
+ } from '@/components/ui/tooltip';
2
8
  import { cn } from '@/lib/utils';
3
9
  import type { LucideIcon } from 'lucide-react';
4
10
  import type { ReactNode } from 'react';
@@ -22,27 +28,40 @@ export function CourseSectionCard({
22
28
  contentClassName,
23
29
  action,
24
30
  }: CourseSectionCardProps) {
31
+ const iconEl = Icon ? (
32
+ <div className="flex h-7 w-7 shrink-0 items-center justify-center rounded-lg border border-border/60 bg-muted/30 text-foreground">
33
+ <Icon className="h-3.5 w-3.5" />
34
+ </div>
35
+ ) : null;
36
+
25
37
  return (
26
38
  <Card className={cn('border-border/70 shadow-sm', className)}>
27
- <CardHeader className="space-y-3 pb-4">
28
- <div className="flex items-start justify-between gap-3">
29
- <div className="flex min-w-0 items-start gap-3">
30
- {Icon ? (
31
- <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border border-border/60 bg-muted/30 text-foreground">
32
- <Icon className="h-4 w-4" />
33
- </div>
34
- ) : null}
35
-
36
- <div className="min-w-0 space-y-1">
37
- <CardTitle className="text-base font-semibold tracking-tight">
38
- {title}
39
- </CardTitle>
40
- {description ? (
41
- <p className="text-sm leading-5 text-muted-foreground">
42
- {description}
43
- </p>
44
- ) : null}
45
- </div>
39
+ <CardHeader className="space-y-1.5 pb-3">
40
+ <div className="flex items-center justify-between gap-3">
41
+ <div className="flex min-w-0 items-center gap-2">
42
+ {Icon && description ? (
43
+ <TooltipProvider>
44
+ <Tooltip>
45
+ <TooltipTrigger asChild>
46
+ <button
47
+ type="button"
48
+ tabIndex={-1}
49
+ className="cursor-default focus:outline-none"
50
+ >
51
+ {iconEl}
52
+ </button>
53
+ </TooltipTrigger>
54
+ <TooltipContent side="right" className="max-w-65 text-xs">
55
+ {description}
56
+ </TooltipContent>
57
+ </Tooltip>
58
+ </TooltipProvider>
59
+ ) : (
60
+ iconEl
61
+ )}
62
+ <CardTitle className="text-sm font-semibold tracking-tight">
63
+ {title}
64
+ </CardTitle>
46
65
  </div>
47
66
 
48
67
  {action ? <div className="shrink-0">{action}</div> : null}
@@ -54,7 +54,7 @@ export function CourseSummaryCard({ course }: CourseSummaryCardProps) {
54
54
  },
55
55
  ]}
56
56
  columns={4}
57
- className="mb-8"
57
+ className="mb-3"
58
58
  />
59
59
  );
60
60
  }
@@ -1,5 +1,5 @@
1
1
  export type CourseEditFormValues = {
2
- codigo: string;
2
+ slug: string;
3
3
  nomeInterno: string;
4
4
  tituloComercial: string;
5
5
  descricaoPublica: string;