main
tsx 107 lines 4.13 KB
Raw
1 "use client";
2
3 import { useState } from "react";
4
5 type Runtime = "NodeJS" | "Swift" | "Ruby";
6
7 interface TerminalLine {
8 text: string;
9 type: "command" | "success" | "progress" | "muted";
10 }
11
12 const runnerSnippets: Record<Runtime, TerminalLine[]> = {
13 NodeJS: [
14 { text: "$ smb", type: "command" },
15 { text: "✔ Valid config", type: "success" },
16 { text: "✔ NodeJS 🟩 runner detected", type: "success" },
17 { text: "✔ Valid project", type: "success" },
18 { text: "✔ Valid deployment setup", type: "success" },
19 { text: "☱ Deploying › Use key path: ~/.ssh/id_11@smbcloud", type: "progress" },
20 { text: "☱ Deploying › Building the app ✔", type: "progress" },
21 { text: "☲ Deploying › App restart ✔", type: "progress" },
22 { text: "☱ Deploying › App is running ✔", type: "progress" },
23 { text: "✔ Deployment complete.", type: "success" },
24 ],
25 Swift: [
26 { text: "$ smb", type: "command" },
27 { text: "✔ Valid config", type: "success" },
28 { text: "✔ Swift 🟧 runner detected", type: "success" },
29 { text: "✔ Valid project", type: "success" },
30 { text: "✔ Valid deployment setup", type: "success" },
31 { text: "☱ Deploying › Use key path: ~/.ssh/id_11@smbcloud", type: "progress" },
32 { text: "☱ Deploying › Building the app ✔", type: "progress" },
33 { text: "☲ Deploying › App restart ✔", type: "progress" },
34 { text: "☱ Deploying › App is running ✔", type: "progress" },
35 { text: "✔ Deployment complete.", type: "success" },
36 ],
37 Ruby: [
38 { text: "$ smb", type: "command" },
39 { text: "✔ Valid config", type: "success" },
40 { text: "✔ Ruby 🟥 runner detected", type: "success" },
41 { text: "✔ Valid project", type: "success" },
42 { text: "✔ Valid deployment setup", type: "success" },
43 { text: "☱ Deploying › Use key path: ~/.ssh/id_11@smbcloud", type: "progress" },
44 { text: "☱ Deploying › Building the app ✔", type: "progress" },
45 { text: "☲ Deploying › App restart ✔", type: "progress" },
46 { text: "☱ Deploying › App is running ✔", type: "progress" },
47 { text: "✔ Deployment complete.", type: "success" },
48 ],
49 };
50
51 const lineClass: Record<TerminalLine["type"], string> = {
52 command: "text-slate-200",
53 success: "text-emerald-400",
54 progress: "text-sky-400",
55 muted: "text-slate-500",
56 };
57
58 export default function TabbedRunner() {
59 const [tab, setTab] = useState<Runtime>("NodeJS");
60 const tabs: Runtime[] = ["NodeJS", "Swift", "Ruby"];
61 const lines = runnerSnippets[tab];
62
63 return (
64 <div className="overflow-hidden rounded-xl border border-slate-200 dark:border-white/[0.08] bg-white dark:bg-[#0D1117] shadow-xl shadow-slate-900/5 dark:shadow-none">
65 {/* Window chrome */}
66 <div className="flex items-center justify-between border-b border-slate-200 dark:border-white/[0.06] bg-slate-50 dark:bg-[#161B22] px-4 py-3">
67 {/* Traffic lights */}
68 <div className="flex items-center gap-1.5">
69 <div className="h-3 w-3 rounded-full bg-[#FF5F57]" />
70 <div className="h-3 w-3 rounded-full bg-[#FEBC2E]" />
71 <div className="h-3 w-3 rounded-full bg-[#28C840]" />
72 </div>
73
74 {/* Runtime tabs */}
75 <div className="flex gap-1">
76 {tabs.map((t) => (
77 <button
78 key={t}
79 onClick={() => setTab(t)}
80 className={`rounded px-3 py-1 text-xs font-medium transition-all ${
81 tab === t
82 ? "bg-white dark:bg-slate-700 text-slate-900 dark:text-slate-100 shadow-sm"
83 : "text-slate-400 dark:text-slate-500 hover:text-slate-600 dark:hover:text-slate-400"
84 }`}
85 >
86 {t}
87 </button>
88 ))}
89 </div>
90
91 {/* Spacer to balance traffic lights */}
92 <div className="w-16" />
93 </div>
94
95 {/* Terminal body */}
96 <div className="p-5 font-mono text-sm leading-relaxed">
97 <div className="space-y-0.5">
98 {lines.map((line, idx) => (
99 <div key={idx} className={lineClass[line.type]}>
100 {line.text}
101 </div>
102 ))}
103 </div>
104 </div>
105 </div>
106 );
107 }