landing.tsx•7.05 kB
import { useState } from "react";
import { useLocation } from "wouter";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Card, CardContent } from "@/components/ui/card";
import { Eye, EyeOff, Rocket, Github, ExternalLink, Bolt } from "lucide-react";
import { useToast } from "@/hooks/use-toast";
import { useMutation } from "@tanstack/react-query";
import { apiRequest } from "@/lib/queryClient";
import LoadingSpinner from "@/components/ui/loading-spinner";
export default function Landing() {
const [token, setToken] = useState("");
const [showToken, setShowToken] = useState(false);
const [, setLocation] = useLocation();
const { toast } = useToast();
const validateTokenMutation = useMutation({
mutationFn: async (token: string) => {
const response = await apiRequest("POST", "/api/token/validate", { token });
return response.json();
},
onSuccess: () => {
toast({
title: "Success!",
description: "GitHub token validated successfully.",
});
setTimeout(() => {
setLocation("/dashboard");
}, 1000);
},
onError: (error: any) => {
toast({
title: "Validation Failed",
description: error.message || "Invalid GitHub token. Please check and try again.",
variant: "destructive",
});
},
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!token.trim()) {
toast({
title: "Token Required",
description: "Please enter a GitHub token.",
variant: "destructive",
});
return;
}
if (!token.startsWith('ghp_') && !token.startsWith('github_pat_')) {
toast({
title: "Invalid Format",
description: "Please enter a valid GitHub personal access token.",
variant: "destructive",
});
return;
}
validateTokenMutation.mutate(token);
};
return (
<div className="min-h-screen flex items-center justify-center px-4 bg-gradient-to-br from-background to-muted">
<div className="max-w-md w-full">
{/* Logo/Header */}
<div className="text-center mb-8">
<div className="inline-flex items-center justify-center w-16 h-16 bg-gradient-to-r from-purple-600 to-blue-600 rounded-xl mb-4 animate-gradient">
<svg className="h-12 w-12 text-white" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="currentColor">
<title>GitHub</title>
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/>
</svg>
</div>
<h1 className="text-3xl font-bold bg-gradient-to-r from-purple-400 to-blue-400 bg-clip-text text-transparent">
GitHub MCP Tool Manager
</h1>
<p className="text-muted-foreground mt-2">Connect your GitHub token to access development tools</p>
</div>
{/* Token Input Form */}
<Card className="shadow-2xl border-border/50">
<CardContent className="pt-6">
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="github-token" className="text-sm font-medium">
GitHub Personal Access Token
</Label>
<div className="relative">
<Input
id="github-token"
type={showToken ? "text" : "password"}
placeholder="ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
value={token}
onChange={(e) => setToken(e.target.value)}
className="pr-10"
disabled={validateTokenMutation.isPending}
/>
<Button
type="button"
variant="ghost"
size="sm"
className="absolute right-0 top-0 h-full px-3 py-2 hover:bg-transparent"
onClick={() => setShowToken(!showToken)}
disabled={validateTokenMutation.isPending}
>
{showToken ? (
<EyeOff className="h-4 w-4 text-muted-foreground" />
) : (
<Eye className="h-4 w-4 text-muted-foreground" />
)}
</Button>
</div>
<p className="text-xs text-muted-foreground">
Your token is stored securely and only used for MCP connections
</p>
</div>
<Button
type="submit"
className="w-full bg-gradient-to-r from-purple-600 to-blue-600 hover:from-purple-700 hover:to-blue-700 transition-all duration-200 transform hover:scale-[1.02]"
disabled={validateTokenMutation.isPending}
>
{validateTokenMutation.isPending ? (
<>
<LoadingSpinner className="mr-2 h-4 w-4" />
Validating...
</>
) : (
<>
<Rocket className="mr-2 h-4 w-4" />
Connect & Continue
</>
)}
</Button>
</form>
<div className="mt-6 pt-6 border-t border-border">
<h3 className="text-sm font-medium mb-3">Need a GitHub token?</h3>
<div className="space-y-2 text-xs text-muted-foreground">
<p>1. Go to GitHub Settings → Developer settings → Personal access tokens</p>
<p>2. Generate a new token with required permissions</p>
<p>3. Copy and paste it above</p>
</div>
<a
href="https://github.com/settings/tokens"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center text-primary hover:text-primary/80 text-xs mt-2 transition-colors"
>
<Github className="mr-1 h-3 w-3" />
Create Token
<ExternalLink className="ml-1 h-3 w-3" />
</a>
</div>
</CardContent>
</Card>
</div>
</div>
);
}