feat: main Fixed responsiveness and added Safe and safe functions and added globalThis usage for recursion safety on SSR

This commit is contained in:
Nikolaj Frey 2023-06-30 09:41:06 +10:00
parent 56da3991a5
commit 9793237357
10 changed files with 234 additions and 111 deletions

View File

@ -1,9 +1,18 @@
import { Flex } from '@chakra-ui/react' import { Flex } from '@chakra-ui/react'
import { Nav } from '../Nav/Nav' import { Nav } from '../Nav/Nav'
import { ProfileDrawer } from '../Nav/ProfileDrawer'
export const Main = props => { export const Main = props => {
return ( return (
<Flex alignItems='center' justifyContent='center' flexDir={'column'}> <Flex
position={'relative'}
alignItems='center'
justifyContent='center'
flexDir={'column'}
overflow='hidden'
maxW='100vw'
>
{/* <ProfileDrawer></ProfileDrawer> */}
<Nav /> <Nav />
{props.children} {props.children}
</Flex> </Flex>

View File

@ -1,8 +1,15 @@
import React from 'react' import React from 'react'
import { Flex } from '@chakra-ui/react' import { Flex } from '@chakra-ui/react'
import { RainbowSkeleton } from '../Skeleton/RainbowSkeleton' import { RainbowSkeleton } from '../Skeleton/RainbowSkeleton'
import { ProfileDrawer } from './ProfileDrawer'
export const Nav = props => { export const Nav = props => {
const [profileDrawerOpen, setProfileDrawerOpen] = React.useState(false)
const toggleProfileDrawer = React.useCallback(() => {
setProfileDrawerOpen(!profileDrawerOpen)
}, [profileDrawerOpen])
return ( return (
<> <>
<Flex <Flex
@ -15,12 +22,24 @@ export const Nav = props => {
top={0} top={0}
left={0} left={0}
right={0} right={0}
py={4} py={6}
px={4} px={6}
bg='white'
zIndex={999}
boxShadow={'0px 0px 10px rgba(0,0,0,0.1)'}
> >
<RainbowSkeleton
ml={'auto'}
w='25px'
h='25px'
onClick={toggleProfileDrawer}
sx={{}}
borderRadius='999px'
></RainbowSkeleton>
{/* <RainbowSkeleton w='40px' ml='auto' mr={"4px"}></RainbowSkeleton> {/* <RainbowSkeleton w='40px' ml='auto' mr={"4px"}></RainbowSkeleton>
<RainbowSkeleton></RainbowSkeleton> */} <RainbowSkeleton></RainbowSkeleton> */}
</Flex> </Flex>
{/* <ProfileDrawer isOpen={profileDrawerOpen}></ProfileDrawer> */}
</> </>
) )
} }

View File

@ -0,0 +1,27 @@
import React from 'react'
import { Drawer, DrawerBody, DrawerContent, Flex } from '@chakra-ui/react'
export const ProfileDrawer = props => {
const navItems = ['settings']
const onClose = React.useCallback(() => {
// nothing
}, [])
return (
<Drawer
placement='right'
size='md'
isOpen={props?.isOpen}
onClose={onClose}
>
<DrawerContent maxW={'90%'} mt={'35px'} className='ProfileDrawer'>
<DrawerBody>
{navItems.map((item, idx) => {
return <Flex key={idx}>{item}</Flex>
})}
</DrawerBody>
</DrawerContent>
</Drawer>
)
}

View File

@ -0,0 +1,7 @@
import { safe } from '~/functions/safe'
export const Safe = props => {
// do not render more than the limit of things to prevent infinite loops
return safe(props)
}

View File

@ -2,15 +2,22 @@ import React from 'react'
import { Flex } from '@chakra-ui/react' import { Flex } from '@chakra-ui/react'
export const RainbowSkeleton = props => { export const RainbowSkeleton = props => {
const [rainbowColours] = React.useState([
const [rainbowColours] = React.useState(["#f34a4a", "#ffbc48", "#58ca70", "#47b5e6", "#a555e8"]) '#f34a4a',
'#ffbc48',
'#58ca70',
'#47b5e6',
'#a555e8'
])
const keyframes = React.useMemo(() => { const keyframes = React.useMemo(() => {
let keyframes = {} let keyframes = {}
rainbowColours.forEach((colour, idx) => { rainbowColours.forEach((colour, idx) => {
keyframes[Math.round(idx * 100 / rainbowColours.length) + "%"] = { backgroundColor: colour } keyframes[Math.round((idx * 100) / rainbowColours.length) + '%'] = {
backgroundColor: colour
}
}) })
keyframes["100%"] = { backgroundColor: rainbowColours[0] } keyframes['100%'] = { backgroundColor: rainbowColours[0] }
return keyframes return keyframes
}, [rainbowColours]) }, [rainbowColours])
@ -20,17 +27,11 @@ export const RainbowSkeleton = props => {
return ( return (
<Flex <Flex
{...props} cursor='pointer'
flexDirection={'column'}
justifyContent={'center'}
alignItems={'center'}
cursor={'pointer'}
>
<Flex
w='10px' w='10px'
h='8px' h='8px'
borderRadius={'2px'} borderRadius={'2px'}
mb='10px' bg={'rgba(0,0,0,0.1)'}
sx={{ sx={{
'@keyframes placeholder-rainbow': keyframes, '@keyframes placeholder-rainbow': keyframes,
'@keyframes placeholder-opacity': { '@keyframes placeholder-opacity': {
@ -42,6 +43,5 @@ export const RainbowSkeleton = props => {
}} }}
{...props} {...props}
></Flex> ></Flex>
</Flex>
) )
} }

View File

@ -1,12 +1,16 @@
import React from 'react' import React from 'react'
import { Box, Flex } from '@chakra-ui/react' import { Box, Flex } from '@chakra-ui/react'
import { safe } from '~/functions/safe' import { Safe } from '../Safety/Safe'
export const Thingtime = props => { export const Thingtime = props => {
// const cuid = React.useMemo(() => { // const uuid = React.useMemo(() => {
// return Math.random().toString(36).substring(7) // return Math.random().toString(36).substring(7)
// }, []) // }, [])
const cuid = React.useRef(Math.random().toString(36).substring(7)) const uuid = React.useRef(Math.random().toString(36).substring(7))
const depth = React.useMemo(() => {
return props?.depth || 1
}, [props?.depth])
const thing = React.useMemo(() => { const thing = React.useMemo(() => {
return props.thing return props.thing
@ -28,13 +32,6 @@ export const Thingtime = props => {
} }
}, [thing, validKeyTypes]) }, [thing, validKeyTypes])
React.useEffect(() => {
if (window?.thingtime?.things) {
window.thingtime.things.count =
(window?.thingtime?.things?.count || 1) + 1
}
}, [])
const type = React.useMemo(() => { const type = React.useMemo(() => {
return typeof thing return typeof thing
}, [thing]) }, [thing])
@ -84,15 +81,11 @@ export const Thingtime = props => {
}) })
} }
console.log('nik ret 1', thing)
recurse(thing, '') recurse(thing, '')
} catch (err) { } catch (err) {
// console.error('Error in Thingtime.tsx creating flattenedKeys', err) // console.error('Error in Thingtime.tsx creating flattenedKeys', err)
} }
console.log('nik ret 2', ret)
return ret return ret
}, [thing]) }, [thing])
@ -105,15 +98,17 @@ export const Thingtime = props => {
const template1Modes = ['view', 'edit'] const template1Modes = ['view', 'edit']
if (template1Modes?.includes(mode)) { if (template1Modes?.includes(mode)) {
console.log('nik keys', keys)
if (keys?.length) { if (keys?.length) {
value = ( value = (
<Safe {...props}>
<Flex <Flex
position='relative' position='relative'
flexDir='column' flexDir='column'
minW='500px' // w={'500px'}
// w={['200px', '500px']}
maxW='100%' maxW='100%'
pl={6} pl={[4, 6]}
pr={[4, 6]}
> >
{keysToUse?.length && {keysToUse?.length &&
keysToUse.map((key, idx) => { keysToUse.map((key, idx) => {
@ -129,13 +124,16 @@ export const Thingtime = props => {
return ( return (
<Thingtime <Thingtime
key={idx} key={idx}
depth={depth + 1}
parent={thing} parent={thing}
path={key} path={key}
thing={nextThing} thing={nextThing}
// thing={{ infinite: { yes: true } }}
></Thingtime> ></Thingtime>
) )
})} })}
</Flex> </Flex>
</Safe>
) )
} else { } else {
editableValue = ( editableValue = (
@ -161,39 +159,45 @@ export const Thingtime = props => {
const [showContextMenu, setShowContextMenu] = React.useState(false) const [showContextMenu, setShowContextMenu] = React.useState(false)
const path = React.useMemo(() => { const path = React.useMemo(() => {
return <Flex fontSize='12px'>{props?.path?.human}</Flex> return (
<Flex maxW='100%' wordBreak={'break-all'} fontSize='12px'>
{props?.path?.human}
</Flex>
)
}, [props?.path]) }, [props?.path])
const handleMouseEvent = React.useCallback( const handleMouseEvent = React.useCallback(
e => { e => {
const target = e?.target const target = e?.target
// extract cuid from className // extract uuid from className
console.log('nik eh', target?.className, cuid)
const className = target?.className const className = target?.className
if (className?.includes(cuid?.current)) { if (className?.includes(uuid?.current)) {
setShowContextMenu(e?.type === 'mouseenter') setShowContextMenu(e?.type === 'mouseenter')
} }
}, },
[cuid] [uuid]
) )
console.log('nik cuid', cuid) return (
<Safe {...props} depth={depth} uuid={uuid?.current}>
return safe(
<Flex <Flex
onMouseEnter={handleMouseEvent} onMouseEnter={handleMouseEvent}
onMouseLeave={handleMouseEvent} onMouseLeave={handleMouseEvent}
position='relative' position='relative'
flexDir='column' flexDir='column'
py={3} py={3}
w='500px'
// minW={depth === 1 ? '120px' : null}
maxW='100%'
{...props} {...props}
className={`thing-${cuid?.current}`} className={`thing-${uuid?.current}`}
> >
{/* {cuid?.current} */} {/* {uuid?.current} */}
{path} {path}
{showContextMenu && contextMenu} {showContextMenu && contextMenu}
{editableValue} {editableValue}
{value} {value}
</Flex> </Flex>
</Safe>
) )
} }

View File

@ -28,7 +28,7 @@ export const ThingtimeDemo = props => {
// return null // return null
return ( return (
<Flex pb={40}> <Flex maxW='100%' pb={40}>
<Thingtime thing={demoThing}></Thingtime> <Thingtime thing={demoThing}></Thingtime>
</Flex> </Flex>
) )

View File

@ -1,16 +1,56 @@
export const safe = response => { export const safe = props => {
// do not render more than the limit of things to prevent infinite loops // do not render more than the limit of things to prevent infinite loops
const thingtime = getThingtime()
const uuid = props?.uuid
try { try {
if ( if (
typeof window?.thingtime?.things?.count === 'number' && typeof thingtime?.things?.count === 'number' &&
window?.thingtime?.things?.count > window?.thingtime?.things?.limit thingtime?.things?.count >= thingtime?.things?.limit
) { ) {
console.error('Maximum things reached') console.error(
'[codex] Maximum things reached',
thingtime?.things?.count,
thingtime?.things?.limit
)
return null return null
} }
} catch (err) { } catch (err) {
// console.error('Error in Thingtime.tsx checking maximum things', err) console.error('[codex] Error in Thingtime.tsx checking maximum things', err)
} }
return response try {
if (!thingtime?.things?.db?.[uuid]) {
thingtime.things.db[uuid] = {
count: 1
}
thingtime.things.count++
}
} catch {
// empty
}
try {
if (props?.depth >= thingtime?.things?.maxDepth) {
console.error(
'[codex] Reached max depth',
props?.depth,
thingtime?.things?.maxDepth
)
return null
}
} catch {
// nothing
}
return props?.children
}
export const getThingtime = () => {
try {
return window?.thingtime || globalThis?.thingtime
} catch {
return globalThis?.thingtime
}
} }

View File

@ -48,16 +48,26 @@ export default function App () {
) )
} }
// limiter // limiter
try {
window.thingtime = { const setThingtime = glob => {
try {
glob.thingtime = {
tmp: {}, tmp: {},
things: { things: {
limit: 999, db: {},
count: 0, limit: 9999,
maxDepth: 10,
count: 0
} }
} }
} catch (err) { } catch (err) {
// will error on server // will error on server
}
}
try {
setThingtime(window)
} catch {
setThingtime(globalThis)
} }

View File

@ -1,12 +1,19 @@
import { Flex } from '@chakra-ui/react' import { Flex } from '@chakra-ui/react'
import { ProfileDrawer } from '~/components/Nav/ProfileDrawer'
import { Splash } from '~/components/Splash/Splash' import { Splash } from '~/components/Splash/Splash'
import { ThingtimeDemo } from '~/components/Thingtime/ThingtimeDemo' import { ThingtimeDemo } from '~/components/Thingtime/ThingtimeDemo'
export default function Index () { export default function Index () {
return ( return (
<Flex flexDir='column' alignItems='center' justifyContent='center'> <Flex
maxW='100%'
flexDir='column'
alignItems='center'
justifyContent='center'
>
<Splash></Splash> <Splash></Splash>
<ThingtimeDemo></ThingtimeDemo> <ThingtimeDemo></ThingtimeDemo>
<ProfileDrawer></ProfileDrawer>
</Flex> </Flex>
) )
} }