|
2 | 2 |
|
3 | 3 | import { useRef, useState } from 'react' |
4 | 4 | import { AlertCircle, Loader2, X } from 'lucide-react' |
5 | | -import { |
6 | | - AlertDialog, |
7 | | - AlertDialogAction, |
8 | | - AlertDialogCancel, |
9 | | - AlertDialogContent, |
10 | | - AlertDialogDescription, |
11 | | - AlertDialogFooter, |
12 | | - AlertDialogHeader, |
13 | | - AlertDialogTitle, |
14 | | -} from '@/components/ui/alert-dialog' |
15 | | -import { Button } from '@/components/ui/button' |
16 | | -import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog' |
| 5 | +import { Button, Modal, ModalContent, ModalTitle, Textarea } from '@/components/emcn' |
17 | 6 | import { Label } from '@/components/ui/label' |
18 | | -import { Textarea } from '@/components/ui/textarea' |
19 | 7 | import { createLogger } from '@/lib/logs/console/logger' |
20 | 8 | import type { ChunkData, DocumentData } from '@/stores/knowledge/store' |
21 | 9 |
|
@@ -123,109 +111,135 @@ export function CreateChunkModal({ |
123 | 111 |
|
124 | 112 | return ( |
125 | 113 | <> |
126 | | - <Dialog open={open} onOpenChange={handleCloseAttempt}> |
127 | | - <DialogContent |
| 114 | + <Modal open={open} onOpenChange={handleCloseAttempt}> |
| 115 | + <ModalContent |
128 | 116 | className='flex h-[74vh] flex-col gap-0 overflow-hidden p-0 sm:max-w-[600px]' |
129 | | - hideCloseButton |
| 117 | + showClose={false} |
130 | 118 | > |
131 | | - <DialogHeader className='flex-shrink-0 border-b px-6 py-4'> |
| 119 | + {/* Modal Header */} |
| 120 | + <div className='flex-shrink-0 px-6 py-5'> |
132 | 121 | <div className='flex items-center justify-between'> |
133 | | - <DialogTitle className='font-medium text-lg'>Create Chunk</DialogTitle> |
134 | | - <Button |
135 | | - variant='ghost' |
136 | | - size='icon' |
137 | | - className='h-8 w-8 p-0' |
138 | | - onClick={handleCloseAttempt} |
139 | | - > |
| 122 | + <ModalTitle className='font-medium text-[14px] text-[var(--text-primary)] dark:text-[var(--text-primary)]'> |
| 123 | + Create Chunk |
| 124 | + </ModalTitle> |
| 125 | + <Button variant='ghost' className='h-8 w-8 p-0' onClick={handleCloseAttempt}> |
140 | 126 | <X className='h-4 w-4' /> |
141 | 127 | <span className='sr-only'>Close</span> |
142 | 128 | </Button> |
143 | 129 | </div> |
144 | | - </DialogHeader> |
145 | | - |
146 | | - <div className='flex flex-1 flex-col overflow-hidden'> |
147 | | - <div className='min-h-0 flex-1 overflow-y-auto px-6'> |
148 | | - <div className='flex min-h-full flex-col py-4'> |
149 | | - {/* Document Info Section - Fixed at top */} |
150 | | - <div className='flex-shrink-0 space-y-4'> |
151 | | - <div className='flex items-center gap-3 rounded-lg border bg-muted/30 p-4'> |
152 | | - <div className='min-w-0 flex-1'> |
153 | | - <p className='font-medium text-sm'> |
154 | | - {document?.filename || 'Unknown Document'} |
155 | | - </p> |
156 | | - <p className='text-muted-foreground text-xs'>Adding chunk to this document</p> |
| 130 | + </div> |
| 131 | + |
| 132 | + {/* Modal Body */} |
| 133 | + <div className='relative flex min-h-0 flex-1 flex-col overflow-hidden'> |
| 134 | + <form className='flex min-h-0 flex-1 flex-col'> |
| 135 | + {/* Scrollable Content */} |
| 136 | + <div className='scrollbar-hide min-h-0 flex-1 overflow-y-auto pb-20'> |
| 137 | + <div className='flex min-h-full flex-col px-6'> |
| 138 | + <div className='flex flex-1 flex-col space-y-[12px] pt-0 pb-6'> |
| 139 | + {/* Document Info Section */} |
| 140 | + <div className='flex-shrink-0 space-y-[8px]'> |
| 141 | + <div className='flex items-center gap-3 rounded-lg border bg-muted/30 p-4'> |
| 142 | + <div className='min-w-0 flex-1'> |
| 143 | + <p className='font-medium text-sm'> |
| 144 | + {document?.filename || 'Unknown Document'} |
| 145 | + </p> |
| 146 | + <p className='text-muted-foreground text-xs'> |
| 147 | + Adding chunk to this document |
| 148 | + </p> |
| 149 | + </div> |
| 150 | + </div> |
| 151 | + |
| 152 | + {/* Error Display */} |
| 153 | + {error && ( |
| 154 | + <div className='flex items-center gap-2 rounded-md border border-red-200 bg-red-50 p-3'> |
| 155 | + <AlertCircle className='h-4 w-4 text-red-600' /> |
| 156 | + <p className='text-red-800 text-sm'>{error}</p> |
| 157 | + </div> |
| 158 | + )} |
157 | 159 | </div> |
158 | | - </div> |
159 | 160 |
|
160 | | - {/* Error Display */} |
161 | | - {error && ( |
162 | | - <div className='flex items-center gap-2 rounded-md border border-red-200 bg-red-50 p-3'> |
163 | | - <AlertCircle className='h-4 w-4 text-red-600' /> |
164 | | - <p className='text-red-800 text-sm'>{error}</p> |
| 161 | + {/* Content Input Section - Expands to fill space */} |
| 162 | + <div className='flex min-h-0 flex-1 flex-col space-y-[8px]'> |
| 163 | + <Label |
| 164 | + htmlFor='content' |
| 165 | + className='font-medium text-[13px] text-[var(--text-primary)] dark:text-[var(--text-primary)]' |
| 166 | + > |
| 167 | + Chunk Content |
| 168 | + </Label> |
| 169 | + <Textarea |
| 170 | + id='content' |
| 171 | + value={content} |
| 172 | + onChange={(e) => setContent(e.target.value)} |
| 173 | + placeholder='Enter the content for this chunk...' |
| 174 | + className='min-h-0 flex-1 resize-none' |
| 175 | + disabled={isCreating} |
| 176 | + /> |
165 | 177 | </div> |
166 | | - )} |
| 178 | + </div> |
167 | 179 | </div> |
| 180 | + </div> |
168 | 181 |
|
169 | | - {/* Content Input Section - Expands to fill remaining space */} |
170 | | - <div className='mt-4 flex flex-1 flex-col'> |
171 | | - <Label htmlFor='content' className='mb-2 font-medium text-sm'> |
172 | | - Chunk Content |
173 | | - </Label> |
174 | | - <Textarea |
175 | | - id='content' |
176 | | - value={content} |
177 | | - onChange={(e) => setContent(e.target.value)} |
178 | | - placeholder='Enter the content for this chunk...' |
179 | | - className='flex-1 resize-none' |
| 182 | + {/* Fixed Footer with Actions */} |
| 183 | + <div className='absolute inset-x-0 bottom-0 bg-[var(--surface-1)] dark:bg-[var(--surface-1)]'> |
| 184 | + <div className='flex w-full items-center justify-between gap-[8px] px-6 py-4'> |
| 185 | + <Button |
| 186 | + variant='default' |
| 187 | + onClick={handleCloseAttempt} |
| 188 | + type='button' |
180 | 189 | disabled={isCreating} |
181 | | - /> |
| 190 | + > |
| 191 | + Cancel |
| 192 | + </Button> |
| 193 | + <Button |
| 194 | + variant='primary' |
| 195 | + onClick={handleCreateChunk} |
| 196 | + type='button' |
| 197 | + disabled={!isFormValid || isCreating} |
| 198 | + > |
| 199 | + {isCreating ? ( |
| 200 | + <> |
| 201 | + <Loader2 className='mr-2 h-4 w-4 animate-spin' /> |
| 202 | + Creating... |
| 203 | + </> |
| 204 | + ) : ( |
| 205 | + 'Create Chunk' |
| 206 | + )} |
| 207 | + </Button> |
182 | 208 | </div> |
183 | 209 | </div> |
184 | | - </div> |
185 | | - |
186 | | - {/* Footer */} |
187 | | - <div className='mt-auto border-t px-6 pt-4 pb-6'> |
188 | | - <div className='flex justify-between'> |
189 | | - <Button variant='outline' onClick={handleCloseAttempt} disabled={isCreating}> |
190 | | - Cancel |
191 | | - </Button> |
192 | | - <Button |
193 | | - onClick={handleCreateChunk} |
194 | | - disabled={!isFormValid || isCreating} |
195 | | - className='bg-[var(--brand-primary-hex)] font-[480] text-primary-foreground shadow-[0_0_0_0_var(--brand-primary-hex)] transition-all duration-200 hover:bg-[var(--brand-primary-hover-hex)] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]' |
196 | | - > |
197 | | - {isCreating ? ( |
198 | | - <> |
199 | | - <Loader2 className='mr-2 h-4 w-4 animate-spin' /> |
200 | | - Creating... |
201 | | - </> |
202 | | - ) : ( |
203 | | - 'Create Chunk' |
204 | | - )} |
205 | | - </Button> |
206 | | - </div> |
207 | | - </div> |
| 210 | + </form> |
208 | 211 | </div> |
209 | | - </DialogContent> |
210 | | - </Dialog> |
| 212 | + </ModalContent> |
| 213 | + </Modal> |
211 | 214 |
|
212 | 215 | {/* Unsaved Changes Alert */} |
213 | | - <AlertDialog open={showUnsavedChangesAlert} onOpenChange={setShowUnsavedChangesAlert}> |
214 | | - <AlertDialogContent> |
215 | | - <AlertDialogHeader> |
216 | | - <AlertDialogTitle>Discard changes?</AlertDialogTitle> |
217 | | - <AlertDialogDescription> |
| 216 | + <Modal open={showUnsavedChangesAlert} onOpenChange={setShowUnsavedChangesAlert}> |
| 217 | + <ModalContent className='flex flex-col gap-0 p-0'> |
| 218 | + {/* Modal Header */} |
| 219 | + <div className='flex-shrink-0 px-6 py-5'> |
| 220 | + <ModalTitle className='font-medium text-[14px] text-[var(--text-primary)] dark:text-[var(--text-primary)]'> |
| 221 | + Discard changes? |
| 222 | + </ModalTitle> |
| 223 | + <p className='mt-2 text-[12px] text-[var(--text-secondary)] dark:text-[var(--text-secondary)]'> |
218 | 224 | You have unsaved changes. Are you sure you want to close without saving? |
219 | | - </AlertDialogDescription> |
220 | | - </AlertDialogHeader> |
221 | | - <AlertDialogFooter> |
222 | | - <AlertDialogCancel onClick={() => setShowUnsavedChangesAlert(false)}> |
| 225 | + </p> |
| 226 | + </div> |
| 227 | + |
| 228 | + {/* Modal Footer */} |
| 229 | + <div className='flex w-full items-center justify-between gap-[8px] px-6 py-4'> |
| 230 | + <Button |
| 231 | + variant='default' |
| 232 | + onClick={() => setShowUnsavedChangesAlert(false)} |
| 233 | + type='button' |
| 234 | + > |
223 | 235 | Keep editing |
224 | | - </AlertDialogCancel> |
225 | | - <AlertDialogAction onClick={handleConfirmDiscard}>Discard changes</AlertDialogAction> |
226 | | - </AlertDialogFooter> |
227 | | - </AlertDialogContent> |
228 | | - </AlertDialog> |
| 236 | + </Button> |
| 237 | + <Button variant='primary' onClick={handleConfirmDiscard} type='button'> |
| 238 | + Discard changes |
| 239 | + </Button> |
| 240 | + </div> |
| 241 | + </ModalContent> |
| 242 | + </Modal> |
229 | 243 | </> |
230 | 244 | ) |
231 | 245 | } |
0 commit comments