import React, { useState, useEffect, useCallback } from "react"; import { Plus, Share, DownloadSimple, Gear, X, GithubLogo, SignOut, ArrowSquareOut, CloudArrowUp, CaretDown, User, FilePlus, } from "phosphor-react"; import Image from "next/image"; import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuArrow, DropdownMenuSeparator, } from "./DropdownMenu"; import NewWindow from "react-new-window"; import { signOut, useSession } from "next-auth/react"; import { useSnapshot } from "valtio"; import toast from "react-hot-toast"; import { createNewFile, syncToGist, updateEditorSettings, downloadAsZip, } from "../state/actions"; import state from "../state"; import Box from "./Box"; import Button from "./Button"; import Container from "./Container"; import { Dialog, DialogTrigger, DialogContent, DialogTitle, DialogDescription, DialogClose, } from "./Dialog"; import Flex from "./Flex"; import Stack from "./Stack"; import { Input, Label } from "./Input"; import Text from "./Text"; import Tooltip from "./Tooltip"; import { styled } from "../stitches.config"; import { showAlert } from "../state/actions/showAlert"; const ErrorText = styled(Text, { color: "$error", mt: "$1", display: "block", }); const EditorNavigation = ({ showWat }: { showWat?: boolean }) => { const snap = useSnapshot(state); const [editorSettingsOpen, setEditorSettingsOpen] = useState(false); const [isNewfileDialogOpen, setIsNewfileDialogOpen] = useState(false); const [newfileError, setNewfileError] = useState(null); const [filename, setFilename] = useState(""); const { data: session, status } = useSession(); const [popup, setPopUp] = useState(false); const [editorSettings, setEditorSettings] = useState(snap.editorSettings); useEffect(() => { if (session && session.user && popup) { setPopUp(false); } }, [session, popup]); // when filename changes, reset error useEffect(() => { setNewfileError(null); }, [filename, setNewfileError]); const showNewGistAlert = () => { showAlert("Are you sure?", { body: ( <> This action will create new public Github Gist from your current saved files. You can delete gist anytime from your GitHub Gists page. ), cancelText: "Cancel", confirmText: "Create new Gist", confirmPrefix: , onConfirm: () => syncToGist(session, true), }); }; const validateFilename = useCallback( (filename: string): { error: string | null } => { // check if filename already exists if (!filename) { return { error: "You need to add filename" }; } if (snap.files.find(file => file.name === filename)) { return { error: "Filename already exists." }; } if (!filename.includes(".") || filename[filename.length - 1] === ".") { return { error: "Filename should include file extension" }; } // check for illegal characters const ALPHA_NUMERICAL_REGEX = /^[A-Za-z0-9_-]+[.][A-Za-z0-9]{1,4}$/g; if (!filename.match(ALPHA_NUMERICAL_REGEX)) { return { error: `Filename can contain only characters from a-z, A-Z, 0-9, "_" and "-" and it needs to have file extension (e.g. ".c")`, }; } return { error: null }; }, [snap.files] ); const handleConfirm = useCallback(() => { // add default extension in case omitted const chk = validateFilename(filename); if (chk && chk.error) { setNewfileError(`Error: ${chk.error}`); return; } setIsNewfileDialogOpen(false); createNewFile(filename); setFilename(""); }, [filename, setIsNewfileDialogOpen, setFilename, validateFilename]); const files = snap.files; return ( {files && files.length > 0 && files.map((file, index) => { if (!file.compiledContent && showWat) { return null; } return ( ); })} {!showWat && ( Create new file setFilename(e.target.value)} onKeyPress={e => { if (e.key === "Enter") { handleConfirm(); } }} /> {newfileError} )} {status === "authenticated" ? ( User avatar signOut()}> {session?.user?.username} ( {session?.user.name}) window.open( `http://gist.github.com/${session?.user.username}` ) } > Go to your Gist signOut({ callbackUrl: "/" })}> Log out ) : ( )} Download as ZIP { navigator.clipboard.writeText( `${window.location.origin}/develop/${snap.gistId}` ); toast.success("Copied share link to clipboard!"); }} > Copy share link to clipboard { syncToGist(session); }} > Push to Gist { showNewGistAlert(); }} > Create as a new Gist setEditorSettingsOpen(true)}> Editor Settings {popup && !session ? ( ) : null} {/* */} Editor settings setEditorSettings(curr => ({ ...curr, tabSize: Number(e.target.value), })) } /> ); }; export default EditorNavigation;