blanchon commited on
Commit
aa886e5
·
1 Parent(s): 8173aa6
Dockerfile CHANGED
@@ -72,7 +72,7 @@ EXPOSE ${PORT}
72
 
73
  # Health check
74
  HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
75
- CMD curl -f http://localhost:3000/ || exit 1
76
 
77
  # Start custom static file server
78
  CMD ["bun", "static-server.js"]
 
72
 
73
  # Health check
74
  HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
75
+ CMD curl -f http://localhost:8000/ || exit 1
76
 
77
  # Start custom static file server
78
  CMD ["bun", "static-server.js"]
README.md CHANGED
@@ -4,7 +4,7 @@ emoji: 🤖
4
  colorFrom: blue
5
  colorTo: purple
6
  sdk: docker
7
- app_port: 3000
8
  pinned: true
9
  fullWidth: true
10
  license: mit
 
4
  colorFrom: blue
5
  colorTo: purple
6
  sdk: docker
7
+ app_port: 8000
8
  pinned: true
9
  fullWidth: true
10
  license: mit
src/lib/components/interface/overlay/WorkspaceIdButton.svelte ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { Button } from "@/components/ui/button";
3
+ import * as Dialog from "@/components/ui/dialog";
4
+ import * as Card from "@/components/ui/card";
5
+ import { Badge } from "@/components/ui/badge";
6
+ import { toast } from "svelte-sonner";
7
+
8
+ interface Props {
9
+ workspaceId: string;
10
+ open?: boolean;
11
+ }
12
+
13
+ let { workspaceId, open = $bindable(false) }: Props = $props();
14
+
15
+ // Copy workspace ID to clipboard
16
+ let isCopying = $state(false);
17
+
18
+ const copyWorkspaceId = async () => {
19
+ try {
20
+ isCopying = true;
21
+ await navigator.clipboard.writeText(workspaceId);
22
+ toast.success('Workspace ID copied!', {
23
+ description: 'Share this ID with others to access the same video streams, robot controls, and Inference Sessions in this workspace.'
24
+ });
25
+ setTimeout(() => {
26
+ isCopying = false;
27
+ }, 200);
28
+ } catch (err) {
29
+ console.error('Failed to copy workspace ID:', err);
30
+ toast.error('Failed to copy workspace ID');
31
+ isCopying = false;
32
+ }
33
+ };
34
+
35
+ // Extract first and last 3 letters from workspace ID
36
+ const getWorkspaceDisplay = (id: string) => {
37
+ if (id.length <= 6) return `#${id}`;
38
+ return `#${id.slice(0, 3)}...${id.slice(-3)}`;
39
+ };
40
+
41
+ // Copy full URL to clipboard
42
+ const copyUrl = async () => {
43
+ const url = `http://blanchon-lerobot-arena.hf.space/${workspaceId}`;
44
+ try {
45
+ await navigator.clipboard.writeText(url);
46
+ toast.success('Workspace URL copied!', {
47
+ description: 'Share this URL for direct access to this workspace.'
48
+ });
49
+ } catch (err) {
50
+ console.error('Failed to copy URL:', err);
51
+ toast.error('Failed to copy URL');
52
+ }
53
+ };
54
+ </script>
55
+
56
+ <!-- Workspace ID Button -->
57
+ <div class="flex items-center overflow-hidden rounded-lg h-8">
58
+ <div class="flex items-center h-full bg-slate-100 dark:bg-slate-800 rounded-lg overflow-hidden border border-slate-200 dark:border-slate-700">
59
+ <!-- Workspace ID Display with Copy on Hover -->
60
+ <button
61
+ onclick={copyWorkspaceId}
62
+ class="group relative flex items-center px-3 h-full text-sm font-mono text-slate-700 dark:text-slate-300 bg-slate-50 dark:bg-slate-900 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors duration-200 cursor-pointer"
63
+ title="Click to copy workspace ID"
64
+ >
65
+ <!-- Workspace ID Text -->
66
+ <span class="transition-opacity duration-300 group-hover:opacity-0">
67
+ {getWorkspaceDisplay(workspaceId)}
68
+ </span>
69
+
70
+ <!-- Copy Icon (appears on hover) -->
71
+ <span class="absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-300">
72
+ <span
73
+ class="icon-[mdi--content-copy] size-4 text-slate-600 dark:text-slate-400 transition-transform duration-200"
74
+ class:animate-pulse={isCopying}
75
+ class:scale-110={isCopying}
76
+ ></span>
77
+ </span>
78
+ </button>
79
+
80
+ <!-- Modal Button -->
81
+ <Button
82
+ variant="ghost"
83
+ size="sm"
84
+ onclick={() => open = true}
85
+ class="rounded-none border-0 border-l border-slate-200 dark:border-slate-700 px-3 h-full text-slate-600 dark:text-slate-400 hover:bg-slate-200 dark:hover:bg-slate-700 hover:text-slate-900 dark:hover:text-slate-100 hover:border-slate-300 dark:hover:border-slate-600 transition-all duration-200"
86
+ title="Open workspace details"
87
+ >
88
+ <span class="icon-[mdi--information-outline] size-4"></span>
89
+ </Button>
90
+ </div>
91
+ </div>
92
+
93
+ <!-- Workspace Details Modal -->
94
+ <Dialog.Root bind:open>
95
+ <Dialog.Content
96
+ class="max-w-lg border-slate-300 bg-slate-100 text-slate-900 dark:border-slate-600 dark:bg-slate-900 dark:text-slate-100"
97
+ >
98
+ <Dialog.Header class="pb-4">
99
+ <Dialog.Title class="flex items-center gap-2 text-lg font-bold text-slate-900 dark:text-slate-100">
100
+ <span class="icon-[mdi--share-variant] size-5 text-blue-500 dark:text-blue-400"></span>
101
+ Workspace Sharing
102
+ </Dialog.Title>
103
+ <Dialog.Description class="text-sm text-slate-600 dark:text-slate-400">
104
+ Connect and collaborate with others using this workspace
105
+ </Dialog.Description>
106
+ </Dialog.Header>
107
+
108
+ <div class="space-y-4">
109
+ <!-- Workspace URL -->
110
+ <Card.Root class="gap-2 border-blue-300/30 bg-blue-100/10 dark:border-blue-500/30 dark:bg-blue-500/10">
111
+ <Card.Header >
112
+ <Card.Title class="flex items-center gap-2 text-sm text-blue-700 dark:text-blue-200">
113
+ <span class="icon-[mdi--link] size-4"></span>
114
+ Direct Access URL
115
+ </Card.Title>
116
+ </Card.Header>
117
+ <Card.Content class="pt-0">
118
+ <div class="space-y-2">
119
+ <div class="rounded-lg border border-slate-300 bg-slate-50 p-2 dark:border-slate-600 dark:bg-slate-800">
120
+ <div class="break-all font-mono text-sm text-slate-800 dark:text-slate-200">
121
+ http://blanchon-lerobot-arena.hf.space/<span class="bg-blue-100 text-blue-800 px-1 rounded dark:bg-blue-900 dark:text-blue-200">{workspaceId}</span>
122
+ </div>
123
+ </div>
124
+ <Button
125
+ variant="outline"
126
+ size="sm"
127
+ onclick={copyUrl}
128
+ class="w-full text-xs"
129
+ >
130
+ <span class="icon-[mdi--content-copy] mr-2 size-3"></span>
131
+ Copy URL
132
+ </Button>
133
+ </div>
134
+ </Card.Content>
135
+ </Card.Root>
136
+
137
+ <!-- Key Features -->
138
+ <div class="space-y-3">
139
+ <h3 class="text-sm font-semibold text-slate-700 dark:text-slate-300">What you can share:</h3>
140
+
141
+ <div class="space-y-2 text-sm">
142
+ <div class="flex items-start gap-2">
143
+ <span class="icon-[mdi--video] size-4 text-green-500 mt-0.5 flex-shrink-0"></span>
144
+ <span class="text-slate-600 dark:text-slate-400">
145
+ <strong class="text-slate-800 dark:text-slate-200">Video Streams</strong> - Live camera feeds from connected devices
146
+ </span>
147
+ </div>
148
+
149
+ <div class="flex items-start gap-2">
150
+ <span class="icon-[mdi--robot] size-4 text-orange-500 mt-0.5 flex-shrink-0"></span>
151
+ <span class="text-slate-600 dark:text-slate-400">
152
+ <strong class="text-slate-800 dark:text-slate-200">Robot Control</strong> - Real-time teleoperation and monitoring
153
+ </span>
154
+ </div>
155
+
156
+ <div class="flex items-start gap-2">
157
+ <span class="icon-[mdi--brain] size-4 text-purple-500 mt-0.5 flex-shrink-0"></span>
158
+ <span class="text-slate-600 dark:text-slate-400">
159
+ <strong class="text-slate-800 dark:text-slate-200">AI Sessions</strong> - Shared inference and autonomous control
160
+ </span>
161
+ </div>
162
+ </div>
163
+ </div>
164
+
165
+ <!-- Privacy & Security -->
166
+ <Card.Root class="border-amber-300/30 bg-amber-100/10 dark:border-amber-500/30 dark:bg-amber-500/10">
167
+ <Card.Content>
168
+ <div class="flex items-start gap-2">
169
+ <span class="icon-[mdi--shield-check] size-4 text-amber-600 mt-0.5 flex-shrink-0"></span>
170
+ <div class="text-sm">
171
+ <div class="font-medium text-amber-700 dark:text-amber-300 mb-1">Private Workspace</div>
172
+ <div class="text-amber-600 dark:text-amber-400">
173
+ Only users with this workspace ID can access your resources. Share it securely with trusted collaborators.
174
+ </div>
175
+ </div>
176
+ </div>
177
+ </Card.Content>
178
+ </Card.Root>
179
+
180
+ <!-- Use Cases -->
181
+ <div class="rounded-lg border border-slate-300 bg-slate-50 p-3 dark:border-slate-600 dark:bg-slate-800">
182
+ <div class="text-xs text-slate-600 dark:text-slate-400">
183
+ <span class="icon-[mdi--lightbulb] mr-1 size-3"></span>
184
+ <strong>Tip:</strong> Use this for remote teleoperation, collaborative research, demonstrations, or sharing your robot setup with team members across different networks.
185
+ </div>
186
+ </div>
187
+ </div>
188
+ </Dialog.Content>
189
+ </Dialog.Root>