Files
xrpl-hooks-ide/components/EditorNavigation.tsx
2022-08-17 11:50:49 +05:30

380 lines
12 KiB
TypeScript

import React, { useState, useEffect, useRef, ReactNode } from 'react'
import {
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 { 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 Tooltip from './Tooltip'
import { showAlert } from '../state/actions/showAlert'
const EditorNavigation = ({ renderNav }: { renderNav?: () => ReactNode }) => {
const snap = useSnapshot(state)
const [editorSettingsOpen, setEditorSettingsOpen] = useState(false)
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])
const showNewGistAlert = () => {
showAlert('Are you sure?', {
body: (
<>
This action will create new <strong>public</strong> Github Gist from your current saved
files. You can delete gist anytime from your GitHub Gists page.
</>
),
cancelText: 'Cancel',
confirmText: 'Create new Gist',
confirmPrefix: <FilePlus size="15px" />,
onConfirm: () => syncToGist(session, true)
})
}
const scrollRef = useRef<HTMLDivElement>(null)
const containerRef = useRef<HTMLDivElement>(null)
return (
<Flex css={{ flexShrink: 0, gap: '$0' }}>
<Flex
id="kissa"
ref={scrollRef}
css={{
overflowX: 'scroll',
overflowY: 'hidden',
py: '$3',
pb: '$0',
flex: 1,
'&::-webkit-scrollbar': {
height: '0.3em',
background: 'rgba(0,0,0,.0)'
},
'&::-webkit-scrollbar-gutter': 'stable',
'&::-webkit-scrollbar-thumb': {
backgroundColor: 'rgba(0,0,0,.2)',
outline: '0px',
borderRadius: '9999px'
},
scrollbarColor: 'rgba(0,0,0,.2) rgba(0,0,0,0)',
scrollbarGutter: 'stable',
scrollbarWidth: 'thin',
'.dark &': {
'&::-webkit-scrollbar': {
background: 'rgba(0,0,0,.0)'
},
'&::-webkit-scrollbar-gutter': 'stable',
'&::-webkit-scrollbar-thumb': {
backgroundColor: 'rgba(255,255,255,.2)',
outline: '0px',
borderRadius: '9999px'
},
scrollbarColor: 'rgba(255,255,255,.2) rgba(0,0,0,0)',
scrollbarGutter: 'stable',
scrollbarWidth: 'thin'
}
}}
onWheelCapture={e => {
if (scrollRef.current) {
scrollRef.current.scrollLeft += e.deltaY
}
}}
>
<Container css={{ flex: 1 }} ref={containerRef}>
{renderNav?.()}
</Container>
</Flex>
<Flex
css={{
py: '$3',
backgroundColor: '$mauve2',
zIndex: 1
}}
>
<Container css={{ width: 'unset', display: 'flex', alignItems: 'center' }}>
{status === 'authenticated' ? (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Box
css={{
display: 'flex',
borderRadius: '$full',
overflow: 'hidden',
width: '$6',
height: '$6',
boxShadow: '0px 0px 0px 1px $colors$mauve11',
position: 'relative',
mr: '$3',
'@hover': {
'&:hover': {
cursor: 'pointer',
boxShadow: '0px 0px 0px 1px $colors$mauve12'
}
}
}}
>
<Image
src={session?.user?.image || ''}
width="30px"
height="30px"
objectFit="cover"
alt="User avatar"
/>
</Box>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem disabled onClick={() => signOut()}>
<User size="16px" /> {session?.user?.username} ({session?.user.name})
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => window.open(`http://gist.github.com/${session?.user.username}`)}
>
<ArrowSquareOut size="16px" />
Go to your Gist
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => signOut({ callbackUrl: '/' })}>
<SignOut size="16px" /> Log out
</DropdownMenuItem>
<DropdownMenuArrow offset={10} />
</DropdownMenuContent>
</DropdownMenu>
) : (
<Button outline size="sm" css={{ mr: '$3' }} onClick={() => setPopUp(true)}>
<GithubLogo size="16px" /> Login
</Button>
)}
<Stack
css={{
display: 'inline-flex',
marginLeft: 'auto',
flexShrink: 0,
gap: '$0',
borderRadius: '$sm',
boxShadow: 'inset 0px 0px 0px 1px $colors$mauve10',
zIndex: 9,
position: 'relative',
button: {
borderRadius: 0,
px: '$2',
alignSelf: 'flex-start',
boxShadow: 'none'
},
'button:not(:first-child):not(:last-child)': {
borderRight: 0,
borderLeft: 0
},
'button:first-child': {
borderTopLeftRadius: '$sm',
borderBottomLeftRadius: '$sm'
},
'button:last-child': {
borderTopRightRadius: '$sm',
borderBottomRightRadius: '$sm',
boxShadow: 'inset 0px 0px 0px 1px $colors$mauve10',
'&:hover': {
boxShadow: 'inset 0px 0px 0px 1px $colors$mauve12'
}
}
}}
>
<Tooltip content="Download as ZIP">
<Button
isLoading={snap.zipLoading}
onClick={downloadAsZip}
outline
size="sm"
css={{ alignItems: 'center' }}
>
<DownloadSimple size="16px" />
</Button>
</Tooltip>
<Tooltip content="Copy share link to clipboard">
<Button
outline
size="sm"
css={{ alignItems: 'center' }}
onClick={() => {
navigator.clipboard.writeText(`${window.location.origin}/develop/${snap.gistId}`)
toast.success('Copied share link to clipboard!')
}}
>
<Share size="16px" />
</Button>
</Tooltip>
<Tooltip
content={
session && session.user
? snap.gistOwner === session?.user.username
? 'Sync to Gist'
: 'Create as a new Gist'
: 'You need to be logged in to sync with Gist'
}
>
<Button
outline
size="sm"
isDisabled={!session || !session.user}
isLoading={snap.gistLoading}
css={{ alignItems: 'center' }}
onClick={() => {
if (!session || !session.user) {
return
}
if (snap.gistOwner === session?.user.username) {
syncToGist(session)
} else {
showNewGistAlert()
}
}}
>
{snap.gistOwner === session?.user.username ? (
<CloudArrowUp size="16px" />
) : (
<FilePlus size="16px" />
)}
</Button>
</Tooltip>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button outline size="sm">
<CaretDown size="16px" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem disabled={snap.zipLoading} onClick={downloadAsZip}>
<DownloadSimple size="16px" /> Download as ZIP
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => {
navigator.clipboard.writeText(
`${window.location.origin}/develop/${snap.gistId}`
)
toast.success('Copied share link to clipboard!')
}}
>
<Share size="16px" />
Copy share link to clipboard
</DropdownMenuItem>
<DropdownMenuItem
disabled={session?.user.username !== snap.gistOwner || !snap.gistId}
onClick={() => {
syncToGist(session)
}}
>
<CloudArrowUp size="16px" /> Push to Gist
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
disabled={status !== 'authenticated'}
onClick={() => {
showNewGistAlert()
}}
>
<FilePlus size="16px" /> Create as a new Gist
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setEditorSettingsOpen(true)}>
<Gear size="16px" /> Editor Settings
</DropdownMenuItem>
<DropdownMenuArrow offset={10} />
</DropdownMenuContent>
</DropdownMenu>
</Stack>
{popup && !session ? <NewWindow center="parent" url="/sign-in" /> : null}
</Container>
</Flex>
<Dialog open={editorSettingsOpen} onOpenChange={setEditorSettingsOpen}>
<DialogTrigger asChild>
{/* <Button outline size="sm" css={{ alignItems: "center" }}>
<Gear size="16px" />
</Button> */}
</DialogTrigger>
<DialogContent>
<DialogTitle>Editor settings</DialogTitle>
<DialogDescription>
<Label>Tab size</Label>
<Input
type="number"
min="1"
value={editorSettings.tabSize}
onChange={e =>
setEditorSettings(curr => ({
...curr,
tabSize: Number(e.target.value)
}))
}
/>
</DialogDescription>
<Flex css={{ marginTop: 25, justifyContent: 'flex-end', gap: '$3' }}>
<DialogClose asChild>
<Button outline onClick={() => updateEditorSettings(editorSettings)}>
Cancel
</Button>
</DialogClose>
<DialogClose asChild>
<Button variant="primary" onClick={() => updateEditorSettings(editorSettings)}>
Save changes
</Button>
</DialogClose>
</Flex>
<DialogClose asChild>
<Box css={{ position: 'absolute', top: '$3', right: '$3' }}>
<X size="20px" />
</Box>
</DialogClose>
</DialogContent>
</Dialog>
</Flex>
)
}
export default EditorNavigation