mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
fix(web): improve builder logic (#560)
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { Check, Copy, Share2, Twitter } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { Check, Copy, Terminal, Twitter } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import { useTheme } from "next-themes";
|
||||
import QRCode from "qrcode";
|
||||
import { useEffect, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -12,7 +14,6 @@ import {
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { QRCode } from "@/components/ui/kibo-ui/qr-code";
|
||||
import { TechBadge } from "@/components/ui/tech-badge";
|
||||
import type { StackState } from "@/lib/constant";
|
||||
import { TECH_OPTIONS } from "@/lib/constant";
|
||||
@@ -31,6 +32,8 @@ export function ShareDialog({
|
||||
stackState,
|
||||
}: ShareDialogProps) {
|
||||
const [copied, setCopied] = useState(false);
|
||||
const [qrCodeDataUrl, setQrCodeDataUrl] = useState<string>("");
|
||||
const { resolvedTheme } = useTheme();
|
||||
|
||||
const techBadges = (() => {
|
||||
const badges: React.ReactNode[] = [];
|
||||
@@ -111,74 +114,173 @@ export function ShareDialog({
|
||||
);
|
||||
};
|
||||
|
||||
// Generate QR code using local qrcode library
|
||||
useEffect(() => {
|
||||
const generateQRCode = async () => {
|
||||
try {
|
||||
const isDark = resolvedTheme === "dark";
|
||||
const dataUrl = await QRCode.toDataURL(stackUrl, {
|
||||
width: 128,
|
||||
margin: 2,
|
||||
color: {
|
||||
dark: isDark ? "#cdd6f4" : "#11111b",
|
||||
light: isDark ? "#11111b" : "#ffffff",
|
||||
},
|
||||
});
|
||||
setQrCodeDataUrl(dataUrl);
|
||||
} catch (error) {
|
||||
console.error("Failed to generate QR code:", error);
|
||||
setQrCodeDataUrl("");
|
||||
}
|
||||
};
|
||||
|
||||
if (stackUrl) {
|
||||
generateQRCode();
|
||||
}
|
||||
}, [stackUrl, resolvedTheme]);
|
||||
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>{children}</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
<Share2 className="h-5 w-5" />
|
||||
Share Your Stack
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
Share your custom tech stack configuration with others
|
||||
<DialogContent className="grid grid-cols-1 bg-fd-background sm:max-w-md">
|
||||
<DialogHeader className="border-border border-b pb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Terminal className="h-4 w-4 text-primary" />
|
||||
<DialogTitle className="font-mono font-semibold text-foreground text-sm">
|
||||
SHARE_STACK.SH
|
||||
</DialogTitle>
|
||||
</div>
|
||||
<DialogDescription className="font-mono text-muted-foreground text-xs">
|
||||
$ ./share_configuration --export
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-3">
|
||||
<div className="font-medium text-foreground text-sm">
|
||||
Technologies
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-1.5 rounded border border-border bg-muted/20 p-3">
|
||||
{techBadges.length > 0 ? (
|
||||
techBadges
|
||||
) : (
|
||||
<span className="text-muted-foreground text-sm">
|
||||
No technologies selected
|
||||
<div className="rounded border border-border">
|
||||
<div className="border-border border-b px-3 py-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-primary text-xs">▶</span>
|
||||
<span className="font-mono font-semibold text-foreground text-xs">
|
||||
DEPENDENCIES.LIST
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="font-medium text-foreground text-sm">QR Code</div>
|
||||
<div className="flex items-center justify-center rounded border border-border bg-muted/20 p-4">
|
||||
<div className="h-32 w-32">
|
||||
<QRCode data={stackUrl} />
|
||||
<div className="ml-auto flex items-center gap-2 text-muted-foreground text-xs">
|
||||
<span>•</span>
|
||||
<span>{techBadges.length} PACKAGES</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3">
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{techBadges.length > 0 ? (
|
||||
techBadges
|
||||
) : (
|
||||
<div className="flex items-center gap-2 text-muted-foreground text-sm">
|
||||
<span className="text-primary">$</span>
|
||||
<span>No technologies selected</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-center text-muted-foreground text-xs">
|
||||
Scan to view this tech stack
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="font-medium text-foreground text-sm">Share</div>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={shareToTwitter}
|
||||
className="flex-1"
|
||||
>
|
||||
<Twitter className="h-4 w-4" />X (Twitter)
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={copyToClipboard}
|
||||
className={cn(
|
||||
"flex-1",
|
||||
copied &&
|
||||
"border-green-500/20 bg-green-500/10 text-green-600 dark:text-green-400",
|
||||
)}
|
||||
>
|
||||
{copied ? (
|
||||
<Check className="h-4 w-4" />
|
||||
) : (
|
||||
<Copy className="h-4 w-4" />
|
||||
)}
|
||||
{copied ? "Copied!" : "Copy URL"}
|
||||
</Button>
|
||||
<div className="rounded border border-border">
|
||||
<div className="border-border border-b px-3 py-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-primary text-xs">▶</span>
|
||||
<span className="font-mono font-semibold text-foreground text-xs">
|
||||
QR_CODE.PNG
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-4">
|
||||
<div className="flex items-center justify-center rounded border border-border bg-muted/20 p-4">
|
||||
<div className="flex h-32 w-32 items-center justify-center">
|
||||
{qrCodeDataUrl ? (
|
||||
<Image
|
||||
src={qrCodeDataUrl}
|
||||
width={128}
|
||||
height={128}
|
||||
alt="QR Code for stack configuration"
|
||||
className="h-full w-full object-contain"
|
||||
/>
|
||||
) : (
|
||||
<div className="flex flex-col items-center gap-2 text-muted-foreground text-xs">
|
||||
<span className="text-primary">$</span>
|
||||
<span>Generating QR code...</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-2 flex items-center justify-center gap-2 text-muted-foreground text-xs">
|
||||
<span className="text-primary">$</span>
|
||||
<span>scan --url stack_config</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded border border-border">
|
||||
<div className="border-border border-b px-3 py-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-primary text-xs">▶</span>
|
||||
<span className="font-mono font-semibold text-foreground text-xs">
|
||||
EXPORT_ACTIONS.SH
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3">
|
||||
<div className="grid gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={shareToTwitter}
|
||||
className="flex items-center gap-2 rounded border border-border bg-fd-background px-3 py-2 font-mono text-muted-foreground text-xs transition-all hover:border-muted-foreground/30 hover:bg-muted hover:text-foreground"
|
||||
>
|
||||
<Twitter className="h-3 w-3" />
|
||||
<span className="text-primary">$</span>
|
||||
<span>./share --platform twitter</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={copyToClipboard}
|
||||
className={cn(
|
||||
"flex items-center gap-2 rounded border px-3 py-2 font-mono text-xs transition-all",
|
||||
copied
|
||||
? "border-green-500/20 bg-green-500/10 text-green-600 dark:text-green-400"
|
||||
: "border-border bg-fd-background text-muted-foreground hover:border-muted-foreground/30 hover:bg-muted hover:text-foreground",
|
||||
)}
|
||||
>
|
||||
{copied ? (
|
||||
<Check className="h-3 w-3" />
|
||||
) : (
|
||||
<Copy className="h-3 w-3" />
|
||||
)}
|
||||
<span className="text-primary">$</span>
|
||||
<span>
|
||||
{copied
|
||||
? "./copy --status success"
|
||||
: "./copy --url clipboard"}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded border border-border">
|
||||
<div className="border-border border-b px-3 py-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-primary text-xs">▶</span>
|
||||
<span className="font-mono font-semibold text-foreground text-xs">
|
||||
OUTPUT.URL
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3">
|
||||
<div className="flex items-center gap-2 text-xs">
|
||||
<span className="text-primary">$</span>
|
||||
<code className="flex-1 truncate text-muted-foreground">
|
||||
{stackUrl}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user