File size: 7,473 Bytes
aa886e5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3cdf7b9
aa886e5
 
 
 
3cdf7b9
 
 
aa886e5
 
 
 
 
3cdf7b9
 
aa886e5
 
 
 
 
 
 
 
 
 
 
 
7176fec
aa886e5
 
3cdf7b9
 
aa886e5
 
3cdf7b9
 
aa886e5
 
 
 
 
3cdf7b9
 
 
 
aa886e5
 
 
3cdf7b9
aa886e5
 
 
 
 
 
3cdf7b9
aa886e5
3cdf7b9
 
 
 
 
aa886e5
 
 
 
 
3cdf7b9
aa886e5
 
 
 
3cdf7b9
 
aa886e5
 
 
 
 
 
 
 
 
 
 
 
 
3cdf7b9
 
 
aa886e5
 
 
 
 
 
 
 
 
 
3cdf7b9
 
 
 
aa886e5
 
 
 
 
 
 
3cdf7b9
 
 
 
 
 
 
 
aa886e5
 
3cdf7b9
aa886e5
 
 
 
 
 
 
 
 
3cdf7b9
 
 
 
aa886e5
 
3cdf7b9
aa886e5
3cdf7b9
 
aa886e5
 
3cdf7b9
aa886e5
3cdf7b9
aa886e5
3cdf7b9
 
aa886e5
 
3cdf7b9
aa886e5
3cdf7b9
aa886e5
3cdf7b9
 
aa886e5
 
 
 
 
 
3cdf7b9
 
 
aa886e5
 
3cdf7b9
 
aa886e5
3cdf7b9
 
 
aa886e5
3cdf7b9
 
aa886e5
 
 
 
 
 
 
3cdf7b9
 
 
aa886e5
 
3cdf7b9
 
aa886e5
 
 
 
3cdf7b9
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
<script lang="ts">
	import { Button } from "@/components/ui/button";
	import * as Dialog from "@/components/ui/dialog";
	import * as Card from "@/components/ui/card";
	import { toast } from "svelte-sonner";

	interface Props {
		workspaceId: string;
		open?: boolean;
	}

	let { workspaceId, open = $bindable(false) }: Props = $props();

	// Copy workspace ID to clipboard
	let isCopying = $state(false);

	const copyWorkspaceId = async () => {
		try {
			isCopying = true;
			await navigator.clipboard.writeText(workspaceId);
			toast.success("Workspace ID copied!", {
				description:
					"Share this ID with others to access the same video streams, robot controls, and Inference Sessions in this workspace."
			});
			setTimeout(() => {
				isCopying = false;
			}, 200);
		} catch (err) {
			console.error("Failed to copy workspace ID:", err);
			toast.error("Failed to copy workspace ID");
			isCopying = false;
		}
	};

	// Extract first and last 3 letters from workspace ID
	const getWorkspaceDisplay = (id: string) => {
		if (id.length <= 6) return `#${id}`;
		return `#${id.slice(0, 3)}...${id.slice(-3)}`;
	};

	// Copy full URL to clipboard
	const copyUrl = async () => {
		const url = `https://blanchon-robothub-frontend.hf.space/${workspaceId}`;
		try {
			await navigator.clipboard.writeText(url);
			toast.success("Workspace URL copied!", {
				description: "Share this URL for direct access to this workspace."
			});
		} catch (err) {
			console.error("Failed to copy URL:", err);
			toast.error("Failed to copy URL");
		}
	};
</script>

<!-- Workspace ID Button -->
<div class="flex h-8 items-center overflow-hidden rounded-lg">
	<div
		class="flex h-full items-center overflow-hidden rounded-lg border border-slate-200 bg-slate-100 dark:border-slate-700 dark:bg-slate-800"
	>
		<!-- Workspace ID Display with Copy on Hover -->
		<button
			onclick={copyWorkspaceId}
			class="group relative flex h-full cursor-pointer items-center bg-slate-50 px-3 font-mono text-sm text-slate-700 transition-colors duration-200 hover:bg-slate-100 dark:bg-slate-900 dark:text-slate-300 dark:hover:bg-slate-800"
			title="Click to copy workspace ID"
		>
			<!-- Workspace ID Text -->
			<span class="transition-opacity duration-300 group-hover:opacity-0">
				{getWorkspaceDisplay(workspaceId)}
			</span>

			<!-- Copy Icon (appears on hover) -->
			<span
				class="absolute inset-0 flex items-center justify-center opacity-0 transition-opacity duration-300 group-hover:opacity-100"
			>
				<span
					class="icon-[mdi--content-copy] size-4 text-slate-600 transition-transform duration-200 dark:text-slate-400"
					class:animate-pulse={isCopying}
					class:scale-110={isCopying}
				></span>
			</span>
		</button>

		<!-- Modal Button -->
		<Button
			variant="ghost"
			size="sm"
			onclick={() => (open = true)}
			class="h-full rounded-none border-0 border-l border-slate-200 px-3 text-slate-600 transition-all duration-200 hover:border-slate-300 hover:bg-slate-200 hover:text-slate-900 dark:border-slate-700 dark:text-slate-400 dark:hover:border-slate-600 dark:hover:bg-slate-700 dark:hover:text-slate-100"
			title="Open workspace details"
		>
			<span class="icon-[mdi--information-outline] size-4"></span>
		</Button>
	</div>
