From 267e4e59f703669d6c6cd98200e53083b8ae481c Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Mon, 9 Mar 2026 00:14:58 -0700 Subject: [PATCH] Add tabs to separate apps and tool repos --- apps/git/index.tsx | 162 +++++++++++++++++++++------------- apps/git/src/client/tabs.ts | 13 +++ apps/git/src/client/toggle.ts | 19 ++++ 3 files changed, 135 insertions(+), 59 deletions(-) create mode 100644 apps/git/src/client/tabs.ts create mode 100644 apps/git/src/client/toggle.ts diff --git a/apps/git/index.tsx b/apps/git/index.tsx index c2015e2..ede6956 100644 --- a/apps/git/index.tsx +++ b/apps/git/index.tsx @@ -15,26 +15,6 @@ const TOES_URL = process.env.TOES_URL! const REPOS_DIR = resolve(DATA_ROOT, 'repos') const VISIBILITY_PATH = join(DATA_DIR, 'visibility.json') -const TOGGLE_SCRIPT = ` -function toggleVisibility(btn) { - var repo = btn.dataset.repo; - var current = btn.dataset.visibility; - var next = current === 'public' ? 'private' : 'public'; - btn.dataset.visibility = next; - btn.textContent = next; - btn.classList.toggle('public', next === 'public'); - fetch('/api/visibility/' + encodeURIComponent(repo), { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ visibility: next }) - }).catch(function() { - btn.dataset.visibility = current; - btn.textContent = current; - btn.classList.toggle('public', current === 'public'); - }); -} -` - const app = new Hype({ prettyHTML: false, layout: false }) const deployLocks = new Map>() @@ -113,6 +93,31 @@ const RepoName = define('RepoName', { color: theme('colors-text'), }) +const Tab = define('Tab', { + base: 'button', + padding: '6px 0', + background: 'none', + border: 'none', + borderBottom: '2px solid transparent', + cursor: 'pointer', + fontSize: '14px', + color: theme('colors-textMuted'), + states: { + ':hover': { color: theme('colors-text') }, + '.active': { + color: theme('colors-text'), + borderBottomColor: theme('colors-primary'), + fontWeight: '500', + }, + }, +}) + +const TabBar = define('TabBar', { + display: 'flex', + gap: '24px', + marginBottom: '20px', +}) + const Toggle = define('Toggle', { base: 'button', display: 'inline-flex', @@ -156,7 +161,7 @@ interface LayoutProps { interface RepoListPageProps { baseUrl: string external: boolean - repos: Array<{ name: string; commits: boolean; branch: string; visibility: Visibility }> + repos: Array<{ name: string; commits: boolean; branch: string; visibility: Visibility; tool: boolean }> tunnelUrl?: string } @@ -544,7 +549,56 @@ function AppRepo({ appName, baseUrl, branch, exists, commits }: AppRepoProps) { ) } +function RepoListItems({ baseUrl, external, repos, tunnelUrl }: { + baseUrl: string + external: boolean + repos: RepoListPageProps['repos'] + tunnelUrl?: string +}) { + if (repos.length === 0) { + return No repositories yet. + } + return ( + + {repos.map(({ name, commits, branch, visibility }) => ( + +
+ {name} + + git clone {baseUrl}/{name} + + {!external && tunnelUrl && visibility === 'public' && ( + + git clone {tunnelUrl}/{name} + + )} +
+
+ {!external && ( + + {visibility === 'public' ? 'public' : 'private'} + + )} + {branch} + {commits + ? deployed + : empty} +
+
+ ))} +
+ ) +} + function RepoListPage({ baseUrl, external, repos, tunnelUrl }: RepoListPageProps) { + const appRepos = repos.filter(r => !r.tool) + const toolRepos = repos.filter(r => r.tool) + return ( {!external && ( @@ -569,40 +623,20 @@ function RepoListPage({ baseUrl, external, repos, tunnelUrl }: RepoListPageProps {repos.length > 0 && ( <> Repositories - - {repos.map(({ name, commits, branch, visibility }) => ( - -
- {name} - - git clone {baseUrl}/{name} - - {!external && tunnelUrl && visibility === 'public' && ( - - git clone {tunnelUrl}/{name} - - )} -
-
- {!external && ( - - {visibility === 'public' ? 'public' : 'private'} - - )} - {branch} - {commits - ? deployed - : empty} -
-
- ))} -
- {!external &&