devist 0.10.0

Project bootstrap CLI for AI-assisted development. Spin up new projects from templates, manage backends, and keep your codebase comprehensible.
import { Button } from "@/components/ui/button";
import { supabaseEnv } from "@/lib/supabase";
import { Check, Copy, Database } from "lucide-react";
import { useState } from "react";

const ENV_TEMPLATE = `VITE_SUPABASE_URL=http://127.0.0.1:54321
VITE_SUPABASE_ANON_KEY=your-anon-key-here`;

function CodeBlock({ code }: { code: string }) {
  const [copied, setCopied] = useState(false);

  const copy = async () => {
    await navigator.clipboard.writeText(code);
    setCopied(true);
    setTimeout(() => setCopied(false), 1500);
  };

  return (
    <div className="relative group">
      <pre className="bg-zinc-900 text-zinc-100 rounded-md p-4 text-xs overflow-x-auto font-mono">
        <code>{code}</code>
      </pre>
      <Button
        type="button"
        size="sm"
        variant="secondary"
        onClick={copy}
        className="absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition"
      >
        {copied ? <Check /> : <Copy />}
        {copied ? "Copied" : "Copy"}
      </Button>
    </div>
  );
}

function Step({
  n,
  title,
  children,
}: {
  n: number;
  title: string;
  children: React.ReactNode;
}) {
  return (
    <div className="flex gap-4">
      <div className="flex-shrink-0 w-8 h-8 rounded-full bg-primary text-primary-foreground flex items-center justify-center text-sm font-semibold">
        {n}
      </div>
      <div className="flex-1 space-y-2 pt-0.5">
        <h3 className="font-semibold text-base">{title}</h3>
        <div className="text-sm text-muted-foreground space-y-2">{children}</div>
      </div>
    </div>
  );
}

export default function SetupGuide() {
  const missing = [
    !supabaseEnv.url && "VITE_SUPABASE_URL",
    !supabaseEnv.anonKey && "VITE_SUPABASE_ANON_KEY",
  ].filter(Boolean) as string[];

  return (
    <div className="min-h-screen bg-background text-foreground">
      <div className="max-w-2xl mx-auto px-6 py-12 space-y-8">
        <header className="space-y-3">
          <div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-amber-100 text-amber-900 text-xs font-medium">
            <Database className="size-3.5" />
            Setup required
          </div>
          <h1 className="text-3xl font-bold tracking-tight">Supabase is not configured</h1>
          <p className="text-muted-foreground">
            Missing environment variables:{" "}
            {missing.map((m, i) => (
              <span key={m}>
                <code className="font-mono text-xs px-1.5 py-0.5 rounded bg-muted text-foreground">
                  {m}
                </code>
                {i < missing.length - 1 ? ", " : ""}
              </span>
            ))}
          </p>
        </header>

        <div className="space-y-8">
          <Step n={1} title="Start the local Supabase stack">
            <p>Make sure Docker is running, then start Supabase:</p>
            <CodeBlock code="supabase start" />
            <p>
              The first run downloads images and may take a minute. When it finishes, the URL and
              anon key are printed in the terminal.
            </p>
          </Step>

          <Step n={2} title="Create .env.local in the project root">
            <p>
              Copy the values from the <code className="font-mono">supabase start</code> output into
              a file named <code className="font-mono">.env.local</code>:
            </p>
            <CodeBlock code={ENV_TEMPLATE} />
          </Step>

          <Step n={3} title="Restart the dev server">
            <p>Vite reads env files at startup. Stop the dev server (Ctrl+C) and run it again:</p>
            <CodeBlock code="pnpm dev" />
          </Step>
        </div>

        <footer className="pt-6 border-t text-xs text-muted-foreground">
          Bootstrapped with devist ยท react-supabase template
        </footer>
      </div>
    </div>
  );
}