</div>

<!-- Workspace Details Modal -->
<Dialog.Root bind:open>
	<Dialog.Content
		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"
	>
		<Dialog.Header class="pb-4">
			<Dialog.Title
				class="flex items-center gap-2 text-lg font-bold text-slate-900 dark:text-slate-100"
			>
				<span class="icon-[mdi--share-variant] size-5 text-blue-500 dark:text-blue-400"></span>
				Workspace Sharing
			</Dialog.Title>
			<Dialog.Description class="text-sm text-slate-600 dark:text-slate-400">
				Connect and collaborate with others using this workspace
			</Dialog.Description>
		</Dialog.Header>

		<div class="space-y-4">
			<!-- Workspace URL -->
			<Card.Root
				class="gap-2 border-blue-300/30 bg-blue-100/10 dark:border-blue-500/30 dark:bg-blue-500/10"
			>
				<Card.Header>
					<Card.Title class="flex items-center gap-2 text-sm text-blue-700 dark:text-blue-200">
						<span class="icon-[mdi--link] size-4"></span>
						Direct Access URL
					</Card.Title>
				</Card.Header>
				<Card.Content class="pt-0">
					<div class="space-y-2">
						<div
							class="rounded-lg border border-slate-300 bg-slate-50 p-2 dark:border-slate-600 dark:bg-slate-800"
						>
							<div class="font-mono text-sm break-all text-slate-800 dark:text-slate-200">
								https://blanchon-robothub-frontend.hf.space<span
									class="rounded bg-blue-100 px-1 text-blue-800 dark:bg-blue-900 dark:text-blue-200"
									>#{workspaceId}</span
								>
							</div>
						</div>
						<Button variant="outline" size="sm" onclick={copyUrl} class="w-full text-xs">
							<span class="icon-[mdi--content-copy] mr-2 size-3"></span>
							Copy URL
						</Button>
					</div>
				</Card.Content>
			</Card.Root>

			<!-- Key Features -->
			<div class="space-y-3">
				<h3 class="text-sm font-semibold text-slate-700 dark:text-slate-300">
					What you can share:
				</h3>

				<div class="space-y-2 text-sm">
					<div class="flex items-start gap-2">
						<span class="icon-[mdi--video] mt-0.5 size-4 flex-shrink-0 text-green-500"></span>
						<span class="text-slate-600 dark:text-slate-400">
							<strong class="text-slate-800 dark:text-slate-200">Video Streams</strong> - Live camera
							feeds from connected devices
						</span>
					</div>

					<div class="flex items-start gap-2">
						<span class="icon-[mdi--robot] mt-0.5 size-4 flex-shrink-0 text-orange-500"></span>
						<span class="text-slate-600 dark:text-slate-400">
							<strong class="text-slate-800 dark:text-slate-200">Robot Control</strong> - Real-time teleoperation
							and monitoring
						</span>
					</div>

					<div class="flex items-start gap-2">
						<span class="icon-[mdi--brain] mt-0.5 size-4 flex-shrink-0 text-purple-500"></span>
						<span class="text-slate-600 dark:text-slate-400">
							<strong class="text-slate-800 dark:text-slate-200">AI Sessions</strong> - Shared inference
							and autonomous control
						</span>
					</div>
				</div>
			</div>

			<!-- Privacy & Security -->
			<Card.Root
				class="border-amber-300/30 bg-amber-100/10 dark:border-amber-500/30 dark:bg-amber-500/10"
			>
				<Card.Content>
					<div class="flex items-start gap-2">
						<span class="icon-[mdi--shield-check] mt-0.5 size-4 flex-shrink-0 text-amber-600"
						></span>
						<div class="text-sm">
							<div class="mb-1 font-medium text-amber-700 dark:text-amber-300">
								Private Workspace
							</div>
							<div class="text-amber-600 dark:text-amber-400">
								Only users with this workspace ID can access your resources. Share it securely with
								trusted collaborators.
							</div>
						</div>
					</div>
				</Card.Content>
			</Card.Root>

			<!-- Use Cases -->
			<div
				class="rounded-lg border border-slate-300 bg-slate-50 p-3 dark:border-slate-600 dark:bg-slate-800"
			>
				<div class="text-xs text-slate-600 dark:text-slate-400">
					<span class="icon-[mdi--lightbulb] mr-1 size-3"></span>
					<strong>Tip:</strong> Use this for remote teleoperation, collaborative research, demonstrations,
					or sharing your robot setup with team members across different networks.
				</div>
			</div>
		</div>
	</Dialog.Content>
</Dialog.Root>