(READ ONLY) Margin is an open annotation layer for the internet. Powered by the AT Protocol. margin.at
extension web atproto comments
98
fork

Configure Feed

Select the types of activity you want to include in your feed.

at frontend-rewrite 116 lines 3.9 kB view raw
1import React, { useState } from "react"; 2import { Button } from "../ui"; 3import { ExternalLink, Shield } from "lucide-react"; 4import { addSkippedHostname } from "../../store/preferences"; 5 6interface ExternalLinkModalProps { 7 isOpen: boolean; 8 onClose: () => void; 9 url: string | null; 10} 11 12export default function ExternalLinkModal({ 13 isOpen, 14 onClose, 15 url, 16}: ExternalLinkModalProps) { 17 const [dontAskAgain, setDontAskAgain] = useState(false); 18 19 if (!isOpen || !url) return null; 20 21 const displayUrl = url.split("#:~:text=")[0]; 22 23 const handleContinue = () => { 24 if (dontAskAgain && url) { 25 try { 26 const hostname = new URL(url).hostname; 27 addSkippedHostname(hostname); 28 } catch (e) { 29 console.error("Invalid URL", e); 30 } 31 } 32 window.open(url, "_blank", "noopener,noreferrer"); 33 onClose(); 34 }; 35 36 const hostname = (() => { 37 try { 38 return new URL(url).hostname; 39 } catch { 40 return "this site"; 41 } 42 })(); 43 44 return ( 45 <div 46 className="fixed inset-0 z-[100] flex items-center justify-center p-4 bg-black/40 backdrop-blur-sm animate-fade-in" 47 onClick={onClose} 48 > 49 <div 50 className="bg-white dark:bg-surface-900 rounded-xl shadow-2xl max-w-md w-full animate-scale-in ring-1 ring-surface-200 dark:ring-surface-700 overflow-hidden" 51 onClick={(e) => e.stopPropagation()} 52 > 53 <div className="px-6 pt-6 pb-4"> 54 <div className="flex items-start gap-3"> 55 <div className="w-9 h-9 bg-primary-100 dark:bg-primary-900/30 text-primary-600 dark:text-primary-400 rounded-lg flex items-center justify-center flex-shrink-0 mt-0.5"> 56 <Shield size={18} /> 57 </div> 58 <div className="min-w-0"> 59 <h2 className="text-base font-semibold text-surface-900 dark:text-white"> 60 Leaving Margin 61 </h2> 62 <p className="text-sm text-surface-500 dark:text-surface-400 mt-1"> 63 You're about to visit an external site. 64 </p> 65 </div> 66 </div> 67 68 <div className="mt-4 flex items-center gap-2 bg-surface-50 dark:bg-surface-800/60 border border-surface-200 dark:border-surface-700 rounded-lg px-3 py-2.5"> 69 <ExternalLink 70 size={14} 71 className="text-surface-400 dark:text-surface-500 flex-shrink-0" 72 /> 73 <span className="text-sm text-surface-700 dark:text-surface-300 break-all line-clamp-2"> 74 {displayUrl} 75 </span> 76 </div> 77 </div> 78 79 <div className="px-6 pb-5 pt-2 flex flex-col gap-3"> 80 <label className="flex items-center gap-2 cursor-pointer select-none group"> 81 <input 82 type="checkbox" 83 checked={dontAskAgain} 84 onChange={(e) => setDontAskAgain(e.target.checked)} 85 className="rounded border-surface-300 dark:border-surface-600 text-primary-600 focus:ring-primary-500 w-3.5 h-3.5 cursor-pointer" 86 /> 87 <span className="text-xs text-surface-500 dark:text-surface-400 group-hover:text-surface-600 dark:group-hover:text-surface-300 transition-colors"> 88 Always allow links to{" "} 89 <span className="font-medium text-surface-700 dark:text-surface-200"> 90 {hostname} 91 </span> 92 </span> 93 </label> 94 95 <div className="flex gap-2"> 96 <Button 97 onClick={onClose} 98 variant="ghost" 99 className="flex-1 justify-center" 100 > 101 Cancel 102 </Button> 103 <Button 104 onClick={handleContinue} 105 variant="primary" 106 className="flex-1 justify-center" 107 icon={<ExternalLink size={14} />} 108 > 109 Open Link 110 </Button> 111 </div> 112 </div> 113 </div> 114 </div> 115 ); 116}