Highly ambitious ATProtocol AppView service and sdks

add copyable slice uri to slice overview page

Changed files
+30 -2
frontend-v2
src
+25 -1
frontend-v2/src/components/CopyableField.tsx
··· 4 4 interface CopyableFieldProps { 5 5 value: string; 6 6 label: string; 7 + variant?: "input" | "inline"; 7 8 } 8 9 9 - export function CopyableField({ value, label }: CopyableFieldProps) { 10 + export function CopyableField({ value, label, variant = "input" }: CopyableFieldProps) { 10 11 const [copied, setCopied] = useState(false); 11 12 12 13 const handleCopy = async () => { ··· 18 19 console.error("Failed to copy:", err); 19 20 } 20 21 }; 22 + 23 + if (variant === "inline") { 24 + return ( 25 + <div className="flex items-center gap-2 group"> 26 + <span className="text-xs text-zinc-500">{label}:</span> 27 + <span className="font-mono text-xs text-zinc-600 break-all"> 28 + {value} 29 + </span> 30 + <button 31 + type="button" 32 + onClick={handleCopy} 33 + className="p-1 text-zinc-400 hover:text-zinc-300 transition-colors rounded hover:bg-zinc-700/50 flex-shrink-0 opacity-0 group-hover:opacity-100" 34 + title="Copy to clipboard" 35 + > 36 + {copied ? ( 37 + <Check size={14} className="text-green-400" /> 38 + ) : ( 39 + <Copy size={14} /> 40 + )} 41 + </button> 42 + </div> 43 + ); 44 + } 21 45 22 46 return ( 23 47 <div>
+5 -1
frontend-v2/src/pages/SliceOverview.tsx
··· 13 13 import { useSessionContext } from "../lib/useSession.ts"; 14 14 import { isSliceOwner } from "../lib/permissions.ts"; 15 15 import { Plus } from "lucide-react"; 16 + import { CopyableField } from "../components/CopyableField.tsx"; 16 17 17 18 export default function SliceOverview() { 18 19 const { handle, rkey } = useParams<{ handle: string; rkey: string }>(); ··· 101 102 } 102 103 > 103 104 <div className="mb-8"> 104 - <div className="flex items-center gap-3"> 105 + <div className="flex items-center gap-3 mb-4"> 105 106 <Avatar 106 107 src={slice?.networkSlicesActorProfile?.avatar?.url} 107 108 alt={`${handle} avatar`} ··· 116 117 </p> 117 118 </div> 118 119 </div> 120 + {slice?.uri && ( 121 + <CopyableField value={slice.uri} label="Slice URI" variant="inline" /> 122 + )} 119 123 </div> 120 124 121 125 {/* Stats Section */}