add runner tab

Seto Elkahfi committed Jun 11, 2025 at 16:12 UTC d1e6ec4975b8bf2d388af037371f853658ce4779
2 files changed +89 -28
app/components/TabbedRunner.tsx new
+87
@@ -0,0 +1,87 @@
1 +"use client"
2 +
3 +import { JSX, useState } from "react";
4 +
5 +const runnerSnippets = {
6 + NodeJS: `$ smb
7 +✔ Valid config
8 +✔ NodeJs 🟩 runner detected
9 +✔ Valid project
10 +✔ Valid deployment setup
11 +☱ Deploying > Use key path: ~/.ssh/id_11@smbcloud
12 +☱ Deploying > Building the app ✔
13 +☲ Deploying > App restart ✔
14 +☱ Deploying > App is running ✔
15 +✔ Deployment complete.`,
16 + Ruby: `$ smb
17 +✔ Valid config
18 +✔ Ruby 🟥 runner detected (coming soon)
19 +✔ Valid project
20 +✔ Valid deployment setup
21 +☱ Deploying > Use key path: ~/.ssh/id_11@smbcloud
22 +☱ Deploying > Building the app ✔
23 +☲ Deploying > App restart ✔
24 +☱ Deploying > App is running ✔
25 +✔ Deployment complete.`,
26 + Swift: `$ smb
27 +✔ Valid config
28 +✔ Swift 🟧 runner detected (coming soon)
29 +✔ Valid project
30 +✔ Valid deployment setup
31 +☱ Deploying > Use key path: ~/.ssh/id_11@smbcloud
32 +☱ Deploying > Building the app ✔
33 +☲ Deploying > App restart ✔
34 +☱ Deploying > App is running ✔
35 +✔ Deployment complete.`
36 +};
37 +
38 +export default function TabbedRunner() {
39 + const [tab, setTab] = useState<keyof typeof runnerSnippets>('NodeJS');
40 + const tabs: { key: keyof typeof runnerSnippets; label: string }[] = [
41 + { key: 'NodeJS', label: 'NodeJS' },
42 + { key: 'Ruby', label: 'Ruby (coming soon)' },
43 + { key: 'Swift', label: 'Swift (coming soon)' }
44 + ];
45 + return (
46 + <div>
47 + <div style={{ display: 'flex', gap: 8, marginBottom: 8 }}>
48 + {tabs.map(t => (
49 + <button
50 + key={t.key}
51 + onClick={() => setTab(t.key)}
52 + style={{
53 + border: 'none',
54 + background: tab === t.key ? '#222' : '#eee',
55 + color: tab === t.key ? '#fff' : '#222',
56 + padding: '4px 12px',
57 + borderRadius: 4,
58 + cursor: 'pointer',
59 + fontWeight: tab === t.key ? 'bold' : 'normal'
60 + }}
61 + >
62 + {t.label}
63 + </button>
64 + ))}
65 + </div>
66 + <pre>
67 + {
68 + runnerSnippets[tab]
69 + .split('\n')
70 + .map((line, idx) => (
71 + <span key={idx}>
72 + {line.split('✔').reduce((acc, part, i, arr) => {
73 + if (i === arr.length - 1) return [...acc, part];
74 + return [
75 + ...acc,
76 + part,
77 + <span key={`check-${i}`} style={{ color: 'green' }}>✔</span>
78 + ];
79 + }, [] as (string | JSX.Element)[])}
80 + {'\n'}
81 + </span>
82 + ))
83 + }
84 + </pre>
85 + </div>
86 + );
87 +}
app/page.tsx
+2 -28
@@ -2,7 +2,7 @@ import { allPosts } from "@/.contentlayer/generated";
2 import Link from "next/link";
3 import { genPageMetadata } from "./seo";
4 import siteMetadata from '@/content/siteMetadata'
5 -import { JSX } from "react";
5 +import TabbedRunner from "./components/TabbedRunner";
6
7 export const metadata = genPageMetadata({ title: `${siteMetadata.title}` })
8
@@ -13,33 +13,7 @@ export default function Home() {
13 <div className="prose dark:prose-invert">
14 <h1>smbCloud</h1>
15 <p className="text-lg">Deploy your NextJS app with one command: </p>
16 - <pre>
17 - {
18 - `$ smb
19 -✔ Valid config
20 -✔ Valid project
21 -✔ Valid deployment setup
22 -☱ Deploying > Use key path: ~/.ssh/id_11@smbcloud
23 -☱ Deploying > Building the app ✔
24 -☲ Deploying > App restart ✔
25 -☱ Deploying > App is running ✔
26 -✔ Deployment complete.`
27 - .split('\n')
28 - .map((line, idx) => (
29 - <span key={idx}>
30 - {line.split('✔').reduce((acc, part, i, arr) => {
31 - if (i === arr.length - 1) return [...acc, part];
32 - return [
33 - ...acc,
34 - part,
35 - <span key={`check-${i}`} style={{ color: 'green' }}>✔</span>
36 - ];
37 - }, [] as (string | JSX.Element)[])}
38 - {'\n'}
39 - </span>
40 - ))
41 - }
42 - </pre>
16 + <TabbedRunner />
17 <hr />
18 <h2>Resources</h2>
19 {publishedPosts.map((post) => (