Added create site page
This commit is contained in:
@@ -0,0 +1,283 @@
|
||||
import { useState } from 'react';
|
||||
import Page from '../Page';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Plus, Zap } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useCreateSite } from '../../hooks/api/useCreateSite';
|
||||
|
||||
const GIT_SERVERS = [
|
||||
{
|
||||
value: 'github',
|
||||
label: 'GitHub',
|
||||
icon: (
|
||||
<svg viewBox="0 0 24 24" className="w-6 h-6 fill-current">
|
||||
<path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
value: 'gitlab',
|
||||
label: 'GitLab',
|
||||
icon: (
|
||||
<svg viewBox="0 0 24 24" className="w-6 h-6 fill-current">
|
||||
<path d="M23.955 13.587l-1.342-4.135-2.664-8.189a.455.455 0 00-.867 0L16.418 9.45H7.582L4.918 1.263a.455.455 0 00-.867 0L1.387 9.452.045 13.587a.924.924 0 00.331 1.023L12 23.054l11.624-8.443a.92.92 0 00.331-1.024" />
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const parseRepoUrl = (url: string) => {
|
||||
const cleaned = url
|
||||
.trim()
|
||||
.replace(/\.git$/, '')
|
||||
.replace(/\/$/, '');
|
||||
|
||||
const patterns = [
|
||||
/^https?:\/\/(github\.com|gitlab\.com)\/([^/]+)\/([^/]+)/,
|
||||
/^git@(github\.com|gitlab\.com):([^/]+)\/([^/]+)/,
|
||||
];
|
||||
|
||||
for (const pattern of patterns) {
|
||||
const match = cleaned.match(pattern);
|
||||
if (match) {
|
||||
const host = match[1];
|
||||
const server = host === 'github.com' ? 'github' : 'gitlab';
|
||||
return { gitServer: server, owner: match[2], repository: match[3] };
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const NewSite = () => {
|
||||
const [name, setName] = useState('');
|
||||
const [repoUrl, setRepoUrl] = useState('');
|
||||
const [gitServer, setGitServer] = useState('');
|
||||
const [owner, setOwner] = useState('');
|
||||
const [repository, setRepository] = useState('');
|
||||
const [branch, setBranch] = useState('');
|
||||
const [domain, setDomain] = useState('');
|
||||
const [spa, setSpa] = useState(false);
|
||||
const [urlError, setUrlError] = useState('');
|
||||
const createNewSite = useCreateSite();
|
||||
|
||||
const handleQuickImport = () => {
|
||||
if (!repoUrl.trim()) return;
|
||||
|
||||
const parsed = parseRepoUrl(repoUrl);
|
||||
if (parsed) {
|
||||
setGitServer(parsed.gitServer);
|
||||
setOwner(parsed.owner);
|
||||
setRepository(parsed.repository);
|
||||
setUrlError('');
|
||||
} else {
|
||||
setUrlError(
|
||||
'Could not parse URL. Supported formats: https://github.com/owner/repo or git@github.com:owner/repo'
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
handleQuickImport();
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
console.log({ name, gitServer, owner, repository, branch, domain, spa });
|
||||
const data = await createNewSite.mutateAsync({
|
||||
name,
|
||||
git_server: gitServer,
|
||||
owner,
|
||||
repository,
|
||||
branch,
|
||||
domain,
|
||||
spa,
|
||||
enabled: true,
|
||||
});
|
||||
console.log('Created site:', data);
|
||||
};
|
||||
|
||||
const isValid = name && gitServer && owner && repository && branch && domain;
|
||||
|
||||
return (
|
||||
<Page title="New Site">
|
||||
<div className="">
|
||||
<h1 className="text-2xl font-semibold mb-1">New Site</h1>
|
||||
<p className="text-muted-foreground mb-6">
|
||||
Deploy a static site from a Git repository.
|
||||
</p>
|
||||
|
||||
<Card className="mb-6 bg-muted/70">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Zap className="w-4 h-4" />
|
||||
Quick Import
|
||||
</div>
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Paste a GitHub or GitLab repository URL to auto-fill the fields below.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
placeholder="https://github.com/owner/repository"
|
||||
value={repoUrl}
|
||||
onChange={(e) => {
|
||||
setRepoUrl(e.target.value);
|
||||
setUrlError('');
|
||||
}}
|
||||
onKeyDown={handleKeyDown}
|
||||
className="flex-1"
|
||||
/>
|
||||
<Button variant="outline" onClick={handleQuickImport}>
|
||||
Import
|
||||
</Button>
|
||||
</div>
|
||||
{urlError && <p className="text-sm text-destructive mt-2">{urlError}</p>}
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Separator className="mb-6" />
|
||||
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="name">Site Name</Label>
|
||||
<Input
|
||||
id="name"
|
||||
placeholder="My awesome site"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
/>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
A display name for your site. This can be changed later and is not part
|
||||
of the URL.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<h2 className="text-lg font-medium">Repository</h2>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label>Git Server</Label>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
{GIT_SERVERS.map((server) => (
|
||||
<button
|
||||
key={server.value}
|
||||
type="button"
|
||||
onClick={() => setGitServer(server.value)}
|
||||
className={cn(
|
||||
'flex items-center gap-3 rounded-lg border-2 p-4 text-left transition-colors',
|
||||
'hover:bg-accent/15',
|
||||
gitServer === server.value
|
||||
? 'border-primary bg-primary/5'
|
||||
: 'border-border hover:border-accent/35'
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'shrink-0',
|
||||
gitServer === server.value
|
||||
? 'text-primary'
|
||||
: 'text-muted-foreground'
|
||||
)}
|
||||
>
|
||||
{server.icon}
|
||||
</div>
|
||||
<span className="font-medium">{server.label}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="owner">Owner</Label>
|
||||
<Input
|
||||
id="owner"
|
||||
placeholder="owner"
|
||||
value={owner}
|
||||
onChange={(e) => setOwner(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="repository">Repository</Label>
|
||||
<Input
|
||||
id="repository"
|
||||
placeholder="repository"
|
||||
value={repository}
|
||||
onChange={(e) => setRepository(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="branch">Branch</Label>
|
||||
<Input
|
||||
id="branch"
|
||||
placeholder="gh-pages"
|
||||
value={branch}
|
||||
onChange={(e) => setBranch(e.target.value)}
|
||||
/>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Assets from this branch will be deployed. Make sure it exists before
|
||||
creating the site.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<h2 className="text-lg font-medium">Configuration</h2>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="domain">Custom Domain</Label>
|
||||
<Input
|
||||
id="domain"
|
||||
placeholder="example.com"
|
||||
value={domain}
|
||||
onChange={(e) => setDomain(e.target.value)}
|
||||
/>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
The domain you want to use for this site.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between rounded-lg border p-4">
|
||||
<div className="space-y-0.5">
|
||||
<Label htmlFor="spa">Single Page Application (SPA)</Label>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Redirect all paths to index.html for client-side routing.
|
||||
</p>
|
||||
</div>
|
||||
<Switch id="spa" checked={spa} onCheckedChange={setSpa} />
|
||||
</div>
|
||||
|
||||
<div className="flex gap-3 pt-2">
|
||||
<Button
|
||||
onClick={handleSubmit}
|
||||
disabled={!isValid}
|
||||
title={!isValid ? 'Please fill in all fields' : ''}
|
||||
>
|
||||
<Plus />
|
||||
Create Site
|
||||
</Button>
|
||||
<Button variant="outline" onClick={() => window.history.back()}>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewSite;
|
||||
Reference in New Issue
Block a user