@@ -206,51 +206,45 @@ const ToolbarInner = ({
206
206
< div className = "flex-grow transition-opacity opacity-100 group-data-[toggled=false]/toolbar:opacity-0 overflow-y-auto px-2 pt-3" >
207
207
< Tabs . Content value = "linter" >
208
208
{ lintLoading ? (
209
- < div className = "animate-pulse text-slate-11 text-sm pt-1" >
210
- Running linting...
211
- </ div >
209
+ < LoadingState message = "Analyzing your code for linting issues..." />
212
210
) : lintingRows ?. length === 0 ? (
213
- < div className = "flex flex-col items-center justify-center pt-8" >
211
+ < SuccessWrapper >
214
212
< SuccessIcon />
215
213
< SuccessTitle > All good</ SuccessTitle >
216
214
< SuccessDescription >
217
215
No linting issues found.
218
216
</ SuccessDescription >
219
- </ div >
217
+ </ SuccessWrapper >
220
218
) : (
221
219
< Linter rows = { lintingRows ?? [ ] } />
222
220
) }
223
221
</ Tabs . Content >
224
222
< Tabs . Content value = "compatibility" >
225
223
{ compatibilityLoading ? (
226
- < div className = "animate-pulse text-slate-11 text-sm pt-1" >
227
- Running compatibility check...
228
- </ div >
224
+ < LoadingState message = "Checking email compatibility..." />
229
225
) : compatibilityCheckingResults ?. length === 0 ? (
230
- < div className = "flex flex-col items-center justify-center pt-8" >
226
+ < SuccessWrapper >
231
227
< SuccessIcon />
232
228
< SuccessTitle > Great compatibility</ SuccessTitle >
233
229
< SuccessDescription >
234
230
Template should render properly everywhere.
235
231
</ SuccessDescription >
236
- </ div >
232
+ </ SuccessWrapper >
237
233
) : (
238
234
< Compatibility results = { compatibilityCheckingResults ?? [ ] } />
239
235
) }
240
236
</ Tabs . Content >
241
237
< Tabs . Content value = "spam-assassin" >
242
238
{ spamLoading ? (
243
- < div className = "animate-pulse text-slate-11 text-sm pt-1" >
244
- Running spam check...
245
- </ div >
239
+ < LoadingState message = "Evaluating your email for spam indicators..." />
246
240
) : spamCheckingResult ?. isSpam === false ? (
247
- < div className = "flex flex-col items-center justify-center pt-8" >
241
+ < SuccessWrapper >
248
242
< SuccessIcon />
249
243
< SuccessTitle > 10/10</ SuccessTitle >
250
244
< SuccessDescription >
251
245
Your email is clean of abuse indicators.
252
246
</ SuccessDescription >
253
- </ div >
247
+ </ SuccessWrapper >
254
248
) : (
255
249
< SpamAssassin result = { spamCheckingResult } />
256
250
) }
@@ -262,6 +256,32 @@ const ToolbarInner = ({
262
256
) ;
263
257
} ;
264
258
259
+ const LoadingState = ( { message } : { message : string } ) => {
260
+ return (
261
+ < div className = "flex flex-col items-center justify-center pt-8" >
262
+ < div className = "relative mb-8 flex items-center justify-center" >
263
+ < div className = "h-12 w-12 rounded-full bg-gradient-to-br from-cyan-400/80 to-cyan-600/80 opacity-10 blur-xl absolute m-auto left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 animate-pulse" />
264
+ < div className = "h-12 w-12 rounded-full border border-slate-4 absolute m-auto left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" />
265
+ < div className = "h-10 w-10 rounded-full flex items-center justify-center absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" >
266
+ < div className = "h-5 w-5 rounded-full border-2 border-white/50 border-t-transparent animate-spin-fast" />
267
+ </ div >
268
+ </ div >
269
+ < h3 className = "text-slate-12 font-medium text-base mb-1" > Processing</ h3 >
270
+ < p className = "text-slate-11 text-sm text-center max-w-[320px]" >
271
+ { message }
272
+ </ p >
273
+ </ div >
274
+ ) ;
275
+ } ;
276
+
277
+ const SuccessWrapper = ( { children } : { children : React . ReactNode } ) => {
278
+ return (
279
+ < div className = "flex flex-col items-center justify-center pt-8" >
280
+ { children }
281
+ </ div >
282
+ ) ;
283
+ } ;
284
+
265
285
const SuccessIcon = ( ) => {
266
286
return (
267
287
< div className = "relative mb-8 flex items-center justify-center" >
0 commit comments