gitspace 0.2.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +21 -0
- package/.gitspace/bundle.json +50 -0
- package/.gitspace/select/01-status.sh +40 -0
- package/.gitspace/setup/01-install-deps.sh +12 -0
- package/.gitspace/setup/02-typecheck.sh +16 -0
- package/AGENTS.md +439 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +25 -0
- package/README.md +607 -0
- package/bin/gssh +62 -0
- package/bun.lock +647 -0
- package/docs/CONNECTION.md +623 -0
- package/docs/GATEWAY-WORKER.md +319 -0
- package/docs/GETTING-STARTED.md +448 -0
- package/docs/GITSPACE-PLATFORM.md +1819 -0
- package/docs/INFRASTRUCTURE.md +1347 -0
- package/docs/PROTOCOL.md +619 -0
- package/docs/QUICKSTART.md +174 -0
- package/docs/RELAY.md +327 -0
- package/docs/REMOTE-DESIGN.md +549 -0
- package/docs/ROADMAP.md +564 -0
- package/docs/SITE_DOCS_FIGMA_MAKE.md +1167 -0
- package/docs/STACK-DESIGN.md +588 -0
- package/docs/UNIFIED_ARCHITECTURE.md +292 -0
- package/experiments/pty-benchmark.ts +148 -0
- package/experiments/pty-latency.ts +100 -0
- package/experiments/router/client.ts +199 -0
- package/experiments/router/protocol.ts +74 -0
- package/experiments/router/router.ts +217 -0
- package/experiments/router/session.ts +180 -0
- package/experiments/router/test.ts +133 -0
- package/experiments/socket-bandwidth.ts +77 -0
- package/homebrew/gitspace.rb +45 -0
- package/landing-page/ATTRIBUTIONS.md +3 -0
- package/landing-page/README.md +11 -0
- package/landing-page/bun.lock +801 -0
- package/landing-page/guidelines/Guidelines.md +61 -0
- package/landing-page/index.html +37 -0
- package/landing-page/package.json +90 -0
- package/landing-page/postcss.config.mjs +15 -0
- package/landing-page/public/_redirects +1 -0
- package/landing-page/public/favicon.png +0 -0
- package/landing-page/src/app/App.tsx +53 -0
- package/landing-page/src/app/components/figma/ImageWithFallback.tsx +27 -0
- package/landing-page/src/app/components/ui/accordion.tsx +66 -0
- package/landing-page/src/app/components/ui/alert-dialog.tsx +157 -0
- package/landing-page/src/app/components/ui/alert.tsx +66 -0
- package/landing-page/src/app/components/ui/aspect-ratio.tsx +11 -0
- package/landing-page/src/app/components/ui/avatar.tsx +53 -0
- package/landing-page/src/app/components/ui/badge.tsx +46 -0
- package/landing-page/src/app/components/ui/breadcrumb.tsx +109 -0
- package/landing-page/src/app/components/ui/button.tsx +57 -0
- package/landing-page/src/app/components/ui/calendar.tsx +75 -0
- package/landing-page/src/app/components/ui/card.tsx +92 -0
- package/landing-page/src/app/components/ui/carousel.tsx +241 -0
- package/landing-page/src/app/components/ui/chart.tsx +353 -0
- package/landing-page/src/app/components/ui/checkbox.tsx +32 -0
- package/landing-page/src/app/components/ui/collapsible.tsx +33 -0
- package/landing-page/src/app/components/ui/command.tsx +177 -0
- package/landing-page/src/app/components/ui/context-menu.tsx +252 -0
- package/landing-page/src/app/components/ui/dialog.tsx +135 -0
- package/landing-page/src/app/components/ui/drawer.tsx +132 -0
- package/landing-page/src/app/components/ui/dropdown-menu.tsx +257 -0
- package/landing-page/src/app/components/ui/form.tsx +168 -0
- package/landing-page/src/app/components/ui/hover-card.tsx +44 -0
- package/landing-page/src/app/components/ui/input-otp.tsx +77 -0
- package/landing-page/src/app/components/ui/input.tsx +21 -0
- package/landing-page/src/app/components/ui/label.tsx +24 -0
- package/landing-page/src/app/components/ui/menubar.tsx +276 -0
- package/landing-page/src/app/components/ui/navigation-menu.tsx +168 -0
- package/landing-page/src/app/components/ui/pagination.tsx +127 -0
- package/landing-page/src/app/components/ui/popover.tsx +48 -0
- package/landing-page/src/app/components/ui/progress.tsx +31 -0
- package/landing-page/src/app/components/ui/radio-group.tsx +45 -0
- package/landing-page/src/app/components/ui/resizable.tsx +56 -0
- package/landing-page/src/app/components/ui/scroll-area.tsx +58 -0
- package/landing-page/src/app/components/ui/select.tsx +189 -0
- package/landing-page/src/app/components/ui/separator.tsx +28 -0
- package/landing-page/src/app/components/ui/sheet.tsx +139 -0
- package/landing-page/src/app/components/ui/sidebar.tsx +726 -0
- package/landing-page/src/app/components/ui/skeleton.tsx +13 -0
- package/landing-page/src/app/components/ui/slider.tsx +63 -0
- package/landing-page/src/app/components/ui/sonner.tsx +25 -0
- package/landing-page/src/app/components/ui/switch.tsx +31 -0
- package/landing-page/src/app/components/ui/table.tsx +116 -0
- package/landing-page/src/app/components/ui/tabs.tsx +66 -0
- package/landing-page/src/app/components/ui/textarea.tsx +18 -0
- package/landing-page/src/app/components/ui/toggle-group.tsx +73 -0
- package/landing-page/src/app/components/ui/toggle.tsx +47 -0
- package/landing-page/src/app/components/ui/tooltip.tsx +61 -0
- package/landing-page/src/app/components/ui/use-mobile.ts +21 -0
- package/landing-page/src/app/components/ui/utils.ts +6 -0
- package/landing-page/src/components/docs/DocsContent.tsx +718 -0
- package/landing-page/src/components/docs/DocsSidebar.tsx +84 -0
- package/landing-page/src/components/landing/CTA.tsx +59 -0
- package/landing-page/src/components/landing/Comparison.tsx +84 -0
- package/landing-page/src/components/landing/FaultyTerminal.tsx +424 -0
- package/landing-page/src/components/landing/Features.tsx +201 -0
- package/landing-page/src/components/landing/Hero.tsx +142 -0
- package/landing-page/src/components/landing/Pricing.tsx +140 -0
- package/landing-page/src/components/landing/Roadmap.tsx +86 -0
- package/landing-page/src/components/landing/Security.tsx +81 -0
- package/landing-page/src/components/landing/TerminalWindow.tsx +27 -0
- package/landing-page/src/components/landing/UseCases.tsx +55 -0
- package/landing-page/src/components/landing/Workflow.tsx +101 -0
- package/landing-page/src/components/layout/DashboardNavbar.tsx +37 -0
- package/landing-page/src/components/layout/Footer.tsx +55 -0
- package/landing-page/src/components/layout/LandingNavbar.tsx +82 -0
- package/landing-page/src/components/ui/badge.tsx +39 -0
- package/landing-page/src/components/ui/breadcrumb.tsx +115 -0
- package/landing-page/src/components/ui/button.tsx +57 -0
- package/landing-page/src/components/ui/card.tsx +79 -0
- package/landing-page/src/components/ui/mock-terminal.tsx +68 -0
- package/landing-page/src/components/ui/separator.tsx +28 -0
- package/landing-page/src/lib/utils.ts +6 -0
- package/landing-page/src/main.tsx +10 -0
- package/landing-page/src/pages/Dashboard.tsx +133 -0
- package/landing-page/src/pages/DocsPage.tsx +79 -0
- package/landing-page/src/pages/LandingPage.tsx +31 -0
- package/landing-page/src/pages/TerminalView.tsx +106 -0
- package/landing-page/src/styles/fonts.css +0 -0
- package/landing-page/src/styles/index.css +3 -0
- package/landing-page/src/styles/tailwind.css +4 -0
- package/landing-page/src/styles/theme.css +181 -0
- package/landing-page/vite.config.ts +19 -0
- package/npm/darwin-arm64/bin/gssh +0 -0
- package/npm/darwin-arm64/package.json +20 -0
- package/package.json +74 -0
- package/scripts/build.ts +284 -0
- package/scripts/release.ts +140 -0
- package/src/__tests__/test-utils.ts +298 -0
- package/src/commands/__tests__/serve-messages.test.ts +190 -0
- package/src/commands/access.ts +298 -0
- package/src/commands/add.ts +452 -0
- package/src/commands/auth.ts +364 -0
- package/src/commands/connect.ts +287 -0
- package/src/commands/directory.ts +16 -0
- package/src/commands/host.ts +396 -0
- package/src/commands/identity.ts +184 -0
- package/src/commands/list.ts +200 -0
- package/src/commands/relay.ts +315 -0
- package/src/commands/remove.ts +241 -0
- package/src/commands/serve.ts +1493 -0
- package/src/commands/share.ts +456 -0
- package/src/commands/status.ts +125 -0
- package/src/commands/switch.ts +353 -0
- package/src/commands/tmux.ts +317 -0
- package/src/core/__tests__/access.test.ts +240 -0
- package/src/core/access.ts +277 -0
- package/src/core/bundle.ts +342 -0
- package/src/core/config.ts +510 -0
- package/src/core/git.ts +317 -0
- package/src/core/github.ts +151 -0
- package/src/core/identity.ts +631 -0
- package/src/core/linear.ts +225 -0
- package/src/core/shell.ts +161 -0
- package/src/core/trusted-relays.ts +315 -0
- package/src/index.ts +821 -0
- package/src/lib/remote-session/index.ts +7 -0
- package/src/lib/remote-session/protocol.ts +267 -0
- package/src/lib/remote-session/session-handler.ts +581 -0
- package/src/lib/remote-session/workspace-scanner.ts +167 -0
- package/src/lib/tmux-lite/README.md +81 -0
- package/src/lib/tmux-lite/cli.ts +796 -0
- package/src/lib/tmux-lite/crypto/__tests__/helpers/handshake-runner.ts +349 -0
- package/src/lib/tmux-lite/crypto/__tests__/helpers/mock-relay.ts +291 -0
- package/src/lib/tmux-lite/crypto/__tests__/helpers/test-identities.ts +142 -0
- package/src/lib/tmux-lite/crypto/__tests__/integration/authorization.integration.test.ts +339 -0
- package/src/lib/tmux-lite/crypto/__tests__/integration/e2e-communication.integration.test.ts +477 -0
- package/src/lib/tmux-lite/crypto/__tests__/integration/error-handling.integration.test.ts +499 -0
- package/src/lib/tmux-lite/crypto/__tests__/integration/handshake.integration.test.ts +371 -0
- package/src/lib/tmux-lite/crypto/__tests__/integration/security.integration.test.ts +573 -0
- package/src/lib/tmux-lite/crypto/access-control.test.ts +512 -0
- package/src/lib/tmux-lite/crypto/access-control.ts +320 -0
- package/src/lib/tmux-lite/crypto/frames.test.ts +262 -0
- package/src/lib/tmux-lite/crypto/frames.ts +141 -0
- package/src/lib/tmux-lite/crypto/handshake.ts +894 -0
- package/src/lib/tmux-lite/crypto/identity.test.ts +220 -0
- package/src/lib/tmux-lite/crypto/identity.ts +286 -0
- package/src/lib/tmux-lite/crypto/index.ts +51 -0
- package/src/lib/tmux-lite/crypto/invites.test.ts +381 -0
- package/src/lib/tmux-lite/crypto/invites.ts +215 -0
- package/src/lib/tmux-lite/crypto/keyexchange.ts +435 -0
- package/src/lib/tmux-lite/crypto/keys.test.ts +58 -0
- package/src/lib/tmux-lite/crypto/keys.ts +47 -0
- package/src/lib/tmux-lite/crypto/secretbox.test.ts +169 -0
- package/src/lib/tmux-lite/crypto/secretbox.ts +124 -0
- package/src/lib/tmux-lite/handshake-handler.ts +451 -0
- package/src/lib/tmux-lite/protocol.test.ts +307 -0
- package/src/lib/tmux-lite/protocol.ts +266 -0
- package/src/lib/tmux-lite/relay-client.ts +506 -0
- package/src/lib/tmux-lite/server.ts +1250 -0
- package/src/lib/tmux-lite/shell-integration.sh +37 -0
- package/src/lib/tmux-lite/terminal-queries.test.ts +54 -0
- package/src/lib/tmux-lite/terminal-queries.ts +49 -0
- package/src/relay/__tests__/e2e-flow.test.ts +1284 -0
- package/src/relay/__tests__/helpers/auth.ts +354 -0
- package/src/relay/__tests__/helpers/ports.ts +51 -0
- package/src/relay/__tests__/protocol-validation.test.ts +265 -0
- package/src/relay/authorization.ts +303 -0
- package/src/relay/embedded-assets.generated.d.ts +15 -0
- package/src/relay/identity.ts +352 -0
- package/src/relay/index.ts +57 -0
- package/src/relay/pipes.test.ts +427 -0
- package/src/relay/pipes.ts +195 -0
- package/src/relay/protocol.ts +804 -0
- package/src/relay/registries.test.ts +437 -0
- package/src/relay/registries.ts +593 -0
- package/src/relay/server.test.ts +1323 -0
- package/src/relay/server.ts +1092 -0
- package/src/relay/signing.ts +238 -0
- package/src/relay/types.ts +69 -0
- package/src/serve/client-session-manager.ts +622 -0
- package/src/serve/daemon.ts +497 -0
- package/src/serve/pty-session.ts +236 -0
- package/src/serve/types.ts +169 -0
- package/src/shared/components/Flow.tsx +453 -0
- package/src/shared/components/Flow.tui.tsx +343 -0
- package/src/shared/components/Flow.web.tsx +442 -0
- package/src/shared/components/Inbox.tsx +446 -0
- package/src/shared/components/Inbox.tui.tsx +262 -0
- package/src/shared/components/Inbox.web.tsx +329 -0
- package/src/shared/components/MachineList.tsx +187 -0
- package/src/shared/components/MachineList.tui.tsx +161 -0
- package/src/shared/components/MachineList.web.tsx +210 -0
- package/src/shared/components/ProjectList.tsx +176 -0
- package/src/shared/components/ProjectList.tui.tsx +109 -0
- package/src/shared/components/ProjectList.web.tsx +143 -0
- package/src/shared/components/SpacesBrowser.tsx +332 -0
- package/src/shared/components/SpacesBrowser.tui.tsx +163 -0
- package/src/shared/components/SpacesBrowser.web.tsx +221 -0
- package/src/shared/components/index.ts +103 -0
- package/src/shared/hooks/index.ts +16 -0
- package/src/shared/hooks/useNavigation.ts +226 -0
- package/src/shared/index.ts +122 -0
- package/src/shared/providers/LocalMachineProvider.ts +425 -0
- package/src/shared/providers/MachineProvider.ts +165 -0
- package/src/shared/providers/RemoteMachineProvider.ts +444 -0
- package/src/shared/providers/index.ts +26 -0
- package/src/shared/types.ts +145 -0
- package/src/tui/adapters.ts +120 -0
- package/src/tui/app.tsx +1816 -0
- package/src/tui/components/Terminal.tsx +580 -0
- package/src/tui/hooks/index.ts +35 -0
- package/src/tui/hooks/useAppState.ts +314 -0
- package/src/tui/hooks/useDaemonStatus.ts +174 -0
- package/src/tui/hooks/useInboxTUI.ts +113 -0
- package/src/tui/hooks/useRemoteMachines.ts +209 -0
- package/src/tui/index.ts +24 -0
- package/src/tui/state.ts +299 -0
- package/src/tui/terminal-bracketed-paste.test.ts +45 -0
- package/src/tui/terminal-bracketed-paste.ts +47 -0
- package/src/types/bundle.ts +112 -0
- package/src/types/config.ts +89 -0
- package/src/types/errors.ts +206 -0
- package/src/types/identity.ts +284 -0
- package/src/types/workspace-fuzzy.ts +49 -0
- package/src/types/workspace.ts +151 -0
- package/src/utils/bun-socket-writer.ts +80 -0
- package/src/utils/deps.ts +127 -0
- package/src/utils/fuzzy-match.ts +125 -0
- package/src/utils/logger.ts +127 -0
- package/src/utils/markdown.ts +254 -0
- package/src/utils/onboarding.ts +229 -0
- package/src/utils/prompts.ts +114 -0
- package/src/utils/run-commands.ts +112 -0
- package/src/utils/run-scripts.ts +142 -0
- package/src/utils/sanitize.ts +98 -0
- package/src/utils/secrets.ts +122 -0
- package/src/utils/shell-escape.ts +40 -0
- package/src/utils/utf8.ts +79 -0
- package/src/utils/workspace-state.ts +47 -0
- package/src/web/README.md +73 -0
- package/src/web/bun.lock +575 -0
- package/src/web/eslint.config.js +23 -0
- package/src/web/index.html +16 -0
- package/src/web/package.json +37 -0
- package/src/web/public/vite.svg +1 -0
- package/src/web/src/App.tsx +604 -0
- package/src/web/src/assets/react.svg +1 -0
- package/src/web/src/components/Terminal.tsx +207 -0
- package/src/web/src/hooks/useRelayConnection.ts +224 -0
- package/src/web/src/hooks/useTerminal.ts +699 -0
- package/src/web/src/index.css +55 -0
- package/src/web/src/lib/crypto/__tests__/web-terminal.test.ts +1158 -0
- package/src/web/src/lib/crypto/frames.ts +205 -0
- package/src/web/src/lib/crypto/handshake.ts +396 -0
- package/src/web/src/lib/crypto/identity.ts +128 -0
- package/src/web/src/lib/crypto/keyexchange.ts +246 -0
- package/src/web/src/lib/crypto/relay-signing.ts +53 -0
- package/src/web/src/lib/invite.ts +58 -0
- package/src/web/src/lib/storage/identity-store.ts +94 -0
- package/src/web/src/main.tsx +10 -0
- package/src/web/src/types/identity.ts +45 -0
- package/src/web/tsconfig.app.json +28 -0
- package/src/web/tsconfig.json +7 -0
- package/src/web/tsconfig.node.json +26 -0
- package/src/web/vite.config.ts +31 -0
- package/todo-security.md +92 -0
- package/tsconfig.json +23 -0
- package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/12b7107e435bf1b9a8713a7f320472a63e543104d633d89a26f8d21f4e4ef182.sqlite +0 -0
- package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/12b7107e435bf1b9a8713a7f320472a63e543104d633d89a26f8d21f4e4ef182.sqlite-shm +0 -0
- package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/12b7107e435bf1b9a8713a7f320472a63e543104d633d89a26f8d21f4e4ef182.sqlite-wal +0 -0
- package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/1a1ac3db1ab86ecf712f90322868a9aabc2c7dc9fe2dfbe94f9b075096276b0f.sqlite +0 -0
- package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/1a1ac3db1ab86ecf712f90322868a9aabc2c7dc9fe2dfbe94f9b075096276b0f.sqlite-shm +0 -0
- package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/1a1ac3db1ab86ecf712f90322868a9aabc2c7dc9fe2dfbe94f9b075096276b0f.sqlite-wal +0 -0
- package/worker/bun.lock +237 -0
- package/worker/package.json +22 -0
- package/worker/schema.sql +96 -0
- package/worker/src/handlers/auth.ts +451 -0
- package/worker/src/handlers/subdomains.ts +376 -0
- package/worker/src/handlers/user.ts +98 -0
- package/worker/src/index.ts +70 -0
- package/worker/src/middleware/auth.ts +152 -0
- package/worker/src/services/cloudflare.ts +609 -0
- package/worker/src/types.ts +96 -0
- package/worker/tsconfig.json +15 -0
- package/worker/wrangler.toml +26 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { cn } from "../../lib/utils";
|
|
3
|
+
|
|
4
|
+
interface TerminalWindowProps {
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
title?: string;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function TerminalWindow({ children, title = "bash", className }: TerminalWindowProps) {
|
|
11
|
+
return (
|
|
12
|
+
<div className={cn("rounded-lg overflow-hidden border border-zinc-800 bg-black/90 font-mono shadow-2xl", className)}>
|
|
13
|
+
<div className="flex items-center justify-between px-4 py-2 bg-zinc-900/50 border-b border-zinc-800">
|
|
14
|
+
<div className="flex space-x-2">
|
|
15
|
+
<div className="w-3 h-3 rounded-full bg-red-500/20 border border-red-500/50" />
|
|
16
|
+
<div className="w-3 h-3 rounded-full bg-yellow-500/20 border border-yellow-500/50" />
|
|
17
|
+
<div className="w-3 h-3 rounded-full bg-green-500/20 border border-green-500/50" />
|
|
18
|
+
</div>
|
|
19
|
+
<div className="text-xs text-zinc-500 font-medium">{title}</div>
|
|
20
|
+
<div className="w-16" /> {/* Spacer for centering */}
|
|
21
|
+
</div>
|
|
22
|
+
<div className="p-4 text-sm md:text-base text-zinc-300 overflow-x-auto">
|
|
23
|
+
{children}
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Quote, Star } from "lucide-react";
|
|
2
|
+
import { Card, CardContent } from "../../app/components/ui/card";
|
|
3
|
+
|
|
4
|
+
export function UseCases() {
|
|
5
|
+
const testimonials = [
|
|
6
|
+
{
|
|
7
|
+
quote: "I run 3-4 Claude agents in parallel now. Each in its own space. I check progress from my phone while making dinner. When they're done, git stack turns the mess into reviewable PRs.",
|
|
8
|
+
author: "Solo founder",
|
|
9
|
+
role: "Shipping 3x faster",
|
|
10
|
+
stars: 5
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
quote: "We share view-only links in Slack. Everyone can watch the agent work without stepping on each other. Game changer for debugging.",
|
|
14
|
+
author: "Tech lead",
|
|
15
|
+
role: "8-person startup",
|
|
16
|
+
stars: 5
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
quote: "No more 'hold on, let me stash my changes.' I have 6 workspaces open right now. Context switching is instant.",
|
|
20
|
+
author: "Senior engineer",
|
|
21
|
+
role: "Enterprise",
|
|
22
|
+
stars: 5
|
|
23
|
+
}
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<section className="py-24 bg-zinc-900/20">
|
|
28
|
+
<div className="container px-4 mx-auto">
|
|
29
|
+
<h2 className="text-3xl md:text-5xl font-bold text-center mb-16">How developers use GitSpace</h2>
|
|
30
|
+
|
|
31
|
+
<div className="grid md:grid-cols-3 gap-8">
|
|
32
|
+
{testimonials.map((item, i) => (
|
|
33
|
+
<Card key={i} className="bg-black/40 border-zinc-800 hover:border-zinc-700 transition-colors">
|
|
34
|
+
<CardContent className="pt-6">
|
|
35
|
+
<div className="flex gap-1 mb-4">
|
|
36
|
+
{[...Array(item.stars)].map((_, i) => (
|
|
37
|
+
<Star key={i} className="w-4 h-4 fill-green-500 text-green-500" />
|
|
38
|
+
))}
|
|
39
|
+
</div>
|
|
40
|
+
<Quote className="w-8 h-8 text-zinc-700 mb-4" />
|
|
41
|
+
<p className="text-zinc-300 leading-relaxed mb-6 italic">
|
|
42
|
+
"{item.quote}"
|
|
43
|
+
</p>
|
|
44
|
+
<div className="border-t border-zinc-800 pt-4">
|
|
45
|
+
<p className="font-bold text-white">{item.author}</p>
|
|
46
|
+
<p className="text-sm text-zinc-500">{item.role}</p>
|
|
47
|
+
</div>
|
|
48
|
+
</CardContent>
|
|
49
|
+
</Card>
|
|
50
|
+
))}
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</section>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { Plus, Play, Smartphone, GitMerge, ArrowRight } from "lucide-react";
|
|
2
|
+
|
|
3
|
+
export function Workflow() {
|
|
4
|
+
return (
|
|
5
|
+
<section id="workflow" className="py-24 bg-zinc-950 relative overflow-hidden">
|
|
6
|
+
<div className="container px-4 mx-auto">
|
|
7
|
+
<div className="text-center mb-16">
|
|
8
|
+
<h2 className="text-3xl md:text-5xl font-bold mb-4">Built for how AI agents work</h2>
|
|
9
|
+
<p className="text-zinc-400 max-w-2xl mx-auto">
|
|
10
|
+
The old way: One branch. Wait for agent. Messy commits. Manual cleanup.<br />
|
|
11
|
+
<span className="text-green-400">The GitSpace way: Parallel work. Remote monitoring. Secure relay.</span>
|
|
12
|
+
</p>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<div className="relative">
|
|
16
|
+
{/* Connecting Line (Desktop) */}
|
|
17
|
+
<div className="hidden md:block absolute top-12 left-0 w-full h-0.5 bg-gradient-to-r from-transparent via-zinc-700 to-transparent" />
|
|
18
|
+
|
|
19
|
+
<div className="grid grid-cols-1 md:grid-cols-4 gap-8 relative z-10">
|
|
20
|
+
<div className="flex flex-col items-center text-center group">
|
|
21
|
+
<div className="w-24 h-24 rounded-2xl bg-black border border-zinc-800 flex items-center justify-center mb-6 shadow-xl group-hover:border-green-500/50 group-hover:shadow-green-500/10 transition-all duration-300 relative">
|
|
22
|
+
<Plus className="w-10 h-10 text-zinc-400 group-hover:text-green-400 transition-colors" />
|
|
23
|
+
<div className="absolute -bottom-3 bg-zinc-900 px-3 py-1 rounded-full text-xs font-bold border border-zinc-800 text-zinc-300">
|
|
24
|
+
CREATE
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<code className="bg-black/50 px-3 py-1 rounded text-sm font-mono text-green-400/80 mb-2 border border-white/5 w-full md:w-auto truncate max-w-[200px]">
|
|
29
|
+
gssh add feature-x
|
|
30
|
+
</code>
|
|
31
|
+
|
|
32
|
+
<p className="text-zinc-500 text-sm">
|
|
33
|
+
Isolated workspace
|
|
34
|
+
</p>
|
|
35
|
+
|
|
36
|
+
{/* Mobile Arrow */}
|
|
37
|
+
<ArrowRight className="md:hidden w-6 h-6 text-zinc-700 my-4" />
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<div className="flex flex-col items-center text-center group">
|
|
41
|
+
<div className="w-24 h-24 rounded-2xl bg-black border border-zinc-800 flex items-center justify-center mb-6 shadow-xl group-hover:border-green-500/50 group-hover:shadow-green-500/10 transition-all duration-300 relative">
|
|
42
|
+
<Play className="w-10 h-10 text-zinc-400 group-hover:text-green-400 transition-colors" />
|
|
43
|
+
<div className="absolute -bottom-3 bg-zinc-900 px-3 py-1 rounded-full text-xs font-bold border border-zinc-800 text-zinc-300">
|
|
44
|
+
RUN
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<code className="bg-black/50 px-3 py-1 rounded text-sm font-mono text-green-400/80 mb-2 border border-white/5 w-full md:w-auto truncate max-w-[200px]">
|
|
49
|
+
claude "add auth system"
|
|
50
|
+
</code>
|
|
51
|
+
|
|
52
|
+
<p className="text-zinc-500 text-sm">
|
|
53
|
+
Agent runs for hours
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
{/* Mobile Arrow */}
|
|
57
|
+
<ArrowRight className="md:hidden w-6 h-6 text-zinc-700 my-4" />
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<div className="flex flex-col items-center text-center group">
|
|
61
|
+
<div className="w-24 h-24 rounded-2xl bg-black border border-zinc-800 flex items-center justify-center mb-6 shadow-xl group-hover:border-green-500/50 group-hover:shadow-green-500/10 transition-all duration-300 relative">
|
|
62
|
+
<Smartphone className="w-10 h-10 text-zinc-400 group-hover:text-green-400 transition-colors" />
|
|
63
|
+
<div className="absolute -bottom-3 bg-zinc-900 px-3 py-1 rounded-full text-xs font-bold border border-zinc-800 text-zinc-300">
|
|
64
|
+
MONITOR
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<code className="bg-black/50 px-3 py-1 rounded text-sm font-mono text-green-400/80 mb-2 border border-white/5 w-full md:w-auto truncate max-w-[200px]">
|
|
69
|
+
Check in from your phone
|
|
70
|
+
</code>
|
|
71
|
+
|
|
72
|
+
<p className="text-zinc-500 text-sm">
|
|
73
|
+
Get notified when done
|
|
74
|
+
</p>
|
|
75
|
+
|
|
76
|
+
{/* Mobile Arrow */}
|
|
77
|
+
<ArrowRight className="md:hidden w-6 h-6 text-zinc-700 my-4" />
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
<div className="flex flex-col items-center text-center group">
|
|
81
|
+
<div className="w-24 h-24 rounded-2xl bg-black border border-zinc-800 flex items-center justify-center mb-6 shadow-xl group-hover:border-green-500/50 group-hover:shadow-green-500/10 transition-all duration-300 relative">
|
|
82
|
+
<GitMerge className="w-10 h-10 text-zinc-400 group-hover:text-green-400 transition-colors" />
|
|
83
|
+
<div className="absolute -bottom-3 bg-zinc-900 px-3 py-1 rounded-full text-xs font-bold border border-zinc-800 text-zinc-300">
|
|
84
|
+
SHIP
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
<code className="bg-black/50 px-3 py-1 rounded text-sm font-mono text-green-400/80 mb-2 border border-white/5 w-full md:w-auto truncate max-w-[200px]">
|
|
89
|
+
gssh switch feature-x
|
|
90
|
+
</code>
|
|
91
|
+
|
|
92
|
+
<p className="text-zinc-500 text-sm">
|
|
93
|
+
Instant context switch
|
|
94
|
+
</p>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
</section>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Link } from "react-router-dom";
|
|
2
|
+
import { Terminal, Bell, ChevronDown } from "lucide-react";
|
|
3
|
+
import { Button } from "../../app/components/ui/button";
|
|
4
|
+
|
|
5
|
+
export function DashboardNavbar() {
|
|
6
|
+
return (
|
|
7
|
+
<nav className="border-b border-white/10 bg-black">
|
|
8
|
+
<div className="container mx-auto px-4 h-14 flex items-center justify-between">
|
|
9
|
+
<Link to="/dashboard" className="flex items-center gap-2 font-semibold text-lg tracking-tight">
|
|
10
|
+
<Terminal className="h-5 w-5 text-green-500" />
|
|
11
|
+
<span>gitspace.sh</span>
|
|
12
|
+
</Link>
|
|
13
|
+
|
|
14
|
+
<div className="flex items-center gap-4">
|
|
15
|
+
<div className="flex items-center gap-2 text-sm font-medium hover:bg-white/5 px-2 py-1.5 rounded-md cursor-pointer transition-colors">
|
|
16
|
+
<div className="h-6 w-6 rounded-full bg-green-500/20 flex items-center justify-center text-green-500 text-xs">B</div>
|
|
17
|
+
<span>brad</span>
|
|
18
|
+
<ChevronDown className="h-4 w-4 text-muted-foreground" />
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<div className="h-8 w-[1px] bg-white/10" />
|
|
22
|
+
|
|
23
|
+
<Button variant="ghost" size="icon" className="relative text-muted-foreground hover:text-foreground">
|
|
24
|
+
<Bell className="h-5 w-5" />
|
|
25
|
+
<span className="absolute top-2 right-2 h-2 w-2 rounded-full bg-red-500 border-2 border-black" />
|
|
26
|
+
</Button>
|
|
27
|
+
|
|
28
|
+
<Link to="/">
|
|
29
|
+
<Button variant="ghost" size="sm" className="text-muted-foreground hover:text-foreground">
|
|
30
|
+
Logout
|
|
31
|
+
</Button>
|
|
32
|
+
</Link>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</nav>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Link } from "react-router-dom";
|
|
2
|
+
import { Terminal } from "lucide-react";
|
|
3
|
+
|
|
4
|
+
export function Footer() {
|
|
5
|
+
return (
|
|
6
|
+
<footer className="border-t border-white/10 bg-black py-12 text-sm">
|
|
7
|
+
<div className="container mx-auto px-4">
|
|
8
|
+
<div className="grid grid-cols-1 md:grid-cols-4 gap-8 mb-12">
|
|
9
|
+
<div className="space-y-4">
|
|
10
|
+
<div className="flex items-center gap-2 font-semibold text-lg tracking-tight">
|
|
11
|
+
<Terminal className="h-5 w-5 text-green-500" />
|
|
12
|
+
<span>gitspace.sh</span>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div className="space-y-4">
|
|
17
|
+
<h4 className="font-semibold">Product</h4>
|
|
18
|
+
<ul className="space-y-2 text-muted-foreground">
|
|
19
|
+
<li><Link to="/#features" className="hover:text-foreground">Features</Link></li>
|
|
20
|
+
<li><Link to="/#pricing" className="hover:text-foreground">Pricing</Link></li>
|
|
21
|
+
<li><Link to="/docs?section=security-notes" className="hover:text-foreground">Security</Link></li>
|
|
22
|
+
<li><Link to="/#workflow" className="hover:text-foreground">Workflow</Link></li>
|
|
23
|
+
</ul>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<div className="space-y-4">
|
|
27
|
+
<h4 className="font-semibold">Resources</h4>
|
|
28
|
+
<ul className="space-y-2 text-muted-foreground">
|
|
29
|
+
<li><Link to="/docs" className="hover:text-foreground">Docs</Link></li>
|
|
30
|
+
<li><a href="https://github.com/inkibra/gitspace.sh" target="_blank" rel="noopener noreferrer" className="hover:text-foreground">GitHub</a></li>
|
|
31
|
+
<li><a href="https://discord.gg/kHRWYPnR" target="_blank" rel="noopener noreferrer" className="hover:text-foreground">Discord</a></li>
|
|
32
|
+
</ul>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<div className="space-y-4">
|
|
36
|
+
<h4 className="font-semibold">Company</h4>
|
|
37
|
+
<ul className="space-y-2 text-muted-foreground">
|
|
38
|
+
<li><a href="https://www.inkibra.com/ink" target="_blank" rel="noopener noreferrer" className="hover:text-foreground">About</a></li>
|
|
39
|
+
<li><a href="https://www.inkibra.com/ink/blog" target="_blank" rel="noopener noreferrer" className="hover:text-foreground">Blog</a></li>
|
|
40
|
+
</ul>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div className="pt-8 border-t border-white/10 flex flex-col md:flex-row justify-between items-center gap-4 text-muted-foreground">
|
|
45
|
+
<p>© 2026 inkibra, Inc.</p>
|
|
46
|
+
<div className="flex gap-6">
|
|
47
|
+
<a href="https://www.inkibra.com/legal/privacy-policy" target="_blank" rel="noopener noreferrer" className="hover:text-foreground">Privacy</a>
|
|
48
|
+
<a href="https://www.inkibra.com/legal/terms-of-service" target="_blank" rel="noopener noreferrer" className="hover:text-foreground">Terms</a>
|
|
49
|
+
<Link to="/docs?section=security-notes" className="hover:text-foreground">Security</Link>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</footer>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Link } from "react-router-dom";
|
|
2
|
+
import { Button } from "../../app/components/ui/button";
|
|
3
|
+
import { Terminal, Menu, X, Github } from "lucide-react";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { motion, AnimatePresence } from "motion/react";
|
|
6
|
+
|
|
7
|
+
export function LandingNavbar() {
|
|
8
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
9
|
+
|
|
10
|
+
const navLinks = [
|
|
11
|
+
{ name: "Features", href: "/#features" },
|
|
12
|
+
{ name: "Pricing", href: "/#pricing" },
|
|
13
|
+
{ name: "Docs", href: "/docs" },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<nav className="border-b border-white/10 bg-black/50 backdrop-blur-md sticky top-0 z-50">
|
|
18
|
+
<div className="container mx-auto px-4 h-14 flex items-center justify-between">
|
|
19
|
+
<Link to="/" className="flex items-center gap-2 font-semibold text-lg tracking-tight z-50">
|
|
20
|
+
<Terminal className="h-5 w-5 text-green-500" />
|
|
21
|
+
<span>gitspace.sh</span>
|
|
22
|
+
</Link>
|
|
23
|
+
|
|
24
|
+
{/* Desktop Nav */}
|
|
25
|
+
<div className="hidden md:flex items-center gap-6 text-sm font-medium text-muted-foreground">
|
|
26
|
+
{navLinks.map((link) => (
|
|
27
|
+
<Link key={link.name} to={link.href} className="hover:text-foreground transition-colors">
|
|
28
|
+
{link.name}
|
|
29
|
+
</Link>
|
|
30
|
+
))}
|
|
31
|
+
<a href="https://github.com/inkibra/gitspace.sh" target="_blank" rel="noopener noreferrer">
|
|
32
|
+
<Button size="sm" className="bg-white text-black hover:bg-gray-200">
|
|
33
|
+
<Github className="w-4 h-4 mr-2" />
|
|
34
|
+
Star on GitHub
|
|
35
|
+
</Button>
|
|
36
|
+
</a>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
{/* Mobile Menu Toggle */}
|
|
40
|
+
<button
|
|
41
|
+
className="md:hidden z-50 p-2 text-zinc-400 hover:text-white"
|
|
42
|
+
onClick={() => setIsOpen(!isOpen)}
|
|
43
|
+
>
|
|
44
|
+
{isOpen ? <X className="h-6 w-6" /> : <Menu className="h-6 w-6" />}
|
|
45
|
+
</button>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
{/* Mobile Nav Overlay */}
|
|
49
|
+
<AnimatePresence>
|
|
50
|
+
{isOpen && (
|
|
51
|
+
<motion.div
|
|
52
|
+
initial={{ opacity: 0, y: -20 }}
|
|
53
|
+
animate={{ opacity: 1, y: 0 }}
|
|
54
|
+
exit={{ opacity: 0, y: -20 }}
|
|
55
|
+
transition={{ duration: 0.2 }}
|
|
56
|
+
className="fixed inset-0 z-40 md:hidden bg-black/95 backdrop-blur-xl pt-24 px-6 flex flex-col gap-8"
|
|
57
|
+
>
|
|
58
|
+
<div className="flex flex-col gap-6 text-xl font-medium text-zinc-400">
|
|
59
|
+
{navLinks.map((link) => (
|
|
60
|
+
<Link
|
|
61
|
+
key={link.name}
|
|
62
|
+
to={link.href}
|
|
63
|
+
onClick={() => setIsOpen(false)}
|
|
64
|
+
className="hover:text-white transition-colors"
|
|
65
|
+
>
|
|
66
|
+
{link.name}
|
|
67
|
+
</Link>
|
|
68
|
+
))}
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<a href="https://github.com/inkibra/gitspace.sh" target="_blank" rel="noopener noreferrer" onClick={() => setIsOpen(false)} className="mt-auto mb-12">
|
|
72
|
+
<Button size="lg" className="w-full bg-white text-black hover:bg-gray-200 text-base py-6">
|
|
73
|
+
<Github className="w-5 h-5 mr-2" />
|
|
74
|
+
Star on GitHub
|
|
75
|
+
</Button>
|
|
76
|
+
</a>
|
|
77
|
+
</motion.div>
|
|
78
|
+
)}
|
|
79
|
+
</AnimatePresence>
|
|
80
|
+
</nav>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
3
|
+
|
|
4
|
+
import { cn } from "../../lib/utils"
|
|
5
|
+
|
|
6
|
+
const badgeVariants = cva(
|
|
7
|
+
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default:
|
|
12
|
+
"border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
|
|
13
|
+
secondary:
|
|
14
|
+
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
15
|
+
destructive:
|
|
16
|
+
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
17
|
+
outline: "text-foreground",
|
|
18
|
+
success: "border-transparent bg-green-500/15 text-green-500 hover:bg-green-500/25",
|
|
19
|
+
warning: "border-transparent bg-amber-500/15 text-amber-500 hover:bg-amber-500/25",
|
|
20
|
+
error: "border-transparent bg-red-500/15 text-red-500 hover:bg-red-500/25",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
defaultVariants: {
|
|
24
|
+
variant: "default",
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
export interface BadgeProps
|
|
30
|
+
extends React.HTMLAttributes<HTMLDivElement>,
|
|
31
|
+
VariantProps<typeof badgeVariants> {}
|
|
32
|
+
|
|
33
|
+
function Badge({ className, variant, ...props }: BadgeProps) {
|
|
34
|
+
return (
|
|
35
|
+
<div className={cn(badgeVariants({ variant }), className)} {...props} />
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export { Badge, badgeVariants }
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { ChevronRight, MoreHorizontal } from "lucide-react"
|
|
3
|
+
import { Slot } from "@radix-ui/react-slot"
|
|
4
|
+
|
|
5
|
+
import { cn } from "../../lib/utils"
|
|
6
|
+
|
|
7
|
+
const Breadcrumb = React.forwardRef<
|
|
8
|
+
HTMLElement,
|
|
9
|
+
React.ComponentPropsWithoutRef<"nav"> & {
|
|
10
|
+
separator?: React.ReactNode
|
|
11
|
+
}
|
|
12
|
+
>(({ ...props }, ref) => <nav ref={ref} aria-label="breadcrumb" {...props} />)
|
|
13
|
+
Breadcrumb.displayName = "Breadcrumb"
|
|
14
|
+
|
|
15
|
+
const BreadcrumbList = React.forwardRef<
|
|
16
|
+
HTMLOListElement,
|
|
17
|
+
React.ComponentPropsWithoutRef<"ol">
|
|
18
|
+
>(({ className, ...props }, ref) => (
|
|
19
|
+
<ol
|
|
20
|
+
ref={ref}
|
|
21
|
+
className={cn(
|
|
22
|
+
"flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5",
|
|
23
|
+
className
|
|
24
|
+
)}
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|
|
27
|
+
))
|
|
28
|
+
BreadcrumbList.displayName = "BreadcrumbList"
|
|
29
|
+
|
|
30
|
+
const BreadcrumbItem = React.forwardRef<
|
|
31
|
+
HTMLLIElement,
|
|
32
|
+
React.ComponentPropsWithoutRef<"li">
|
|
33
|
+
>(({ className, ...props }, ref) => (
|
|
34
|
+
<li
|
|
35
|
+
ref={ref}
|
|
36
|
+
className={cn("inline-flex items-center gap-1.5", className)}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
))
|
|
40
|
+
BreadcrumbItem.displayName = "BreadcrumbItem"
|
|
41
|
+
|
|
42
|
+
const BreadcrumbLink = React.forwardRef<
|
|
43
|
+
HTMLAnchorElement,
|
|
44
|
+
React.ComponentPropsWithoutRef<"a"> & {
|
|
45
|
+
asChild?: boolean
|
|
46
|
+
}
|
|
47
|
+
>(({ asChild, className, ...props }, ref) => {
|
|
48
|
+
const Comp = asChild ? Slot : "a"
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<Comp
|
|
52
|
+
ref={ref}
|
|
53
|
+
className={cn("transition-colors hover:text-foreground", className)}
|
|
54
|
+
{...props}
|
|
55
|
+
/>
|
|
56
|
+
)
|
|
57
|
+
})
|
|
58
|
+
BreadcrumbLink.displayName = "BreadcrumbLink"
|
|
59
|
+
|
|
60
|
+
const BreadcrumbPage = React.forwardRef<
|
|
61
|
+
HTMLSpanElement,
|
|
62
|
+
React.ComponentPropsWithoutRef<"span">
|
|
63
|
+
>(({ className, ...props }, ref) => (
|
|
64
|
+
<span
|
|
65
|
+
ref={ref}
|
|
66
|
+
role="link"
|
|
67
|
+
aria-disabled="true"
|
|
68
|
+
aria-current="page"
|
|
69
|
+
className={cn("font-normal text-foreground", className)}
|
|
70
|
+
{...props}
|
|
71
|
+
/>
|
|
72
|
+
))
|
|
73
|
+
BreadcrumbPage.displayName = "BreadcrumbPage"
|
|
74
|
+
|
|
75
|
+
const BreadcrumbSeparator = ({
|
|
76
|
+
children,
|
|
77
|
+
className,
|
|
78
|
+
...props
|
|
79
|
+
}: React.ComponentProps<"li">) => (
|
|
80
|
+
<li
|
|
81
|
+
role="presentation"
|
|
82
|
+
aria-hidden="true"
|
|
83
|
+
className={cn("[&>svg]:size-3.5", className)}
|
|
84
|
+
{...props}
|
|
85
|
+
>
|
|
86
|
+
{children ?? <ChevronRight />}
|
|
87
|
+
</li>
|
|
88
|
+
)
|
|
89
|
+
BreadcrumbSeparator.displayName = "BreadcrumbSeparator"
|
|
90
|
+
|
|
91
|
+
const BreadcrumbEllipsis = ({
|
|
92
|
+
className,
|
|
93
|
+
...props
|
|
94
|
+
}: React.ComponentProps<"span">) => (
|
|
95
|
+
<span
|
|
96
|
+
role="presentation"
|
|
97
|
+
aria-hidden="true"
|
|
98
|
+
className={cn("flex h-9 w-9 items-center justify-center", className)}
|
|
99
|
+
{...props}
|
|
100
|
+
>
|
|
101
|
+
<MoreHorizontal className="h-4 w-4" />
|
|
102
|
+
<span className="sr-only">More</span>
|
|
103
|
+
</span>
|
|
104
|
+
)
|
|
105
|
+
BreadcrumbEllipsis.displayName = "BreadcrumbEllipsis"
|
|
106
|
+
|
|
107
|
+
export {
|
|
108
|
+
Breadcrumb,
|
|
109
|
+
BreadcrumbList,
|
|
110
|
+
BreadcrumbItem,
|
|
111
|
+
BreadcrumbLink,
|
|
112
|
+
BreadcrumbPage,
|
|
113
|
+
BreadcrumbSeparator,
|
|
114
|
+
BreadcrumbEllipsis,
|
|
115
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Slot } from "@radix-ui/react-slot"
|
|
3
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
4
|
+
|
|
5
|
+
import { cn } from "../../lib/utils"
|
|
6
|
+
|
|
7
|
+
const buttonVariants = cva(
|
|
8
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
13
|
+
destructive:
|
|
14
|
+
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
15
|
+
outline:
|
|
16
|
+
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
17
|
+
secondary:
|
|
18
|
+
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
19
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
20
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
21
|
+
terminal: "bg-green-600 text-black hover:bg-green-500 font-mono",
|
|
22
|
+
},
|
|
23
|
+
size: {
|
|
24
|
+
default: "h-10 px-4 py-2",
|
|
25
|
+
sm: "h-9 rounded-md px-3",
|
|
26
|
+
lg: "h-11 rounded-md px-8",
|
|
27
|
+
icon: "h-10 w-10",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
defaultVariants: {
|
|
31
|
+
variant: "default",
|
|
32
|
+
size: "default",
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
export interface ButtonProps
|
|
38
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
39
|
+
VariantProps<typeof buttonVariants> {
|
|
40
|
+
asChild?: boolean
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
44
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
45
|
+
const Comp = asChild ? Slot : "button"
|
|
46
|
+
return (
|
|
47
|
+
<Comp
|
|
48
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
49
|
+
ref={ref}
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
Button.displayName = "Button"
|
|
56
|
+
|
|
57
|
+
export { Button, buttonVariants }
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../lib/utils"
|
|
4
|
+
|
|
5
|
+
const Card = React.forwardRef<
|
|
6
|
+
HTMLDivElement,
|
|
7
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
8
|
+
>(({ className, ...props }, ref) => (
|
|
9
|
+
<div
|
|
10
|
+
ref={ref}
|
|
11
|
+
className={cn(
|
|
12
|
+
"rounded-lg border bg-card text-card-foreground shadow-sm",
|
|
13
|
+
className
|
|
14
|
+
)}
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
))
|
|
18
|
+
Card.displayName = "Card"
|
|
19
|
+
|
|
20
|
+
const CardHeader = React.forwardRef<
|
|
21
|
+
HTMLDivElement,
|
|
22
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
23
|
+
>(({ className, ...props }, ref) => (
|
|
24
|
+
<div
|
|
25
|
+
ref={ref}
|
|
26
|
+
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
|
27
|
+
{...props}
|
|
28
|
+
/>
|
|
29
|
+
))
|
|
30
|
+
CardHeader.displayName = "CardHeader"
|
|
31
|
+
|
|
32
|
+
const CardTitle = React.forwardRef<
|
|
33
|
+
HTMLParagraphElement,
|
|
34
|
+
React.HTMLAttributes<HTMLHeadingElement>
|
|
35
|
+
>(({ className, ...props }, ref) => (
|
|
36
|
+
<h3
|
|
37
|
+
ref={ref}
|
|
38
|
+
className={cn(
|
|
39
|
+
"text-2xl font-semibold leading-none tracking-tight",
|
|
40
|
+
className
|
|
41
|
+
)}
|
|
42
|
+
{...props}
|
|
43
|
+
/>
|
|
44
|
+
))
|
|
45
|
+
CardTitle.displayName = "CardTitle"
|
|
46
|
+
|
|
47
|
+
const CardDescription = React.forwardRef<
|
|
48
|
+
HTMLParagraphElement,
|
|
49
|
+
React.HTMLAttributes<HTMLParagraphElement>
|
|
50
|
+
>(({ className, ...props }, ref) => (
|
|
51
|
+
<p
|
|
52
|
+
ref={ref}
|
|
53
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
54
|
+
{...props}
|
|
55
|
+
/>
|
|
56
|
+
))
|
|
57
|
+
CardDescription.displayName = "CardDescription"
|
|
58
|
+
|
|
59
|
+
const CardContent = React.forwardRef<
|
|
60
|
+
HTMLDivElement,
|
|
61
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
62
|
+
>(({ className, ...props }, ref) => (
|
|
63
|
+
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
|
64
|
+
))
|
|
65
|
+
CardContent.displayName = "CardContent"
|
|
66
|
+
|
|
67
|
+
const CardFooter = React.forwardRef<
|
|
68
|
+
HTMLDivElement,
|
|
69
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
70
|
+
>(({ className, ...props }, ref) => (
|
|
71
|
+
<div
|
|
72
|
+
ref={ref}
|
|
73
|
+
className={cn("flex items-center p-6 pt-0", className)}
|
|
74
|
+
{...props}
|
|
75
|
+
/>
|
|
76
|
+
))
|
|
77
|
+
CardFooter.displayName = "CardFooter"
|
|
78
|
+
|
|
79
|
+
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
|