1 import { useState } from "react";
2 import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
3 import { Button } from "@/components/ui/button";
4 import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
5 import { apiRequest } from "@/lib/queryClient";
6 import {
7 Bookmark,
8 X,
9 AlertTriangle,
10 Wrench,
11 Clock,
12 Sparkles,
13 CheckCircle2,
14 Info,
15 ShieldAlert,
16 Share2,
17 Printer,
18 Laptop,
19 Monitor,
20 Cpu,
21 Code,
22 Eraser,
23 MoveUp,
24 ExternalLink,
25 ChevronRight,
26 Zap,
27 Gauge,
28 ListOrdered,
29 FileCheck2,
30 SlidersHorizontal,
31 Check
32 } from "lucide-react";
33 import type { RepairGuide, DeviceModel, RepairStep } from "@shared/schema";
34 import { cn } from "@/lib/utils";
35 import { useToast } from "@/hooks/use-toast";
36
37 interface GuideDetailModalProps {
38 guideId: string;
39 onClose: () => void;
40 isPage?: boolean;
41 }
42
43 export default function GuideDetailModal({ guideId, onClose, isPage = false }: GuideDetailModalProps) {
44 const queryClient = useQueryClient();
45 const { toast } = useToast();
46 const [completedSteps, setCompletedSteps] = useState<number[]>([]);
47 const [checkedSubSteps, setCheckedSubSteps] = useState<Record<string, boolean>>({});
48
49 const { data: guide, isLoading, error } = useQuery<RepairGuide>({
50 queryKey: ["/api/repair-guides", guideId],
51 queryFn: () => fetch(`/api/repair-guides/${guideId}`).then(res => res.json()),
52 enabled: !!guideId,
53 });
54
55 const { data: compatibleModels = [] } = useQuery<DeviceModel[]>({
56 queryKey: ["/api/guides", guideId, "models"],
57 queryFn: () => fetch(`/api/guides/${guideId}/models`).then(res => res.json()),
58 enabled: !!guideId,
59 });
60
61 const bookmarkMutation = useMutation({
62 mutationFn: () => apiRequest("PATCH", `/api/repair-guides/${guideId}/bookmark`),
63 onSuccess: () => {
64 queryClient.invalidateQueries({ queryKey: ["/api/repair-guides", guideId] });
65 queryClient.invalidateQueries({ queryKey: ["api", "repair-guides"] });
66 toast({
67 title: guide?.isBookmarked ? "Removed from Bookmarks" : "Saved to Bookmarks",
68 description: guide?.isBookmarked ? "Guide removed from your favorites." : "Guide added to your saved offline repair library.",
69 });
70 },
71 });
72
73 const toggleStep = (stepNumber: number) => {
74 setCompletedSteps(prev =>
75 prev.includes(stepNumber)
76 ? prev.filter(s => s !== stepNumber)
77 : [...prev, stepNumber]
78 );
79 };
80
81 const toggleSubStep = (stepNumber: number, subIndex: number, e: React.MouseEvent) => {
82 e.stopPropagation();
83 const key = `${stepNumber}-${subIndex}`;
84 setCheckedSubSteps(prev => ({
85 ...prev,
86 [key]: !prev[key]
87 }));
88 };
89
90 const handleCopyLink = () => {
91 const url = `${window.location.origin}/guide/${guideId}`;
92 navigator.clipboard.writeText(url);
93 toast({
94 title: "Link Copied",
95 description: "Direct guide URL has been copied to your clipboard.",
96 });
97 };
98
99 const handlePrint = () => {
100 window.print();
101 };
102
103 if (isLoading) {
104 const SkeletonUI = (
105 <div className="p-6 md:p-8 space-y-6 animate-pulse">
106 <div className="h-8 bg-muted rounded-2xl w-3/4" />
107 <div className="h-4 bg-muted rounded-xl w-1/2" />
108 <div className="grid grid-cols-3 gap-4 pt-4">
109 <div className="h-20 bg-muted rounded-2xl" />
110 <div className="h-20 bg-muted rounded-2xl" />
111 <div className="h-20 bg-muted rounded-2xl" />
112 </div>
113 <div className="space-y-4 pt-4">
114 <div className="h-32 bg-muted rounded-2xl" />
115 <div className="h-32 bg-muted rounded-2xl" />
116 </div>
117 </div>
118 );
119
120 if (isPage) return <div className="bg-card rounded-3xl border border-border/50">{SkeletonUI}</div>;
121 return (
122 <Dialog open={true} onOpenChange={() => onClose()}>
123 <DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto p-0 rounded-3xl border-border/60 bg-card">
124 {SkeletonUI}
125 </DialogContent>
126 </Dialog>
127 );
128 }
129
130 if (error || !guide) {
131 const ErrorUI = (
132 <div className="p-8 text-center space-y-4">
133 <div className="h-12 w-12 rounded-full bg-destructive/10 text-destructive flex items-center justify-center mx-auto">
134 <ShieldAlert className="h-6 w-6" />
135 </div>
136 <h3 className="text-lg font-bold">Failed to load repair guide</h3>
137 <p className="text-sm text-muted-foreground">The requested manual could not be retrieved from the database.</p>
138 <Button onClick={onClose} variant="outline" className="rounded-full">Close</Button>
139 </div>
140 );
141
142 if (isPage) return <div className="bg-card rounded-3xl border border-border/50">{ErrorUI}</div>;
143 return (
144 <Dialog open={true} onOpenChange={() => onClose()}>
145 <DialogContent className="max-w-md p-0 rounded-3xl border-border/60 bg-card">{ErrorUI}</DialogContent>
146 </Dialog>
147 );
148 }
149
150 const getDifficultyColor = (diff: string) => {
151 switch (diff) {
152 case "easy": return "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 border-emerald-500/20";
153 case "medium": return "bg-amber-500/10 text-amber-600 dark:text-amber-400 border-amber-500/20";
154 case "hard": return "bg-rose-500/10 text-rose-600 dark:text-rose-400 border-rose-500/20";
155 default: return "bg-muted text-muted-foreground";
156 }
157 };
158
159 const getCategoryTheme = (cat: string) => {
160 switch (cat) {
161 case "hardware": return { label: "Hardware Repair", icon: Cpu, badge: "bg-indigo-500/10 text-indigo-600 dark:text-indigo-400 border-indigo-500/20" };
162 case "software": return { label: "Software / OS Protocol", icon: Code, badge: "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 border-emerald-500/20" };
163 case "cleaning": return { label: "Thermal & Cleaning", icon: Eraser, badge: "bg-amber-500/10 text-amber-600 dark:text-amber-400 border-amber-500/20" };
164 case "upgrades": return { label: "Performance Upgrade", icon: MoveUp, badge: "bg-purple-500/10 text-purple-600 dark:text-purple-400 border-purple-500/20" };
165 default: return { label: "Technical Guide", icon: Wrench, badge: "bg-primary/10 text-primary border-primary/20" };
166 }
167 };
168
169 const catTheme = getCategoryTheme(guide.category);
170 const CategoryIcon = catTheme.icon;
171 const steps = (guide.steps || []) as RepairStep[];
172
173 const content = (
174 <div className="space-y-6">
175 {/* Header Banner */}
176 <div className="p-6 md:p-8 border-b border-border/40 space-y-4 bg-muted/20">
177 <div className="flex flex-wrap items-center justify-between gap-3">
178 <div className="flex flex-wrap items-center gap-2">
179 <span className={cn("text-[11px] font-bold uppercase tracking-wider px-3 py-1 rounded-full border flex items-center gap-1.5", catTheme.badge)}>
180 <CategoryIcon className="h-3.5 w-3.5" />
181 {catTheme.label}
182 </span>
183 <span className={cn("text-[11px] font-bold uppercase tracking-wider px-3 py-1 rounded-full border", getDifficultyColor(guide.difficulty))}>
184 {guide.difficulty} Difficulty
185 </span>
186 <span className="text-[11px] font-semibold text-muted-foreground bg-muted/80 px-3 py-1 rounded-full border border-border/50 flex items-center gap-1">
187 {guide.deviceType === "laptop" ? <Laptop className="h-3.5 w-3.5" /> : <Monitor className="h-3.5 w-3.5" />}
188 {guide.deviceType === "laptop" ? "Laptop & Ultrabook" : "Desktop PC & Tower"}
189 </span>
190 </div>
191
192 <div className="flex items-center gap-2">
193 <Button
194 variant="outline"
195 size="sm"
196 onClick={() => bookmarkMutation.mutate()}
197 className={cn("h-8 rounded-xl text-xs gap-1.5 border-border/60 transition-colors", guide.isBookmarked && "bg-amber-500/10 text-amber-600 border-amber-500/30")}
198 >
199 <Bookmark className={cn("h-3.5 w-3.5", guide.isBookmarked && "fill-amber-500 text-amber-500")} />
200 <span>{guide.isBookmarked ? "Saved" : "Save"}</span>
201 </Button>
202 <Button
203 variant="outline"
204 size="sm"
205 onClick={handleCopyLink}
206 className="h-8 rounded-xl text-xs gap-1.5 border-border/60"
207 >
208 <Share2 className="h-3.5 w-3.5" />
209 <span>Share</span>
210 </Button>
211 <Button
212 variant="outline"
213 size="sm"
214 onClick={handlePrint}
215 className="h-8 rounded-xl text-xs gap-1.5 border-border/60 hidden sm:flex"
216 >
217 <Printer className="h-3.5 w-3.5" />
218 <span>Print</span>
219 </Button>
220 {!isPage && (
221 <Button
222 variant="ghost"
223 size="icon"
224 className="h-8 w-8 rounded-full ml-1"
225 onClick={onClose}
226 >
227 <X className="h-5 w-5" />
228 </Button>
229 )}
230 </div>
231 </div>
232
233 <DialogTitle className="text-xl sm:text-2xl md:text-3xl font-extrabold tracking-tight text-foreground leading-snug">
234 {guide.title}
235 </DialogTitle>
236
237 <p className="text-xs sm:text-sm text-muted-foreground leading-relaxed max-w-3xl">
238 {guide.description}
239 </p>
240
241 {/* Quick Bench Metrics */}
242 <div className="grid grid-cols-2 sm:grid-cols-4 gap-3 pt-2">
243 <div className="p-3.5 rounded-2xl bg-card/60 border border-border/40 flex items-center gap-3">
244 <div className="h-9 w-9 rounded-xl bg-primary/10 text-primary flex items-center justify-center shrink-0">
245 <Clock className="h-4 w-4" />
246 </div>
247 <div>
248 <div className="text-[10px] font-bold text-muted-foreground uppercase">Estimated Time</div>
249 <div className="text-xs font-bold text-foreground">{guide.estimatedTime}</div>
250 </div>
251 </div>
252
253 <div className="p-3.5 rounded-2xl bg-card/60 border border-border/40 flex items-center gap-3">
254 <div className="h-9 w-9 rounded-xl bg-indigo-500/10 text-indigo-500 flex items-center justify-center shrink-0">
255 <Wrench className="h-4 w-4" />
256 </div>
257 <div>
258 <div className="text-[10px] font-bold text-muted-foreground uppercase">Bench Tools</div>
259 <div className="text-xs font-bold text-foreground">{guide.toolsRequired ? guide.toolsRequired.length : 0} items</div>
260 </div>
261 </div>
262
263 <div className="p-3.5 rounded-2xl bg-card/60 border border-border/40 flex items-center gap-3">
264 <div className="h-9 w-9 rounded-xl bg-purple-500/10 text-purple-500 flex items-center justify-center shrink-0">
265 <ListOrdered className="h-4 w-4" />
266 </div>
267 <div>
268 <div className="text-[10px] font-bold text-muted-foreground uppercase">Total Steps</div>
269 <div className="text-xs font-bold text-foreground">{steps.length} detailed phases</div>
270 </div>
271 </div>
272
273 <div className="p-3.5 rounded-2xl bg-card/60 border border-border/40 flex items-center gap-3">
274 <div className="h-9 w-9 rounded-xl bg-emerald-500/10 text-emerald-500 flex items-center justify-center shrink-0">
275 <CheckCircle2 className="h-4 w-4" />
276 </div>
277 <div>
278 <div className="text-[10px] font-bold text-muted-foreground uppercase">Bench Progress</div>
279 <div className="text-xs font-bold text-foreground">{completedSteps.length} of {steps.length} complete</div>
280 </div>
281 </div>
282 </div>
283 </div>
284
285 <div className="p-6 md:p-8 space-y-8">
286 {/* Safety Warnings Checklist */}
287 {guide.safetyWarnings && guide.safetyWarnings.length > 0 && (
288 <div className="p-5 rounded-3xl bg-rose-500/10 border border-rose-500/30 text-rose-950 dark:text-rose-200 space-y-3">
289 <div className="flex items-center gap-2 font-bold text-rose-700 dark:text-rose-400 text-sm">
290 <AlertTriangle className="h-5 w-5" />
291 Critical Safety & ESD Directives (Must Review Before Disassembly)
292 </div>
293 <ul className="space-y-2 pl-2 text-xs sm:text-sm">
294 {guide.safetyWarnings.map((warning, idx) => (
295 <li key={idx} className="flex items-start gap-2.5">
296 <span className="h-2 w-2 rounded-full bg-rose-500 shrink-0 mt-1.5" />
297 <span className="leading-relaxed">{warning}</span>
298 </li>
299 ))}
300 </ul>
301 </div>
302 )}
303
304 {/* Required Tools Grid */}
305 {guide.toolsRequired && guide.toolsRequired.length > 0 && (
306 <div className="space-y-3">
307 <h3 className="text-sm font-bold uppercase tracking-wider text-foreground flex items-center gap-2">
308 <Wrench className="h-4 w-4 text-primary" />
309 Required Bench Equipment & Precision Drivers
310 </h3>
311 <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-2.5">
312 {guide.toolsRequired.map((tool, idx) => (
313 <div key={idx} className="p-3 rounded-2xl bg-muted/40 border border-border/50 text-xs font-medium flex items-center gap-2.5">
314 <div className="h-2 w-2 rounded-full bg-primary shrink-0" />
315 <span className="text-foreground/90">{tool}</span>
316 </div>
317 ))}
318 </div>
319 </div>
320 )}
321
322 {/* Compatible Device Models */}
323 {compatibleModels.length > 0 && (
324 <div className="space-y-3">
325 <h3 className="text-sm font-bold uppercase tracking-wider text-foreground flex items-center gap-2">
326 <Sparkles className="h-4 w-4 text-indigo-500" />
327 Compatible Hardware Series
328 </h3>
329 <div className="flex flex-wrap gap-2">
330 {compatibleModels.map((model) => (
331 <span key={model.id} className="px-3 py-1.5 rounded-2xl bg-card border border-border/60 text-xs font-semibold text-foreground/90">
332 {model.name} {model.year ? `(${model.year})` : ""}
333 </span>
334 ))}
335 </div>
336 </div>
337 )}
338
339 {/* Start-to-Finish Intimate Step-by-Step Procedure */}
340 <div className="space-y-6">
341 <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-2 border-b border-border/40 pb-3">
342 <div>
343 <h3 className="text-lg sm:text-xl font-bold flex items-center gap-2 text-foreground">
344 <FileCheck2 className="h-5 w-5 text-emerald-500" />
345 Start-to-Finish Comprehensive Repair Sequence
346 </h3>
347 <p className="text-xs text-muted-foreground">
348 Follow all technical phases in chronological order. Check off completed items to track bench progress.
349 </p>
350 </div>
351 <span className="text-xs font-semibold text-primary bg-primary/10 px-3 py-1 rounded-full w-fit">
352 {completedSteps.length}/{steps.length} Steps Completed
353 </span>
354 </div>
355
356 <div className="space-y-5">
357 {steps.map((step, sIdx) => {
358 const isCompleted = completedSteps.includes(step.stepNumber);
359
360 return (
361 <div
362 key={step.stepNumber}
363 onClick={() => toggleStep(step.stepNumber)}
364 className={cn(
365 "p-5 sm:p-6 rounded-3xl border transition-all duration-300 cursor-pointer space-y-4",
366 isCompleted
367 ? "bg-emerald-500/5 border-emerald-500/30"
368 : "bg-card/40 hover:bg-card/70 border-border/50 hover:border-primary/40"
369 )}
370 >
371 {/* Step Header with Phase & Tool Specifications */}
372 <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 border-b border-border/30 pb-3">
373 <div className="flex items-center gap-3">
374 <div className={cn(
375 "h-8 w-8 rounded-full flex items-center justify-center text-xs font-bold transition-colors shrink-0",
376 isCompleted ? "bg-emerald-500 text-white" : "bg-primary text-primary-foreground"
377 )}>
378 {isCompleted ? <Check className="h-4 w-4" /> : step.stepNumber}
379 </div>
380
381 <div>
382 {step.phase && (
383 <div className="text-[10px] font-bold uppercase tracking-wider text-primary">
384 {step.phase}
385 </div>
386 )}
387 <h4 className={cn("font-bold text-base sm:text-lg text-foreground", isCompleted && "line-through text-muted-foreground")}>
388 {step.title}
389 </h4>
390 </div>
391 </div>
392
393 <div className="flex flex-wrap items-center gap-2 pl-11 sm:pl-0">
394 {step.torqueSpec && (
395 <span className="text-[11px] font-mono font-bold px-2.5 py-0.5 rounded-full bg-indigo-500/10 text-indigo-600 dark:text-indigo-400 border border-indigo-500/20 flex items-center gap-1">
396 <Gauge className="h-3 w-3" />
397 {step.torqueSpec}
398 </span>
399 )}
400 {step.toolRequired && (
401 <span className="text-[11px] font-semibold px-2.5 py-0.5 rounded-full bg-muted text-muted-foreground border border-border/40 flex items-center gap-1">
402 <Wrench className="h-3 w-3" />
403 {step.toolRequired}
404 </span>
405 )}
406 <span className={cn(
407 "text-[10px] font-bold uppercase tracking-wider px-2.5 py-0.5 rounded-full",
408 isCompleted ? "bg-emerald-500/20 text-emerald-600 dark:text-emerald-400" : "bg-muted text-muted-foreground"
409 )}>
410 {isCompleted ? "Step Completed" : `Step ${step.stepNumber} of ${steps.length}`}
411 </span>
412 </div>
413 </div>
414
415 {/* Primary Detailed Technical Description */}
416 <p className="text-xs sm:text-sm text-foreground/90 leading-relaxed pl-0 sm:pl-11">
417 {step.description}
418 </p>
419
420 {/* Intimate Sub-Steps Checklist */}
421 {step.subSteps && step.subSteps.length > 0 && (
422 <div className="pl-0 sm:pl-11 space-y-2 pt-1">
423 <div className="text-[11px] font-bold uppercase tracking-wider text-muted-foreground flex items-center gap-1.5">
424 <ListOrdered className="h-3.5 w-3.5 text-primary" />
425 Granular Micro-Procedures Checklist
426 </div>
427 <div className="space-y-1.5">
428 {step.subSteps.map((sub, subIdx) => {
429 const isSubChecked = !!checkedSubSteps[`${step.stepNumber}-${subIdx}`];
430 return (
431 <div
432 key={subIdx}
433 onClick={(e) => toggleSubStep(step.stepNumber, subIdx, e)}
434 className={cn(
435 "p-2.5 rounded-xl border text-xs flex items-start gap-2.5 transition-colors cursor-pointer",
436 isSubChecked
437 ? "bg-emerald-500/10 border-emerald-500/30 text-muted-foreground"
438 : "bg-background/60 hover:bg-muted/60 border-border/40 text-foreground/90"
439 )}
440 >
441 <div className={cn(
442 "h-4 w-4 rounded-md border flex items-center justify-center shrink-0 mt-0.5 transition-colors",
443 isSubChecked ? "bg-emerald-500 border-emerald-500 text-white" : "border-border/80 bg-background"
444 )}>
445 {isSubChecked && <Check className="h-3 w-3" />}
446 </div>
447 <span className={cn("leading-relaxed", isSubChecked && "line-through")}>
448 {sub}
449 </span>
450 </div>
451 );
452 })}
453 </div>
454 </div>
455 )}
456
457 {/* Step Image */}
458 {step.imageUrl && (
459 <div className="pl-0 sm:pl-11 pt-2">
460 <img
461 src={step.imageUrl}
462 alt={step.title}
463 className="rounded-2xl border border-border/40 w-full max-h-80 object-cover shadow-2xs"
464 loading="lazy"
465 />
466 </div>
467 )}
468
469 {/* Verification Checkpoints */}
470 {step.checkpoints && step.checkpoints.length > 0 && (
471 <div className="ml-0 sm:ml-11 p-3.5 rounded-2xl bg-emerald-500/10 border border-emerald-500/20 text-xs text-emerald-950 dark:text-emerald-200 space-y-1.5">
472 <div className="font-bold flex items-center gap-1.5 text-emerald-700 dark:text-emerald-400">
473 <CheckCircle2 className="h-4 w-4" />
474 Verification Checkpoints (Confirm Before Proceeding)
475 </div>
476 <ul className="space-y-1 pl-5 list-disc text-emerald-900 dark:text-emerald-200">
477 {step.checkpoints.map((cp, cpIdx) => (
478 <li key={cpIdx}>{cp}</li>
479 ))}
480 </ul>
481 </div>
482 )}
483
484 {/* Warnings / Cautions */}
485 {step.warnings && step.warnings.length > 0 && (
486 <div className="ml-0 sm:ml-11 p-3.5 rounded-2xl bg-rose-500/10 border border-rose-500/20 text-xs text-rose-950 dark:text-rose-200 flex items-start gap-2.5">
487 <AlertTriangle className="h-4 w-4 text-rose-500 shrink-0 mt-0.5" />
488 <div>
489 <strong>Technician Caution:</strong> {step.warnings.join(" ")}
490 </div>
491 </div>
492 )}
493
494 {/* Pro Tips */}
495 {step.tips && step.tips.length > 0 && (
496 <div className="ml-0 sm:ml-11 p-3.5 rounded-2xl bg-indigo-500/10 border border-indigo-500/20 text-xs text-indigo-950 dark:text-indigo-200 flex items-start gap-2.5">
497 <Info className="h-4 w-4 text-indigo-500 shrink-0 mt-0.5" />
498 <div>
499 <strong>Bench Pro Tip:</strong> {step.tips.join(" ")}
500 </div>
501 </div>
502 )}
503
504 {/* Engineering Notes */}
505 {step.notes && step.notes.length > 0 && (
506 <div className="ml-0 sm:ml-11 p-3 rounded-xl bg-muted/40 border border-border/40 text-xs text-muted-foreground">
507 <strong>Specification Note:</strong> {step.notes.join(" ")}
508 </div>
509 )}
510 </div>
511 );
512 })}
513 </div>
514 </div>
515
516 {/* Alternative Solutions & Post-Repair Validation */}
517 {guide.alternativeSolutions && (
518 <div className="p-5 rounded-3xl bg-muted/40 border border-border/50 space-y-2">
519 <h4 className="font-bold text-sm text-foreground flex items-center gap-2">
520 <Sparkles className="h-4 w-4 text-primary" />
521 Post-Repair Quality Assurance & Alternative Methods
522 </h4>
523 <p className="text-xs sm:text-sm text-muted-foreground leading-relaxed">
524 {guide.alternativeSolutions}
525 </p>
526 </div>
527 )}
528 </div>
529
530 {/* Footer Actions */}
531 <div className="p-6 md:p-8 bg-muted/30 border-t border-border/40 flex flex-col sm:flex-row items-center justify-between gap-4">
532 <div className="flex items-center gap-2 text-xs text-emerald-600 dark:text-emerald-400 font-semibold">
533 <CheckCircle2 className="h-4 w-4" />
534 <span>JCR Certified Intimate Engineering Standard</span>
535 </div>
536
537 <div className="flex items-center gap-2 w-full sm:w-auto">
538 {!isPage && (
539 <Button
540 variant="outline"
541 onClick={onClose}
542 className="rounded-2xl text-xs h-10 px-5 flex-1 sm:flex-initial border-border/60"
543 >
544 Close
545 </Button>
546 )}
547 <Button
548 onClick={() => {
549 toast({
550 title: "Guide Exported",
551 description: `Complete technical package for "${guide.title}" is saved for offline bench reference.`,
552 });
553 }}
554 className="rounded-2xl text-xs font-bold h-10 px-6 gap-2 bg-primary hover:bg-primary/90 text-primary-foreground flex-1 sm:flex-initial shadow-xs"
555 >
556 <Bookmark className="h-4 w-4" />
557 <span>Export Offline Guide</span>
558 </Button>
559 </div>
560 </div>
561 </div>
562 );
563
564 if (isPage) {
565 return <div className="bg-card rounded-3xl border border-border/50 shadow-glass overflow-hidden">{content}</div>;
566 }
567
568 return (
569 <Dialog open={true} onOpenChange={() => onClose()}>
570 <DialogContent className="max-w-4xl max-h-[92vh] overflow-y-auto p-0 rounded-3xl border-border/60 bg-card/95 backdrop-blur-2xl shadow-glass">
571 {content}
572 </DialogContent>
573 </Dialog>
574 );
575 }