Create Publish panel to easy GitHub and Vercel push (#655)

This commit is contained in:
Will Chen
2025-07-17 15:54:08 -07:00
committed by GitHub
parent cb60a0562b
commit 444397ea86
26 changed files with 2113 additions and 28 deletions

View File

@@ -10,6 +10,7 @@ import {
Trash2,
AlertTriangle,
Wrench,
Globe,
} from "lucide-react";
import { motion } from "framer-motion";
import { useEffect, useRef, useState, useCallback } from "react";
@@ -32,7 +33,12 @@ import { useMutation } from "@tanstack/react-query";
import { useCheckProblems } from "@/hooks/useCheckProblems";
import { isPreviewOpenAtom } from "@/atoms/viewAtoms";
export type PreviewMode = "preview" | "code" | "problems" | "configure";
export type PreviewMode =
| "preview"
| "code"
| "problems"
| "configure"
| "publish";
const BUTTON_CLASS_NAME =
"no-app-region-drag cursor-pointer relative flex items-center gap-1 px-2 py-1 rounded-md text-[13px] font-medium z-10 hover:bg-[var(--background)]";
@@ -46,12 +52,13 @@ export const PreviewHeader = () => {
const codeRef = useRef<HTMLButtonElement>(null);
const problemsRef = useRef<HTMLButtonElement>(null);
const configureRef = useRef<HTMLButtonElement>(null);
const publishRef = useRef<HTMLButtonElement>(null);
const [indicatorStyle, setIndicatorStyle] = useState({ left: 0, width: 0 });
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
const { problemReport } = useCheckProblems(selectedAppId);
const { restartApp, refreshAppIframe } = useRunApp();
const isCompact = windowWidth < 840;
const isCompact = windowWidth < 860;
// Track window width
useEffect(() => {
@@ -128,6 +135,9 @@ export const PreviewHeader = () => {
case "configure":
targetRef = configureRef;
break;
case "publish":
targetRef = publishRef;
break;
default:
return;
}
@@ -239,6 +249,13 @@ export const PreviewHeader = () => {
"Configure",
"configure-mode-button",
)}
{renderButton(
"publish",
publishRef,
<Globe size={14} />,
"Publish",
"publish-mode-button",
)}
</div>
<div className="flex items-center">
<DropdownMenu>

View File

@@ -15,6 +15,7 @@ import { useEffect, useRef, useState } from "react";
import { PanelGroup, Panel, PanelResizeHandle } from "react-resizable-panels";
import { Console } from "./Console";
import { useRunApp } from "@/hooks/useRunApp";
import { PublishPanel } from "./PublishPanel";
interface ConsoleHeaderProps {
isOpen: boolean;
@@ -116,6 +117,8 @@ export function PreviewPanel() {
<CodeView loading={loading} app={app} />
) : previewMode === "configure" ? (
<ConfigurePanel />
) : previewMode === "publish" ? (
<PublishPanel />
) : (
<Problems />
)}

View File

@@ -0,0 +1,169 @@
import { useAtomValue } from "jotai";
import { selectedAppIdAtom } from "@/atoms/appAtoms";
import { useLoadApp } from "@/hooks/useLoadApp";
import { GitHubConnector } from "@/components/GitHubConnector";
import { VercelConnector } from "@/components/VercelConnector";
import { IpcClient } from "@/ipc/ipc_client";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
export const PublishPanel = () => {
const selectedAppId = useAtomValue(selectedAppIdAtom);
const { app, loading } = useLoadApp(selectedAppId);
if (loading) {
return (
<div className="flex flex-col items-center justify-center h-full p-8 text-center">
<div className="w-12 h-12 rounded-full bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center">
<svg
className="w-6 h-6 text-blue-600 dark:text-blue-400 animate-spin"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
/>
<path
className="opacity-75"
fill="currentColor"
d="m4 12a8 8 0 0 1 8-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 0 1 4 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
/>
</svg>
</div>
<h2 className="text-xl font-semibold text-gray-900 dark:text-gray-100">
Loading...
</h2>
</div>
);
}
if (!selectedAppId || !app) {
return (
<div className="flex flex-col items-center justify-center h-full p-8 text-center">
<div className="w-12 h-12 rounded-full bg-gray-100 dark:bg-gray-900/30 flex items-center justify-center">
<svg
className="w-6 h-6 text-gray-600 dark:text-gray-400"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"
/>
</svg>
</div>
<h2 className="text-xl font-semibold text-gray-900 dark:text-gray-100">
No App Selected
</h2>
<p className="text-gray-600 dark:text-gray-400 max-w-md">
Select an app to view publishing options.
</p>
</div>
);
}
return (
<div className="flex flex-col h-full overflow-y-auto">
<div className="p-4 space-y-4">
<div>
<h1 className="text-2xl font-bold text-gray-900 dark:text-gray-100 mb-2">
Publish App
</h1>
</div>
{/* GitHub Section */}
<Card>
<CardHeader className="pb-3">
<CardTitle className="flex items-center gap-2">
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path
fillRule="evenodd"
d="M10 0C4.477 0 0 4.484 0 10.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0110 4.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.203 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.942.359.31.678.921.678 1.856 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0020 10.017C20 4.484 15.522 0 10 0z"
clipRule="evenodd"
/>
</svg>
GitHub
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<p className="text-sm text-gray-600 dark:text-gray-400">
Sync your code to GitHub for collaboration.
</p>
<GitHubConnector
appId={selectedAppId}
folderName={app.name}
expanded={true}
/>
</CardContent>
</Card>
{/* Vercel Section */}
<Card>
<CardHeader className="pb-3">
<CardTitle className="flex items-center gap-2">
<button
onClick={() => {
const ipcClient = IpcClient.getInstance();
ipcClient.openExternalUrl("https://vercel.com/dashboard");
}}
className="flex items-center gap-2 hover:text-blue-600 dark:hover:text-blue-400 transition-colors cursor-pointer bg-transparent border-none p-0"
>
<svg
className="w-5 h-5"
fill="currentColor"
viewBox="0 0 24 24"
>
<path d="M24 22.525H0l12-21.05 12 21.05z" />
</svg>
Vercel
</button>
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<p className="text-sm text-gray-600 dark:text-gray-400">
Publish your app by deploying it to Vercel.
</p>
{!app?.githubOrg || !app?.githubRepo ? (
<div className="bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-lg p-4">
<div className="flex items-start gap-3">
<svg
className="w-5 h-5 text-amber-600 dark:text-amber-400 mt-0.5 flex-shrink-0"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
/>
</svg>
<div>
<h3 className="text-sm font-medium text-amber-800 dark:text-amber-200">
GitHub Required for Vercel Deployment
</h3>
<p className="text-sm text-amber-700 dark:text-amber-300 mt-1">
Deploying to Vercel requires connecting to GitHub first.
Please set up your GitHub repository above.
</p>
</div>
</div>
</div>
) : (
<VercelConnector appId={selectedAppId} folderName={app.name} />
)}
</CardContent>
</Card>
</div>
</div>
);
};