diff --git a/src/app/(gistLayout)/layout-ui.tsx b/src/app/(gistLayout)/layout-ui.tsx index 78819af..37d1fb2 100644 --- a/src/app/(gistLayout)/layout-ui.tsx +++ b/src/app/(gistLayout)/layout-ui.tsx @@ -186,9 +186,9 @@ function CreateGistModal({ title="New Gist" trigger={
- + - diff --git a/src/app/(gistLayout)/layout.tsx b/src/app/(gistLayout)/layout.tsx index 1833ae0..3a5da90 100644 --- a/src/app/(gistLayout)/layout.tsx +++ b/src/app/(gistLayout)/layout.tsx @@ -9,7 +9,7 @@ import { useCreateOrg } from "@/lib/queries/orgs.queries" import { useLogout } from "@/lib/queries/auth.queries" export default function GistLayoutFeature({ children }: { children: ReactNode }) { - const { data, error } = useMe() + const { data } = useMe() const { toast } = useToast() const { mutate: createGist } = useCreateGist({ onSuccess: () => { diff --git a/src/app/(gistLayout)/mygist/[gistId]/page-ui.tsx b/src/app/(gistLayout)/mygist/[gistId]/page-ui.tsx index c24fa4f..cffcb49 100644 --- a/src/app/(gistLayout)/mygist/[gistId]/page-ui.tsx +++ b/src/app/(gistLayout)/mygist/[gistId]/page-ui.tsx @@ -7,9 +7,19 @@ interface MyGistIdPageProps { onSave: (name: string, code: string) => void onDelete: (id: string) => void onShare: () => void + onCopy: (code: string) => void + onCopyCurl: () => void } -export default function MyGistIdPage({ gist, onDownload, onSave, onDelete, onShare }: MyGistIdPageProps) { +export default function MyGistIdPage({ + gist, + onDownload, + onSave, + onDelete, + onShare, + onCopy, + onCopyCurl, +}: MyGistIdPageProps) { return ( ) } diff --git a/src/app/(gistLayout)/mygist/[gistId]/page.tsx b/src/app/(gistLayout)/mygist/[gistId]/page.tsx index a404d84..e165ed0 100644 --- a/src/app/(gistLayout)/mygist/[gistId]/page.tsx +++ b/src/app/(gistLayout)/mygist/[gistId]/page.tsx @@ -3,7 +3,7 @@ import React from "react" import MyGistIdPage from "./page-ui" import { useGist, usePatchGistContent, usePatchGistName } from "@/lib/queries/gists.queries" import { useToast } from "@/components/shadcn/use-toast" -import { useKeyPress } from "@/lib/hook/use-key-press" +import { getRawGistURL } from "@/lib/utils" interface MyGistIdFeaturePageProps { params: { @@ -52,8 +52,42 @@ export default function MyGistIdFeaturePage({ params }: MyGistIdFeaturePageProps console.log("Share") } + const onCopy = (code: string) => { + navigator.clipboard + .writeText(code) + .then(() => { + console.log("Copy") + toast({ + title: "Gist Copied", + description: "Your gist has been copied successfully", + }) + }) + .catch((error) => { + console.error("Failed to copy text: ", error) + }) + } + + const onCopyCurl = () => { + const curlCommand = `curl ${getRawGistURL(gistId)} -o- | /bin/bash` + toast({ + title: "Gist Copied", + description: "Your curl command has been copied successfully", + }) + navigator.clipboard.writeText(curlCommand) + } + if (!data) { return null } - return + return ( + + ) } diff --git a/src/app/(gistLayout)/org/[orgId]/gist/[gistId]/page-ui.tsx b/src/app/(gistLayout)/org/[orgId]/gist/[gistId]/page-ui.tsx index 2064803..3c0c156 100644 --- a/src/app/(gistLayout)/org/[orgId]/gist/[gistId]/page-ui.tsx +++ b/src/app/(gistLayout)/org/[orgId]/gist/[gistId]/page-ui.tsx @@ -8,6 +8,8 @@ interface MyOrgGistIdPageProps { onSave: () => void onDelete: (id: string) => void onShare: () => void + onCopy: (code: string) => void + onCopyCurl: () => void } export default function MyOrgGistIdPage({ @@ -16,6 +18,8 @@ export default function MyOrgGistIdPage({ onDownload, onSave, onDelete, + onCopy, + onCopyCurl, onShare, }: MyOrgGistIdPageProps) { return ( @@ -26,6 +30,8 @@ export default function MyOrgGistIdPage({ onSave={onSave} onDelete={onDelete} onShare={onShare} + onCopy={onCopy} + onCopyCurl={onCopyCurl} /> ) } diff --git a/src/app/(gistLayout)/org/[orgId]/gist/[gistId]/page.tsx b/src/app/(gistLayout)/org/[orgId]/gist/[gistId]/page.tsx index 8081401..4ac7d00 100644 --- a/src/app/(gistLayout)/org/[orgId]/gist/[gistId]/page.tsx +++ b/src/app/(gistLayout)/org/[orgId]/gist/[gistId]/page.tsx @@ -3,6 +3,7 @@ import { useToast } from "@/components/shadcn/use-toast" import GistDetails from "@/components/ui/gist-details" import { useGist, usePatchGistContent, usePatchGistName } from "@/lib/queries/gists.queries" import { useOrg } from "@/lib/queries/orgs.queries" +import { getRawGistURL } from "@/lib/utils" import React from "react" interface MyOrgGistIdFeaturePageProps { @@ -48,10 +49,42 @@ export default function MyOrgGistIdFeaturePage({ params }: MyOrgGistIdFeaturePag const onShare = () => { console.log("Share") + toast({ + title: "Gist Shared", + description: "Your gist has been shared successfully", + }) } const onDelete = (id: string) => { console.log(`Deleting gist with ID: ${id}`) + toast({ + title: "Gist Deleted", + description: "Your gist has been deleted successfully", + }) + } + + const onCopy = (code: string) => { + navigator.clipboard + .writeText(code) + .then(() => { + console.log("Copy") + toast({ + title: "Gist Copied", + description: "Your gist has been copied successfully", + }) + }) + .catch((error) => { + console.error("Failed to copy text: ", error) + }) + } + + const onCopyCurl = () => { + const curlCommand = `curl ${getRawGistURL(gistId)} -o- | /bin/bash` + toast({ + title: "Gist Copied", + description: "Your curl command has been copied successfully", + }) + navigator.clipboard.writeText(curlCommand) } if (!gistData) { @@ -66,6 +99,8 @@ export default function MyOrgGistIdFeaturePage({ params }: MyOrgGistIdFeaturePag onSave={onSave} onShare={onShare} onDelete={onDelete} + onCopy={onCopy} + onCopyCurl={onCopyCurl} /> ) } diff --git a/src/app/login/page-ui.tsx b/src/app/login/page-ui.tsx index bc9860b..e9add02 100644 --- a/src/app/login/page-ui.tsx +++ b/src/app/login/page-ui.tsx @@ -5,7 +5,6 @@ import { Input } from "@/components/shadcn/input" import { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } from "@/components/shadcn/input-otp" import { UseFormRegisterReturn } from "react-hook-form" import { Icon } from "@iconify/react" -import { useKeyPress } from "@/lib/hook/use-key-press" interface LoginProps { step: "initial" | "emailInput" | "otpInput" diff --git a/src/components/api/api-provider.tsx b/src/components/api/api-provider.tsx index f11e85b..3499f05 100644 --- a/src/components/api/api-provider.tsx +++ b/src/components/api/api-provider.tsx @@ -1,8 +1,7 @@ "use client" import getQueryClient from "@/lib/queries/queries" -import { QueryClient, QueryClientProvider } from "@tanstack/react-query" -import { useState } from "react" +import { QueryClientProvider } from "@tanstack/react-query" export default function QueryProvider({ children }: { children: React.ReactNode }) { return {children} diff --git a/src/components/logic/gists-landing-logic.tsx b/src/components/logic/gists-landing-logic.tsx index 10763cb..0d2e256 100644 --- a/src/components/logic/gists-landing-logic.tsx +++ b/src/components/logic/gists-landing-logic.tsx @@ -1,6 +1,6 @@ "use client" -import { useState, useEffect, useCallback, useRef } from "react" +import { useState, useEffect, useCallback } from "react" import { Gist } from "@/types" import GistLanding from "@/components/ui/gist-landing" import { toast } from "../shadcn/use-toast" @@ -26,7 +26,6 @@ export default function GistsLandingLogic() { name: "Welcome to Gists.app", code: "", }) - const fileInputRef = useRef(null) const [isShareDialogOpen, setIsShareDialogOpen] = useState(false) useEffect(() => { diff --git a/src/components/shadcn/button.tsx b/src/components/shadcn/button.tsx index 385a217..a3739b6 100644 --- a/src/components/shadcn/button.tsx +++ b/src/components/shadcn/button.tsx @@ -9,16 +9,17 @@ const buttonVariants = cva( { variants: { variant: { - default: "bg-primary text-primary-foreground hover:bg-primary/90", - destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", - outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground", - secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", - ghost: "hover:bg-light-background hover:text-foreground", - disabled: "hover:bg-light-background hover:text-foreground opacity-50 cursor-not-allowed", - link: "text-primary text-base underline-offset-4 hover:underline", - icon: "text-foreground bg-icon hover:bg-icon/80", - menu: "text-primary-foreground hover:bg-primary hover:text-primary-foreground", - header: "hover:bg-primary hover:text-foreground", + default: "bg-primary text-primary-foreground hover:bg-primary/90 tranition-all", + destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90 tranition-all", + outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground tranition-all", + secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 tranition-all", + ghost: "hover:bg-light-background hover:text-foreground tranition-all", + disabled: "hover:bg-light-background hover:text-foreground opacity-50 cursor-not-allowed tranition-all", + link: "text-primary text-base underline-offset-4 hover:underline tranition-all", + icon: "text-foreground bg-icon hover:bg-icon/80 tranition-all", + "icon-ghost": "hover:bg-icon hover:text-foreground tranition-all", + menu: "text-primary-foreground hover:bg-primary hover:text-primary-foreground tranition-all", + header: "hover:bg-primary hover:text-foreground tranition-all", }, size: { default: "h-10 px-6 py-3", diff --git a/src/components/ui/gist-details.tsx b/src/components/ui/gist-details.tsx index e7370ce..f4d873b 100644 --- a/src/components/ui/gist-details.tsx +++ b/src/components/ui/gist-details.tsx @@ -2,14 +2,23 @@ import { Badge } from "@/components/shadcn/badge" import { Input } from "@/components/shadcn/input" import MenuButton from "@/components/ui/menu-button" import { Gist } from "@/types" -import { ChevronRightIcon, DownloadIcon, ExternalLinkIcon, ShareIcon, Trash2Icon } from "lucide-react" +import { + ChevronRightIcon, + CopyIcon, + DownloadIcon, + ExternalLinkIcon, + ShareIcon, + SquareCodeIcon, + Trash2Icon, +} from "lucide-react" import Link from "next/link" import { useState } from "react" import { Codearea } from "../shadcn/codearea" import { getLanguage } from "@/lib/language" import TooltipShortcut, { TooltipShortcutTrigger } from "./tooltip-shortcut" -import { getBackendURL } from "@/lib/utils" +import { getBackendURL, getRawGistURL } from "@/lib/utils" import { SidebarTrigger } from "../shadcn/sidebar" +import { Button } from "../shadcn/button" interface GistDetailsProps { gist: Gist @@ -18,6 +27,8 @@ interface GistDetailsProps { onDownload: (name: string, code: string) => void onShare: () => void onDelete: (id: string) => void + onCopy: (code: string) => void + onCopyCurl: () => void onSave: (name: string, code: string) => void } @@ -28,6 +39,8 @@ export default function GistDetails({ onDownload, onShare, onDelete, + onCopy, + onCopyCurl, onSave, }: GistDetailsProps) { const [gistId] = useState(gist.id) @@ -43,12 +56,7 @@ export default function GistDetails({ const onOpenPlainText = (gistID: string) => { // if production go to https://raw.gists.app/{gistID} console.log(process.env.NODE_ENV) - if (process.env.NODE_ENV === "production") { - const raw_url = getBackendURL().replace("api", "raw") + "/" + gistID - window.open(raw_url, "_blank") - return - } - window.open(getBackendURL() + "/gists/raw/" + gistID, "_blank") + window.open(getRawGistURL(gistID), "_blank") } return ( @@ -59,6 +67,8 @@ export default function GistDetails({ redirect={redirect} onDownload={() => onDownload(gistName, gistCode)} onOpenPlainText={onOpenPlainText} + onCopy={onCopy} + onCopyCurl={onCopyCurl} />
@@ -123,10 +133,12 @@ interface HeaderProps { orgName: string redirect?: boolean onDownload: (name: string, code: string) => void + onCopy: (code: string) => void + onCopyCurl: () => void onOpenPlainText?: (gistID: string) => void } -function Header({ gist, orgName, redirect, onDownload, onOpenPlainText }: HeaderProps) { +function Header({ gist, orgName, redirect, onDownload, onCopy, onCopyCurl, onOpenPlainText }: HeaderProps) { return (
@@ -145,31 +157,55 @@ function Header({ gist, orgName, redirect, onDownload, onOpenPlainText }: Header
-
+
+ + + + + + + + + + {onOpenPlainText && ( - + - onOpenPlainText(gist.id)} - icon={} - variant={"header"} > - Raw - + + )} - + - onDownload(gist.name, gist.code)} - icon={} - variant={"header"} > - Download - + +
diff --git a/src/components/ui/menu-button.tsx b/src/components/ui/menu-button.tsx index 291c0ec..3aeb02a 100644 --- a/src/components/ui/menu-button.tsx +++ b/src/components/ui/menu-button.tsx @@ -26,7 +26,7 @@ const MenuButton = React.forwardRef(
{icon && React.cloneElement(icon, { - className: "h-4 w-4 text-slate-500 group-hover:text-primary-foreground", + className: "h-4 w-4 text-slate-500 group-hover:text-primary-foreground tranition-all", })} {children}
diff --git a/src/lib/queries/auth.queries.tsx b/src/lib/queries/auth.queries.tsx index 5b4177e..7934eb3 100644 --- a/src/lib/queries/auth.queries.tsx +++ b/src/lib/queries/auth.queries.tsx @@ -2,7 +2,6 @@ import ky from "ky" import { getBackendURL } from "../utils" import { useMutation, useQueryClient } from "@tanstack/react-query" -import getQueryClient from "./queries" const fetchLocalAuth = async ({ email }: { email: string }) => { const json = await ky diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 9e95e94..2da1e49 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -8,3 +8,11 @@ export function cn(...inputs: ClassValue[]) { export function getBackendURL() { return process.env.NEXT_PUBLIC_BACKEND_URL || "https://api.gists.app" } + +export function getRawGistURL(id: string) { + if (process.env.NODE_ENV === "production") { + const raw_url = getBackendURL().replace("api", "raw") + "/" + id + return raw_url + } + return getBackendURL() + "/gists/raw/" + id +}