File size: 3,505 Bytes
fc9bd9f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import React, { useState } from "react";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Terminal, ExternalLink, Copy, Check } from "lucide-react";

const ONE_LINER =
  "uv tool install git+https://github.com/huggingface/leLab.git && lelab";
const LOCAL_URL = "http://localhost:8000/";

interface UsageInstructionsModalProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  dismissible?: boolean;
}

const UsageInstructionsModal: React.FC<UsageInstructionsModalProps> = ({
  open,
  onOpenChange,
  dismissible = true,
}) => {
  const [copied, setCopied] = useState(false);

  const blockClose = (e: Event) => {
    if (!dismissible) e.preventDefault();
  };

  const handleCopy = async () => {
    try {
      await navigator.clipboard.writeText(ONE_LINER);
      setCopied(true);
      setTimeout(() => setCopied(false), 1500);
    } catch (err) {
      console.warn("Clipboard write failed:", err);
    }
  };

  return (
    <Dialog
      open={open}
      onOpenChange={dismissible ? onOpenChange : () => undefined}
    >
      <DialogContent
        className="bg-gray-900 border-gray-700 text-gray-300 sm:max-w-xl"
        hideClose={!dismissible}
        onEscapeKeyDown={blockClose}
        onPointerDownOutside={blockClose}
        onInteractOutside={blockClose}
      >
        <DialogHeader className="text-center sm:text-center min-w-0">
          <DialogTitle className="text-white flex items-center justify-center gap-2 text-xl">
            <Terminal className="w-6 h-6" />
            Get Started with LeLab
          </DialogTitle>
          <DialogDescription>
            LeLab runs on your machine. Click the command to copy it, then paste
            in a terminal:
          </DialogDescription>
        </DialogHeader>
        <div className="space-y-4 py-2 min-w-0">
          <button
            type="button"
            onClick={handleCopy}
            aria-label="Copy command to clipboard"
            className="group relative w-full bg-gray-800 hover:bg-gray-750 rounded-lg border border-gray-700 hover:border-gray-600 text-left transition-colors cursor-pointer"
          >
            <pre className="p-4 pr-12 text-xs sm:text-sm overflow-x-auto whitespace-pre-wrap break-all">
              <code className="text-green-400">{ONE_LINER}</code>
            </pre>
            <span className="absolute right-2 top-2 flex items-center gap-1 px-2 py-1 rounded text-xs text-gray-400 group-hover:text-white bg-gray-900/80">
              {copied ? (
                <>
                  <Check className="w-3.5 h-3.5 text-green-400" />
                  Copied
                </>
              ) : (
                <>
                  <Copy className="w-3.5 h-3.5" />
                  Copy
                </>
              )}
            </span>
          </button>
          <p className="text-gray-400 text-sm text-center">
            After running, your browser will open the local LeLab app.
          </p>
          <Button
            asChild
            className="w-full bg-blue-600 hover:bg-blue-700 text-white"
          >
            <a href={LOCAL_URL} target="_blank" rel="noopener noreferrer">
              <ExternalLink className="w-4 h-4 mr-2" />
              Open LeLab
            </a>
          </Button>
        </div>
      </DialogContent>
    </Dialog>
  );
};

export default UsageInstructionsModal;