feat: feature/mvp-sprint-1 Added type wrapping, custom types, new child types, commander address bar behaviour
This commit is contained in:
parent
168035201d
commit
a69c4067df
@ -30,7 +30,207 @@ try {
|
||||
|
||||
const force = {
|
||||
settings: {
|
||||
undoLimit: 999,
|
||||
types: {
|
||||
javascript: {
|
||||
any: {
|
||||
type: "any",
|
||||
value: () => {
|
||||
return null
|
||||
},
|
||||
},
|
||||
object: {
|
||||
type: "object",
|
||||
value: () => {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
array: {
|
||||
type: "array",
|
||||
value: () => {
|
||||
return []
|
||||
},
|
||||
},
|
||||
string: {
|
||||
type: "string",
|
||||
value: () => {
|
||||
return ""
|
||||
},
|
||||
},
|
||||
number: {
|
||||
type: "number",
|
||||
value: () => {
|
||||
return 0
|
||||
},
|
||||
},
|
||||
boolean: {
|
||||
type: "boolean",
|
||||
value: () => {
|
||||
return false
|
||||
},
|
||||
},
|
||||
function: {
|
||||
type: "function",
|
||||
value: () => {
|
||||
return () => {}
|
||||
},
|
||||
},
|
||||
},
|
||||
custom: {
|
||||
"Thingtime Logo": {
|
||||
type: "chakra",
|
||||
value: {
|
||||
type: "chakra",
|
||||
chakra: "Box",
|
||||
props: {
|
||||
fontSize: 12,
|
||||
},
|
||||
rawChildren: ["🌈 Thingtime"],
|
||||
},
|
||||
},
|
||||
"Violet Container Centered": {
|
||||
name: "Violet Container Centered",
|
||||
type: "chakra",
|
||||
icon: "💜",
|
||||
wrap: "children",
|
||||
value: {
|
||||
name: "Violet Container Centered",
|
||||
type: "chakra",
|
||||
chakra: "Center",
|
||||
props: {
|
||||
bg: "#AB47BC",
|
||||
padding: 4,
|
||||
borderRadius: 12,
|
||||
},
|
||||
children: [],
|
||||
},
|
||||
},
|
||||
"Indigo Container Centered": {
|
||||
name: "Indigo Container Centered",
|
||||
type: "chakra",
|
||||
icon: "🩷",
|
||||
wrap: "children",
|
||||
value: {
|
||||
name: "Indigo Container Centered",
|
||||
type: "chakra",
|
||||
chakra: "Center",
|
||||
props: {
|
||||
bg: "#5C6BC0",
|
||||
padding: 4,
|
||||
borderRadius: 12,
|
||||
},
|
||||
children: [],
|
||||
},
|
||||
},
|
||||
"Blue Container Centered": {
|
||||
name: "Blue Container Centered",
|
||||
type: "chakra",
|
||||
icon: "💙",
|
||||
wrap: "children",
|
||||
value: {
|
||||
name: "Blue Container Centered",
|
||||
type: "chakra",
|
||||
chakra: "Center",
|
||||
props: {
|
||||
bg: "#42A5F5",
|
||||
padding: 4,
|
||||
borderRadius: 12,
|
||||
},
|
||||
children: [],
|
||||
},
|
||||
},
|
||||
"Green Container Centered": {
|
||||
name: "Green Container Centered",
|
||||
type: "chakra",
|
||||
icon: "💚",
|
||||
wrap: "children",
|
||||
value: {
|
||||
name: "Green Container Centered",
|
||||
type: "chakra",
|
||||
chakra: "Center",
|
||||
props: {
|
||||
bg: "#66BB6A",
|
||||
padding: 4,
|
||||
borderRadius: 12,
|
||||
},
|
||||
children: [],
|
||||
},
|
||||
},
|
||||
"Yellow Container Centered": {
|
||||
name: "Yellow Container Centered",
|
||||
type: "chakra",
|
||||
icon: "💛",
|
||||
wrap: "children",
|
||||
value: {
|
||||
name: "Yellow Container Centered",
|
||||
type: "chakra",
|
||||
chakra: "Center",
|
||||
props: {
|
||||
bg: "#FFEE58",
|
||||
padding: 4,
|
||||
borderRadius: 12,
|
||||
},
|
||||
children: [],
|
||||
},
|
||||
},
|
||||
"Orange Container Centered": {
|
||||
name: "Orange Container Centered",
|
||||
type: "chakra",
|
||||
icon: "🧡",
|
||||
wrap: "children",
|
||||
value: {
|
||||
name: "Orange Container Centered",
|
||||
type: "chakra",
|
||||
chakra: "Center",
|
||||
props: {
|
||||
bg: "#FF7043",
|
||||
padding: 4,
|
||||
borderRadius: 12,
|
||||
},
|
||||
children: [],
|
||||
},
|
||||
},
|
||||
"Red Container Centered": {
|
||||
name: "Red Container Centered",
|
||||
type: "chakra",
|
||||
icon: "❤️",
|
||||
wrap: "children",
|
||||
value: {
|
||||
name: "Red Container Centered",
|
||||
type: "chakra",
|
||||
chakra: "Center",
|
||||
props: {
|
||||
bg: "#C62828",
|
||||
padding: 4,
|
||||
borderRadius: 12,
|
||||
},
|
||||
children: [],
|
||||
},
|
||||
},
|
||||
"Left Aligned": {
|
||||
type: "chakra",
|
||||
value: {
|
||||
type: "chakra",
|
||||
chakra: "Flex",
|
||||
props: {
|
||||
mr: "auto",
|
||||
},
|
||||
children: [],
|
||||
},
|
||||
},
|
||||
"Right Aligned": {
|
||||
type: "chakra",
|
||||
value: {
|
||||
type: "chakra",
|
||||
chakra: "Flex",
|
||||
props: {
|
||||
ml: "auto",
|
||||
},
|
||||
children: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// undoLimit: 999,
|
||||
// commander: {
|
||||
// nav: {
|
||||
// commanderActive: false,
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from "react"
|
||||
import ClickAwayListener from "react-click-away-listener"
|
||||
import { Center, Flex, Input } from "@chakra-ui/react"
|
||||
import { useLocation } from "@remix-run/react"
|
||||
import Fuse from "fuse.js"
|
||||
|
||||
import { Rainbow } from "../Rainbow/Rainbow"
|
||||
@ -8,12 +9,15 @@ import { Thingtime } from "../Thingtime/Thingtime"
|
||||
import { useThingtime } from "../Thingtime/useThingtime"
|
||||
|
||||
import { sanitise } from "~/functions/sanitise"
|
||||
import { usePath } from "~/hooks/usePath"
|
||||
import { getParentPath } from "~/smarts"
|
||||
|
||||
export const CommanderV1 = (props) => {
|
||||
const { thingtime, setThingtime, getThingtime, thingtimeRef, paths } =
|
||||
useThingtime()
|
||||
|
||||
const { mode, changePath } = usePath()
|
||||
|
||||
const commanderId = React.useMemo(() => {
|
||||
return props?.id || "global"
|
||||
}, [props?.id])
|
||||
@ -36,7 +40,7 @@ export const CommanderV1 = (props) => {
|
||||
const [active, setActive] = React.useState(false)
|
||||
const [contextPath, setContextPath] = React.useState()
|
||||
|
||||
const mode = React.useMemo(() => {
|
||||
const commanderMode = React.useMemo(() => {
|
||||
return props?.mode || "value"
|
||||
}, [props?.mode])
|
||||
|
||||
@ -318,8 +322,13 @@ export const CommanderV1 = (props) => {
|
||||
// const newValue = setThingtime(commandPath, prevValue)
|
||||
|
||||
console.log("Setting context path", commandPath)
|
||||
setContextPath(commandPath)
|
||||
setShowContext(true, "commandContainsPath check")
|
||||
// setContextPath(commandPath)
|
||||
|
||||
changePath({
|
||||
path: commandPath,
|
||||
})
|
||||
|
||||
// setShowContext(true, "commandContainsPath check")
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Caught error on commander onEnter", err)
|
||||
@ -328,6 +337,8 @@ export const CommanderV1 = (props) => {
|
||||
}, [
|
||||
hoveredSuggestion,
|
||||
selectSuggestion,
|
||||
mode,
|
||||
changePath,
|
||||
commanderActive,
|
||||
commandIsAction,
|
||||
commandPath,
|
||||
@ -421,9 +432,9 @@ export const CommanderV1 = (props) => {
|
||||
<ClickAwayListener onClickAway={closeCommander}>
|
||||
<Flex
|
||||
position="absolute"
|
||||
zIndex={9999}
|
||||
top={0}
|
||||
right={0}
|
||||
// zIndex={99999}
|
||||
// position='fixed'
|
||||
// top='100px'
|
||||
left={0}
|
||||
@ -438,6 +449,7 @@ export const CommanderV1 = (props) => {
|
||||
>
|
||||
<Flex
|
||||
position="absolute"
|
||||
zIndex={9999}
|
||||
top="100%"
|
||||
right={0}
|
||||
left={0}
|
||||
@ -528,6 +540,7 @@ export const CommanderV1 = (props) => {
|
||||
>
|
||||
<Center
|
||||
position="relative"
|
||||
zIndex={9999}
|
||||
overflow="hidden"
|
||||
width={["100%", "400px"]}
|
||||
maxWidth={[mobileVW, "100%"]}
|
||||
@ -553,6 +566,7 @@ export const CommanderV1 = (props) => {
|
||||
color: "greys.dark",
|
||||
},
|
||||
}}
|
||||
zIndex={9999}
|
||||
width="100%"
|
||||
height="100%"
|
||||
background="grey"
|
||||
@ -570,6 +584,7 @@ export const CommanderV1 = (props) => {
|
||||
{!props?.rainbow && (
|
||||
<Center
|
||||
position="relative"
|
||||
zIndex={9999}
|
||||
overflow="hidden"
|
||||
width={["100%", "400px"]}
|
||||
maxWidth={[mobileVW, "100%"]}
|
||||
@ -588,6 +603,7 @@ export const CommanderV1 = (props) => {
|
||||
color: "greys.dark",
|
||||
},
|
||||
}}
|
||||
zIndex={9999}
|
||||
width="100%"
|
||||
height="100%"
|
||||
background="grey"
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React from "react"
|
||||
import { Center } from "@chakra-ui/react"
|
||||
import emojis from "emojis-list"
|
||||
|
||||
export const Icon = (props) => {
|
||||
const name = props?.name
|
||||
@ -183,6 +184,28 @@ export const Icon = (props) => {
|
||||
}
|
||||
return "🌀"
|
||||
}
|
||||
if (["function", "lambda"]?.includes(name)) {
|
||||
return "📐"
|
||||
}
|
||||
if (["pin", "pinned", "located"]?.includes(name)) {
|
||||
return "📌"
|
||||
}
|
||||
|
||||
if (["wrap", "wrapped"]?.includes(name)) {
|
||||
return "🎁"
|
||||
// return "🎀"
|
||||
}
|
||||
|
||||
if (emojis?.includes(name)) {
|
||||
return name
|
||||
}
|
||||
|
||||
if (["random"]?.includes(name)) {
|
||||
return emojis[Math.floor(Math.random() * emojis.length)]
|
||||
}
|
||||
|
||||
// question mark
|
||||
return "❓"
|
||||
}, [name])
|
||||
|
||||
return (
|
||||
|
@ -7,6 +7,11 @@ import { ProfileDrawer } from "../Nav/ProfileDrawer"
|
||||
export const Main = (props) => {
|
||||
return (
|
||||
<Flex
|
||||
sx={{
|
||||
"*": {
|
||||
whiteSpace: "pre-wrap",
|
||||
},
|
||||
}}
|
||||
position="relative"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
|
@ -79,7 +79,7 @@ export const Nav = (props) => {
|
||||
<>
|
||||
<Box
|
||||
position="fixed"
|
||||
zIndex={999}
|
||||
zIndex={9999}
|
||||
top={0}
|
||||
right={0}
|
||||
left={0}
|
||||
|
@ -9,6 +9,15 @@ export const SettingsMenu = (props) => {
|
||||
const [show, setShow] = useState(false)
|
||||
const hideRef = React.useRef(null)
|
||||
const [opacity, setOpacity] = React.useState(props?.opacity === 0 ? 0 : 1)
|
||||
const [pinStatus, setPinStatus] = React.useState(false)
|
||||
|
||||
const stateRef = React.useRef({
|
||||
pinStatus,
|
||||
})
|
||||
|
||||
React.useEffect(() => {
|
||||
stateRef.current.pinStatus = pinStatus
|
||||
}, [pinStatus])
|
||||
|
||||
const { thingtime, events } = useThingtime()
|
||||
|
||||
@ -25,7 +34,10 @@ export const SettingsMenu = (props) => {
|
||||
React.useEffect(() => {
|
||||
const subscription = events.subscribe((event) => {
|
||||
if (event?.type === "settings-menu-hide" && event?.uuid !== uuid) {
|
||||
setShow(false)
|
||||
if (!stateRef?.current?.pinStatus || event?.force) {
|
||||
setShow(false)
|
||||
setOpacity(0)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -40,8 +52,10 @@ export const SettingsMenu = (props) => {
|
||||
setOpacity(props?.opacity)
|
||||
} else {
|
||||
opacityRef.current = setInterval(() => {
|
||||
setOpacity(props?.opacity)
|
||||
setShow(false)
|
||||
if (!stateRef?.current?.pinStatus) {
|
||||
setOpacity(props?.opacity)
|
||||
setShow(false)
|
||||
}
|
||||
}, waitTime)
|
||||
}
|
||||
}, [props?.opacity])
|
||||
@ -53,17 +67,23 @@ export const SettingsMenu = (props) => {
|
||||
type: "settings-menu-hide",
|
||||
uuid,
|
||||
})
|
||||
} else if (!show) {
|
||||
setPinStatus(false)
|
||||
}
|
||||
}, [show, props?.opacity, events, uuid])
|
||||
|
||||
const maybeHide = React.useCallback(() => {
|
||||
clearInterval(hideRef?.current)
|
||||
hideRef.current = setTimeout(() => {
|
||||
setShow(false)
|
||||
if (!stateRef?.current?.pinStatus) {
|
||||
setShow(false)
|
||||
setOpacity(0)
|
||||
}
|
||||
}, waitTime)
|
||||
}, [])
|
||||
|
||||
const showMenu = React.useCallback(() => {
|
||||
clearInterval(hideRef?.current)
|
||||
setShow(true)
|
||||
}, [])
|
||||
|
||||
@ -76,22 +96,41 @@ export const SettingsMenu = (props) => {
|
||||
}, [])
|
||||
|
||||
const types = React.useMemo(() => {
|
||||
const ret = [
|
||||
{ label: "any", icon: "any" },
|
||||
"object",
|
||||
"array",
|
||||
"string",
|
||||
"number",
|
||||
"boolean",
|
||||
]
|
||||
return ret
|
||||
}, [])
|
||||
const baseTypes = thingtime?.settings?.types?.javascript || {}
|
||||
const baseTypeKeys = Object.keys(baseTypes)
|
||||
|
||||
const onChangeType = React.useCallback(
|
||||
(type) => {
|
||||
props?.onChangeType?.(type)
|
||||
const customTypes = thingtime?.settings?.types?.custom || {}
|
||||
const customTypeKeysRaw = Object.keys(customTypes)
|
||||
const customTypeKeys = customTypeKeysRaw?.filter((key) => {
|
||||
return !baseTypeKeys?.includes?.(key)
|
||||
})
|
||||
|
||||
const types = [
|
||||
...(baseTypeKeys?.map?.((key) => {
|
||||
return {
|
||||
...baseTypes?.[key],
|
||||
key,
|
||||
}
|
||||
}) || []),
|
||||
...(customTypeKeys?.map?.((key) => {
|
||||
return {
|
||||
...customTypes?.[key],
|
||||
key,
|
||||
}
|
||||
}) || []),
|
||||
]
|
||||
|
||||
return types
|
||||
}, [
|
||||
thingtime?.settings?.types?.javascript,
|
||||
thingtime?.settings?.types?.custom,
|
||||
])
|
||||
|
||||
const onType = React.useCallback(
|
||||
(args) => {
|
||||
props?.onType?.(args)
|
||||
},
|
||||
[props?.onChangeType]
|
||||
[props?.onType]
|
||||
)
|
||||
const onDelete = React.useCallback(
|
||||
(type) => {
|
||||
@ -100,7 +139,8 @@ export const SettingsMenu = (props) => {
|
||||
[props?.onDelete]
|
||||
)
|
||||
|
||||
const iconSize = 10
|
||||
const childIconSize = 10
|
||||
const iconSize = props?.iconSize || 7
|
||||
|
||||
return (
|
||||
<ClickAwayListener onClickAway={hideMenu}>
|
||||
@ -120,7 +160,7 @@ export const SettingsMenu = (props) => {
|
||||
// onClick={deleteValue}
|
||||
transition="all 0.2s ease-in-out"
|
||||
>
|
||||
<Icon name="wizard" size={7}></Icon>
|
||||
<Icon name="wizard" size={iconSize}></Icon>
|
||||
</Flex>
|
||||
<Flex
|
||||
position="absolute"
|
||||
@ -131,6 +171,20 @@ export const SettingsMenu = (props) => {
|
||||
opacity={show ? 1 : 0}
|
||||
pointerEvents={show ? "all" : "none"}
|
||||
>
|
||||
<Flex
|
||||
position="absolute"
|
||||
top={0}
|
||||
right={0}
|
||||
padding="5px"
|
||||
cursor="pointer"
|
||||
onClick={() => setPinStatus((prev) => !prev)}
|
||||
>
|
||||
<Icon
|
||||
opacity={pinStatus ? 1 : 0.5}
|
||||
name={pinStatus ? "pinned" : "pin"}
|
||||
size="8px"
|
||||
></Icon>
|
||||
</Flex>
|
||||
<Flex
|
||||
flexDirection="column"
|
||||
// rowGap={basePadding / 3}
|
||||
@ -143,8 +197,8 @@ export const SettingsMenu = (props) => {
|
||||
<Flex
|
||||
alignItems="center"
|
||||
flexDirection="row"
|
||||
paddingRight={basePadding * 2}
|
||||
paddingLeft={basePadding * 1}
|
||||
// paddingRight={basePadding}
|
||||
paddingLeft={basePadding}
|
||||
_hover={{
|
||||
background: "greys.light",
|
||||
}}
|
||||
@ -152,7 +206,11 @@ export const SettingsMenu = (props) => {
|
||||
// paddingX={basePadding * 1}
|
||||
paddingY={basePadding / 2}
|
||||
>
|
||||
<Icon marginBottom="-2px" name="cyclone" size={iconSize}></Icon>
|
||||
<Icon
|
||||
marginBottom="-2px"
|
||||
name="cyclone"
|
||||
size={childIconSize}
|
||||
></Icon>
|
||||
<Text marginTop="-2px" paddingLeft={2} fontSize="xs">
|
||||
Types
|
||||
</Text>
|
||||
@ -161,6 +219,8 @@ export const SettingsMenu = (props) => {
|
||||
<Flex
|
||||
flexDirection="column"
|
||||
// rowGap={basePadding}
|
||||
overflowY="scroll"
|
||||
maxHeight="300px"
|
||||
background="greys.lightt"
|
||||
cursor="pointer"
|
||||
>
|
||||
@ -176,32 +236,53 @@ export const SettingsMenu = (props) => {
|
||||
},
|
||||
}}
|
||||
cursor="pointer"
|
||||
onClick={() => onChangeType(type?.key || type)}
|
||||
onClick={() => onType({ type })}
|
||||
paddingY={1}
|
||||
>
|
||||
<Flex
|
||||
alignItems="center"
|
||||
flexDirection="row"
|
||||
width="100%"
|
||||
paddingRight={basePadding * 4}
|
||||
paddingRight={basePadding}
|
||||
paddingLeft={basePadding * 2}
|
||||
paddingY={basePadding / 2}
|
||||
>
|
||||
<Icon
|
||||
marginBottom="-2px"
|
||||
name={type?.icon || type?.key || type?.label || type}
|
||||
size={iconSize}
|
||||
size={childIconSize}
|
||||
></Icon>
|
||||
<Text marginTop="-2px" paddingLeft={2} fontSize="xs">
|
||||
{type?.label || type?.key || type}
|
||||
</Text>
|
||||
{type?.wrap && (
|
||||
<Flex
|
||||
marginLeft="auto"
|
||||
_hover={{
|
||||
transform: "scale(1.3)",
|
||||
}}
|
||||
transition="all 0.2s ease-out"
|
||||
onClick={(e) => {
|
||||
e?.preventDefault?.()
|
||||
e?.stopPropagation?.()
|
||||
// cancel bubble
|
||||
e?.nativeEvent?.stopImmediatePropagation?.()
|
||||
onType({
|
||||
type,
|
||||
wrap: true,
|
||||
})
|
||||
}}
|
||||
>
|
||||
<Icon name="wrap" size={childIconSize}></Icon>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
)
|
||||
return ret
|
||||
})}
|
||||
</Flex>
|
||||
{!props?.readonly && (
|
||||
{!props?.readonly && props?.onDelete && (
|
||||
<Flex
|
||||
alignItems="center"
|
||||
flexDirection="row"
|
||||
@ -213,7 +294,11 @@ export const SettingsMenu = (props) => {
|
||||
paddingX={basePadding * 1}
|
||||
paddingY={basePadding / 2}
|
||||
>
|
||||
<Icon marginBottom="-2px" name="bin" size={iconSize}></Icon>
|
||||
<Icon
|
||||
marginBottom="-2px"
|
||||
name="bin"
|
||||
size={childIconSize}
|
||||
></Icon>
|
||||
<Text marginTop="-2px" paddingLeft={2} fontSize="xs">
|
||||
Recycle
|
||||
</Text>
|
||||
|
@ -25,6 +25,7 @@ import { Safe } from "../Safety/Safe"
|
||||
import { SettingsMenu } from "./SettingsMenu"
|
||||
import { useThingtime } from "./useThingtime"
|
||||
|
||||
import { useThings } from "~/hooks/useThings"
|
||||
import { getThing } from "~/smarts"
|
||||
|
||||
export const Thingtime = (props) => {
|
||||
@ -32,7 +33,10 @@ export const Thingtime = (props) => {
|
||||
// and add button to expand circular reference
|
||||
// up to 1 level deep
|
||||
|
||||
const { thingtime, setThingtime, getThingtime, loading } = useThingtime()
|
||||
const { append } = useThings()
|
||||
|
||||
const { thingtime, setThingtime, getThingtime, loading, events } =
|
||||
useThingtime()
|
||||
|
||||
const [uuid, setUuid] = React.useState(undefined)
|
||||
|
||||
@ -42,6 +46,8 @@ export const Thingtime = (props) => {
|
||||
|
||||
const thingtimeRef = React.useRef()
|
||||
|
||||
const [showFullPathContext, setShowFullPathContext] = React.useState(false)
|
||||
|
||||
const editValueRef = React.useRef({})
|
||||
|
||||
const depth = React.useMemo(() => {
|
||||
@ -65,20 +71,20 @@ export const Thingtime = (props) => {
|
||||
return "100%"
|
||||
}, [props?.width, props?.w, render])
|
||||
|
||||
const chakras = React.useMemo(() => {
|
||||
if (!props?.edit && props?.chakra) {
|
||||
const chakraChild = React.useMemo(() => {
|
||||
if (!props?.edit && props?.chakraChild) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}, [props?.edit, props?.chakra])
|
||||
}, [props?.edit, props?.chakraChild])
|
||||
|
||||
const pl = React.useMemo(() => {
|
||||
if (!props.edit && chakras) {
|
||||
if (!props.edit && chakraChild) {
|
||||
return [0]
|
||||
}
|
||||
|
||||
return props?.pl || [4, 6]
|
||||
}, [props?.pl, props?.edit, chakras])
|
||||
}, [props?.pl, props?.edit, chakraChild])
|
||||
|
||||
const pr = React.useMemo(() => {
|
||||
return props?.pr || (depth === 0 ? [4, 6] : 0)
|
||||
@ -138,7 +144,7 @@ export const Thingtime = (props) => {
|
||||
|
||||
const thing = React.useMemo(() => {
|
||||
return props.thing
|
||||
}, [props.thing, childrenRef.current])
|
||||
}, [props.thing, uuid, childrenRef.current])
|
||||
|
||||
const chakra = React.useMemo(() => {
|
||||
return !props?.edit && typeof thing?.chakra === "string" && thing?.chakra
|
||||
@ -250,7 +256,7 @@ export const Thingtime = (props) => {
|
||||
}, [props?.valuePl, props?.path])
|
||||
|
||||
const renderableValue = React.useMemo(() => {
|
||||
if (chakras) {
|
||||
if (chakraChild) {
|
||||
return null
|
||||
}
|
||||
|
||||
@ -287,11 +293,7 @@ export const Thingtime = (props) => {
|
||||
} else {
|
||||
return "Something.."
|
||||
}
|
||||
}, [thing, thingDep, type, chakras, keys])
|
||||
|
||||
const hasChakraChildren = React.useMemo(() => {
|
||||
return !props?.edit && chakra && render && thing?.children
|
||||
}, [chakra, props?.edit, render, thing?.children])
|
||||
}, [thing, thingDep, type, chakraChild, keys])
|
||||
|
||||
const renderChakra = React.useMemo(() => {
|
||||
if (!props?.edit && chakra && render) {
|
||||
@ -366,7 +368,7 @@ export const Thingtime = (props) => {
|
||||
notRoot
|
||||
fullPath={fullPath + "." + key?.key}
|
||||
path={key}
|
||||
chakraChildren={chakra}
|
||||
chakraChild={chakra}
|
||||
thing={nextThing}
|
||||
// thing={{ infinite: { yes: true } }}
|
||||
valuePl={pl}
|
||||
@ -382,6 +384,8 @@ export const Thingtime = (props) => {
|
||||
|
||||
console.log("Thingtime is chakra", fullPath, chakra)
|
||||
|
||||
const rawChildren = thing?.rawChildren
|
||||
|
||||
try {
|
||||
if (ChakraComponent) {
|
||||
console.log(
|
||||
@ -393,6 +397,7 @@ export const Thingtime = (props) => {
|
||||
|
||||
const ret = (
|
||||
<ChakraComponent {...(thing?.props || {})}>
|
||||
{rawChildren}
|
||||
{inner}
|
||||
</ChakraComponent>
|
||||
)
|
||||
@ -406,7 +411,7 @@ export const Thingtime = (props) => {
|
||||
// TODO: Is it safe to spread props
|
||||
// because having props as a dependency will cause a re-render every time
|
||||
|
||||
if (props?.chakraChildren) {
|
||||
if (props?.chakraChild) {
|
||||
return inner
|
||||
}
|
||||
|
||||
@ -432,7 +437,7 @@ export const Thingtime = (props) => {
|
||||
circular,
|
||||
seen,
|
||||
type,
|
||||
props?.chakraChildren,
|
||||
props?.chakraChild,
|
||||
props?.path,
|
||||
props?.edit,
|
||||
chakra,
|
||||
@ -460,30 +465,34 @@ export const Thingtime = (props) => {
|
||||
}, [updateValue])
|
||||
|
||||
const onChangeType = React.useCallback(
|
||||
(type) => {
|
||||
const newType =
|
||||
type?.key || type?.value || type?.label || type?.icon || type
|
||||
(args) => {
|
||||
const { type, wrap } = args
|
||||
const typeValue =
|
||||
typeof type?.value === "function" ? type?.value() : type?.value
|
||||
|
||||
if (newType === "object") {
|
||||
updateValue({ value: {} })
|
||||
} else if (newType === "array") {
|
||||
updateValue({ value: [] })
|
||||
} else if (newType === "string") {
|
||||
updateValue({ value: "" })
|
||||
} else if (newType === "number") {
|
||||
updateValue({ value: 0 })
|
||||
} else if (newType === "boolean") {
|
||||
updateValue({ value: false })
|
||||
} else if (newType === "undefined") {
|
||||
updateValue({ value: undefined })
|
||||
} else if (newType === "null") {
|
||||
updateValue({ value: null })
|
||||
} else if (newType === "any") {
|
||||
updateValue({ value: null })
|
||||
} else {
|
||||
console.error("Unknown type", newType)
|
||||
if (type) {
|
||||
const wrapTarget = type?.wrap
|
||||
if (wrap && wrapTarget) {
|
||||
const newValue = append({
|
||||
thing: typeValue[wrapTarget],
|
||||
value: thing,
|
||||
})
|
||||
typeValue[wrapTarget] = newValue
|
||||
if (typeValue) {
|
||||
updateValue({ value: typeValue })
|
||||
}
|
||||
} else {
|
||||
updateValue({ value: typeValue })
|
||||
}
|
||||
}
|
||||
},
|
||||
[updateValue, thing, append, fullPath]
|
||||
)
|
||||
|
||||
const onWrapType = React.useCallback(
|
||||
(type) => {
|
||||
// nothing
|
||||
},
|
||||
[updateValue]
|
||||
)
|
||||
|
||||
@ -704,7 +713,7 @@ export const Thingtime = (props) => {
|
||||
const pathRef = React.useRef(null)
|
||||
|
||||
const pathDom = React.useMemo(() => {
|
||||
if (chakras) {
|
||||
if (chakraChild) {
|
||||
return <></>
|
||||
}
|
||||
|
||||
@ -726,7 +735,7 @@ export const Thingtime = (props) => {
|
||||
</>
|
||||
)
|
||||
}
|
||||
}, [renderedPath, pl, chakras, props?.edit, props?.pathPl])
|
||||
}, [renderedPath, pl, chakraChild, props?.edit, props?.pathPl])
|
||||
|
||||
const handleMouseEvent = React.useCallback(
|
||||
(e) => {
|
||||
@ -740,33 +749,73 @@ export const Thingtime = (props) => {
|
||||
[uuid]
|
||||
)
|
||||
|
||||
const addNewChild = React.useCallback(() => {
|
||||
const newChild = null
|
||||
const addNewChild = React.useCallback(
|
||||
(args) => {
|
||||
const { type } = args
|
||||
const newChild =
|
||||
typeof type?.value === "function" ? type?.value() : type?.value || null
|
||||
|
||||
if (thing instanceof Array) {
|
||||
// add new child to array
|
||||
const newValue = [...thing, newChild]
|
||||
setThingtime(fullPath, newValue)
|
||||
return
|
||||
}
|
||||
if (thing instanceof Array) {
|
||||
// add new child to array
|
||||
const newValue = [...thing, newChild]
|
||||
setThingtime(fullPath, newValue)
|
||||
return
|
||||
}
|
||||
|
||||
const newChildBasePath = "New Value"
|
||||
// find increment that thing doesn't already have New Value N+1
|
||||
let increment = 0
|
||||
let newPath = newChildBasePath
|
||||
while (Object.hasOwnProperty.call(thing, newPath) && increment <= 999) {
|
||||
increment++
|
||||
newPath = newChildBasePath + " " + increment
|
||||
}
|
||||
const newChildPath = newPath
|
||||
const newChildFullPath = fullPath + "." + newChildPath
|
||||
// create new child on thing using setThingtime
|
||||
setThingtime(newChildFullPath, newChild)
|
||||
}, [fullPath, setThingtime, thing])
|
||||
const newChildBasePath = "New Value"
|
||||
// find increment that thing doesn't already have New Value N+1
|
||||
let increment = 0
|
||||
let newPath = newChildBasePath
|
||||
while (Object.hasOwnProperty.call(thing, newPath) && increment <= 999) {
|
||||
increment++
|
||||
newPath = newChildBasePath + " " + increment
|
||||
}
|
||||
const newChildPath = newPath
|
||||
const newChildFullPath = fullPath + "." + newChildPath
|
||||
// create new child on thing using setThingtime
|
||||
setThingtime(newChildFullPath, newChild)
|
||||
},
|
||||
[fullPath, setThingtime, thing]
|
||||
)
|
||||
|
||||
const [showContextIcon, setShowContextIcon] = React.useState(false)
|
||||
const [showNewContextIcon, setShowNewContextIcon] = React.useState(false)
|
||||
|
||||
if (props?.chakraChildren) {
|
||||
// should be absolute last
|
||||
React.useEffect(() => {
|
||||
try {
|
||||
window.meta.things[uuid] = {
|
||||
thing: props?.thing,
|
||||
props,
|
||||
state: {
|
||||
chakra,
|
||||
chakraChild,
|
||||
circular,
|
||||
depth,
|
||||
fullPath,
|
||||
parent,
|
||||
parentPath,
|
||||
path,
|
||||
},
|
||||
}
|
||||
} catch {
|
||||
// nothing
|
||||
}
|
||||
}, [
|
||||
thing,
|
||||
props,
|
||||
uuid,
|
||||
chakra,
|
||||
chakraChild,
|
||||
circular,
|
||||
depth,
|
||||
fullPath,
|
||||
parent,
|
||||
parentPath,
|
||||
path,
|
||||
])
|
||||
|
||||
if (chakra || chakraChild) {
|
||||
return thingtimeChildren
|
||||
}
|
||||
|
||||
@ -790,7 +839,7 @@ export const Thingtime = (props) => {
|
||||
data-path={props?.path}
|
||||
>
|
||||
{/* {uuid?.current} */}
|
||||
{!chakras && !chakra && (
|
||||
{!chakraChild && !chakra && (
|
||||
<Flex position="relative" flexDirection="row">
|
||||
<Flex
|
||||
alignItems="center"
|
||||
@ -824,7 +873,7 @@ export const Thingtime = (props) => {
|
||||
uuid={uuid}
|
||||
fullPath={fullPath}
|
||||
readonly={!props?.edit}
|
||||
onChangeType={onChangeType}
|
||||
onType={onChangeType}
|
||||
onDelete={deleteValue}
|
||||
></SettingsMenu>
|
||||
</Flex>
|
||||
@ -848,14 +897,37 @@ export const Thingtime = (props) => {
|
||||
{thingtimeChildren}
|
||||
{!render && type === "object" && (
|
||||
<Flex
|
||||
position="relative"
|
||||
width="100%"
|
||||
paddingLeft={multiplyPl(2)}
|
||||
opacity={props?.edit ? 1 : 0}
|
||||
cursor="pointer"
|
||||
transition="all 0.2s ease-out"
|
||||
onClick={addNewChild}
|
||||
onMouseEnter={() => {
|
||||
setShowFullPathContext(true)
|
||||
setShowNewContextIcon(true)
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setShowFullPathContext(false)
|
||||
setShowNewContextIcon(false)
|
||||
}}
|
||||
paddingY={2}
|
||||
>
|
||||
<Flex
|
||||
position="absolute"
|
||||
bottom="100%"
|
||||
left={0}
|
||||
display={showFullPathContext ? "flex" : "none"}
|
||||
fontSize="sm"
|
||||
background="greys.light"
|
||||
borderRadius={6}
|
||||
pointerEvents="none"
|
||||
paddingX={3}
|
||||
paddingY={1}
|
||||
>
|
||||
{fullPath}
|
||||
</Flex>
|
||||
<Icon
|
||||
_focus={{
|
||||
outline: "none !important",
|
||||
@ -870,6 +942,25 @@ export const Thingtime = (props) => {
|
||||
size={10}
|
||||
name="seedling"
|
||||
></Icon>
|
||||
<Flex
|
||||
marginLeft={2}
|
||||
onClick={(e) => {
|
||||
e?.preventDefault()
|
||||
e?.stopPropagation()
|
||||
e?.nativeEvent?.stopImmediatePropagation()
|
||||
}}
|
||||
>
|
||||
<SettingsMenu
|
||||
transition="all 0.2s ease-in-out"
|
||||
opacity={showNewContextIcon ? 1 : 0}
|
||||
uuid={uuid}
|
||||
iconSize={10}
|
||||
fullPath={fullPath}
|
||||
readonly={!props?.edit}
|
||||
onType={addNewChild}
|
||||
></SettingsMenu>
|
||||
</Flex>
|
||||
|
||||
{/* <Icon size={7} name="plus"></Icon>
|
||||
<Icon size={7} name="plus"></Icon> */}
|
||||
</Flex>
|
||||
|
@ -103,14 +103,14 @@ export const ThingtimeURL = (props) => {
|
||||
width="600px"
|
||||
// width="100%"
|
||||
maxHeight="100vh"
|
||||
paddingY={2}
|
||||
// paddingY={2}
|
||||
>
|
||||
<Thingtime
|
||||
path={path}
|
||||
thing={thing}
|
||||
render
|
||||
chakras={{ marginY: "200px" }}
|
||||
width="600px"
|
||||
// width="600px"
|
||||
></Thingtime>
|
||||
</Box>
|
||||
)}
|
||||
|
55
remix/app/hooks/usePath.tsx
Normal file
55
remix/app/hooks/usePath.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
import React from "react"
|
||||
import { useLocation } from "@remix-run/react"
|
||||
import { useNavigate } from "@remix-run/react"
|
||||
export const usePath = (props?: any) => {
|
||||
const location = useLocation()
|
||||
const { pathname } = location
|
||||
|
||||
const navigate = useNavigate()
|
||||
|
||||
const [mode, setMode] = React.useState("")
|
||||
|
||||
const modes = React.useMemo(() => {
|
||||
// make sure any substrings come first
|
||||
return [
|
||||
"edit",
|
||||
"editor",
|
||||
"code",
|
||||
"coder",
|
||||
"thing",
|
||||
"things",
|
||||
"thingtime",
|
||||
"thingtimes",
|
||||
]
|
||||
}, [])
|
||||
|
||||
React.useEffect(() => {
|
||||
let set = false
|
||||
modes.forEach((mode) => {
|
||||
const pathPart = pathname.slice(1, mode.length + 1)
|
||||
if (pathPart === mode) {
|
||||
setMode(mode)
|
||||
set = true
|
||||
}
|
||||
})
|
||||
// if (!set) {
|
||||
// setMode("things")
|
||||
// }
|
||||
}, [pathname, modes])
|
||||
|
||||
const changePath = React.useCallback(
|
||||
(props) => {
|
||||
const { path } = props
|
||||
|
||||
navigate(`${mode}/${path}`)
|
||||
},
|
||||
[navigate, mode]
|
||||
)
|
||||
|
||||
const ret = {
|
||||
mode,
|
||||
changePath,
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
34
remix/app/hooks/useThings.tsx
Normal file
34
remix/app/hooks/useThings.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import React from "react"
|
||||
|
||||
export const useThings = (props?: any) => {
|
||||
const append = React.useCallback((args) => {
|
||||
const { thing, value } = args
|
||||
|
||||
if (thing instanceof Array) {
|
||||
const newValue = [...thing, value]
|
||||
return newValue
|
||||
}
|
||||
|
||||
if (typeof thing === "object") {
|
||||
const newChildBasePath = "New Value"
|
||||
// find increment that thing doesn't already have New Value N+1
|
||||
let increment = 0
|
||||
let newPath = newChildBasePath
|
||||
while (Object.hasOwnProperty.call(thing, newPath) && increment <= 999) {
|
||||
increment++
|
||||
newPath = newChildBasePath + " " + increment
|
||||
}
|
||||
const newChildPath = newPath
|
||||
|
||||
const newValue = { ...thing }
|
||||
newValue[newChildPath] = value
|
||||
return newValue
|
||||
}
|
||||
}, [])
|
||||
|
||||
const ret = {
|
||||
append,
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
@ -68,7 +68,7 @@ const setThingtime = (glob) => {
|
||||
stats: {
|
||||
db: {},
|
||||
limit: 9999,
|
||||
maxDepth: 10,
|
||||
maxDepth: 99,
|
||||
count: 0,
|
||||
},
|
||||
things: {},
|
||||
|
@ -20,6 +20,7 @@
|
||||
"@vercel/analytics": "^0.1.11",
|
||||
"@vercel/remix": "^1.15.0",
|
||||
"draft-js": "^0.11.7",
|
||||
"emojis-list": "^3.0.0",
|
||||
"flatted": "^3.2.7",
|
||||
"fuse.js": "^6.6.2",
|
||||
"gradient-path": "^2.3.0",
|
||||
|
@ -44,6 +44,9 @@ dependencies:
|
||||
draft-js:
|
||||
specifier: ^0.11.7
|
||||
version: 0.11.7(react-dom@18.2.0)(react@18.2.0)
|
||||
emojis-list:
|
||||
specifier: ^3.0.0
|
||||
version: 3.0.0
|
||||
flatted:
|
||||
specifier: ^3.2.7
|
||||
version: 3.2.7
|
||||
@ -2572,6 +2575,7 @@ packages:
|
||||
|
||||
/@emotion/memoize@0.7.4:
|
||||
resolution: {integrity: sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==}
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
@ -4501,6 +4505,7 @@ packages:
|
||||
|
||||
/bindings@1.5.0:
|
||||
resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
file-uri-to-path: 1.0.0
|
||||
dev: true
|
||||
@ -5192,7 +5197,6 @@ packages:
|
||||
/emojis-list@3.0.0:
|
||||
resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==}
|
||||
engines: {node: '>= 4'}
|
||||
dev: true
|
||||
|
||||
/encodeurl@1.0.2:
|
||||
resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
|
||||
@ -6159,6 +6163,7 @@ packages:
|
||||
|
||||
/file-uri-to-path@1.0.0:
|
||||
resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
@ -7939,6 +7944,7 @@ packages:
|
||||
|
||||
/node-addon-api@1.7.2:
|
||||
resolution: {integrity: sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==}
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user