167 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import React, { useState } from 'react'
 | 
						|
import { useSnapshot } from 'valtio'
 | 
						|
 | 
						|
import { useTheme } from 'next-themes'
 | 
						|
import { useRouter } from 'next/router'
 | 
						|
import NextLink from 'next/link'
 | 
						|
import ReactTimeAgo from 'react-time-ago'
 | 
						|
import filesize from 'filesize'
 | 
						|
 | 
						|
import Box from './Box'
 | 
						|
import Container from './Container'
 | 
						|
import state from '../state'
 | 
						|
import wat from '../utils/wat-highlight'
 | 
						|
 | 
						|
import EditorNavigation from './EditorNavigation'
 | 
						|
import { Button, Text, Link, Flex, Tabs, Tab } from '.'
 | 
						|
import Monaco from './Monaco'
 | 
						|
 | 
						|
const FILESIZE_BREAKPOINTS: [number, number] = [2 * 1024, 5 * 1024]
 | 
						|
 | 
						|
const DeployEditor = () => {
 | 
						|
  const snap = useSnapshot(state)
 | 
						|
  const router = useRouter()
 | 
						|
  const { theme } = useTheme()
 | 
						|
 | 
						|
  const [showContent, setShowContent] = useState(false)
 | 
						|
 | 
						|
  const compiledFiles = snap.files.filter(file => file.compiledContent)
 | 
						|
  const activeFile = compiledFiles[snap.activeWat]
 | 
						|
 | 
						|
  const renderNav = () => (
 | 
						|
    <Tabs activeIndex={snap.activeWat} onChangeActive={idx => (state.activeWat = idx)}>
 | 
						|
      {compiledFiles.map((file, index) => {
 | 
						|
        return <Tab key={file.name} header={`${file.name}.wat`} />
 | 
						|
      })}
 | 
						|
    </Tabs>
 | 
						|
  )
 | 
						|
 | 
						|
  const compiledSize = activeFile?.compiledContent?.byteLength || 0
 | 
						|
  const color =
 | 
						|
    compiledSize > FILESIZE_BREAKPOINTS[1]
 | 
						|
      ? '$error'
 | 
						|
      : compiledSize > FILESIZE_BREAKPOINTS[0]
 | 
						|
      ? '$warning'
 | 
						|
      : '$success'
 | 
						|
 | 
						|
  const isContentChanged = activeFile && activeFile.compiledValueSnapshot !== activeFile.content
 | 
						|
  // const hasDeployErrors = activeFile && activeFile.containsErrors;
 | 
						|
 | 
						|
  const CompiledStatView = activeFile && (
 | 
						|
    <Flex
 | 
						|
      column
 | 
						|
      align="center"
 | 
						|
      css={{
 | 
						|
        fontSize: '$sm',
 | 
						|
        fontFamily: '$monospace',
 | 
						|
        textAlign: 'center'
 | 
						|
      }}
 | 
						|
    >
 | 
						|
      <Flex row align="center">
 | 
						|
        <Text css={{ mr: '$1' }}>Compiled {activeFile.name.split('.')[0] + '.wasm'}</Text>
 | 
						|
        {activeFile?.lastCompiled && <ReactTimeAgo date={activeFile.lastCompiled} locale="en-US" />}
 | 
						|
 | 
						|
        {activeFile.compiledContent?.byteLength && (
 | 
						|
          <Text css={{ ml: '$2', color }}>({filesize(activeFile.compiledContent.byteLength)})</Text>
 | 
						|
        )}
 | 
						|
      </Flex>
 | 
						|
      {activeFile.compiledContent?.byteLength && activeFile.compiledContent?.byteLength >= 64000 && (
 | 
						|
        <Flex css={{ flexDirection: 'column', py: '$3', pb: '$1' }}>
 | 
						|
          <Text css={{ ml: '$2', color: '$error' }}>
 | 
						|
            File size is larger than 64kB, cannot set hook!
 | 
						|
          </Text>
 | 
						|
        </Flex>
 | 
						|
      )}
 | 
						|
      <Button variant="link" onClick={() => setShowContent(true)}>
 | 
						|
        View as WAT-file
 | 
						|
      </Button>
 | 
						|
      {isContentChanged && (
 | 
						|
        <Text warning>
 | 
						|
          File contents were changed after last compile, compile again to incorporate your latest
 | 
						|
          changes in the build.
 | 
						|
        </Text>
 | 
						|
      )}
 | 
						|
    </Flex>
 | 
						|
  )
 | 
						|
  const NoContentView = !snap.loading && router.isReady && (
 | 
						|
    <Text
 | 
						|
      css={{
 | 
						|
        mt: '-60px',
 | 
						|
        fontSize: '$sm',
 | 
						|
        fontFamily: '$monospace',
 | 
						|
        maxWidth: '300px',
 | 
						|
        textAlign: 'center'
 | 
						|
      }}
 | 
						|
    >
 | 
						|
      {`You haven't compiled any files yet, compile files on `}
 | 
						|
      <NextLink shallow href={`/develop/${router.query.slug}`} passHref>
 | 
						|
        <Link as="a">develop view</Link>
 | 
						|
      </NextLink>
 | 
						|
    </Text>
 | 
						|
  )
 | 
						|
 | 
						|
  const isContent = snap.files?.filter(file => file.compiledWatContent).length > 0 && router.isReady
 | 
						|
  return (
 | 
						|
    <Box
 | 
						|
      css={{
 | 
						|
        flex: 1,
 | 
						|
        display: 'flex',
 | 
						|
        position: 'relative',
 | 
						|
        flexDirection: 'column',
 | 
						|
        backgroundColor: '$mauve2',
 | 
						|
        width: '100%'
 | 
						|
      }}
 | 
						|
    >
 | 
						|
      <EditorNavigation renderNav={renderNav} />
 | 
						|
      <Container
 | 
						|
        css={{
 | 
						|
          display: 'flex',
 | 
						|
          flex: 1,
 | 
						|
          justifyContent: 'center',
 | 
						|
          alignItems: 'center'
 | 
						|
        }}
 | 
						|
      >
 | 
						|
        {!isContent ? (
 | 
						|
          NoContentView
 | 
						|
        ) : !showContent ? (
 | 
						|
          CompiledStatView
 | 
						|
        ) : (
 | 
						|
          <Monaco
 | 
						|
            className="hooks-editor"
 | 
						|
            defaultLanguage={'wat'}
 | 
						|
            language={'wat'}
 | 
						|
            path={`file://tmp/c/${activeFile?.name}.wat`}
 | 
						|
            value={activeFile?.compiledWatContent || ''}
 | 
						|
            beforeMount={monaco => {
 | 
						|
              monaco.languages.register({ id: 'wat' })
 | 
						|
              monaco.languages.setLanguageConfiguration('wat', wat.config)
 | 
						|
              monaco.languages.setMonarchTokensProvider('wat', wat.tokens)
 | 
						|
            }}
 | 
						|
            onMount={editor => {
 | 
						|
              editor.updateOptions({
 | 
						|
                glyphMargin: true,
 | 
						|
                readOnly: true
 | 
						|
              })
 | 
						|
            }}
 | 
						|
            theme={theme === 'dark' ? 'dark' : 'light'}
 | 
						|
            overlay={
 | 
						|
              <Flex
 | 
						|
                css={{
 | 
						|
                  m: '$1',
 | 
						|
                  ml: 'auto',
 | 
						|
                  fontSize: '$sm',
 | 
						|
                  color: '$textMuted'
 | 
						|
                }}
 | 
						|
              >
 | 
						|
                <Link onClick={() => setShowContent(false)}>Exit editor mode</Link>
 | 
						|
              </Flex>
 | 
						|
            }
 | 
						|
          />
 | 
						|
        )}
 | 
						|
      </Container>
 | 
						|
    </Box>
 | 
						|
  )
 | 
						|
}
 | 
						|
 | 
						|
export default DeployEditor
 |