diff --git a/remix/.eslintrc.js b/remix/.eslintrc.js index d5a4569..3b51f1b 100644 --- a/remix/.eslintrc.js +++ b/remix/.eslintrc.js @@ -37,6 +37,8 @@ module.exports = { "error", { props: "never", children: "never" }, ], + "direct-eval/direct-eval": "off", + "no-eval": "off", "no-async-promise-executor": "off", "react/prop-types": "off", "react/display-name": "off", diff --git a/remix/app/Providers/Chakra/theme.tsx b/remix/app/Providers/Chakra/theme.tsx index b44a762..43567f3 100644 --- a/remix/app/Providers/Chakra/theme.tsx +++ b/remix/app/Providers/Chakra/theme.tsx @@ -1,5 +1,6 @@ -import { extendTheme } from '@chakra-ui/react' -import { colors } from './colors' +import { extendTheme, Select, Switch } from "@chakra-ui/react" + +import { colors } from "./colors" export const theme = extendTheme({ colors, @@ -7,51 +8,100 @@ export const theme = extendTheme({ styles: { global: { // make all elements padding and margin animate - '*': { - transition: 'padding 0.2s ease, margin 0.2s ease' + "*": { + transition: "padding 0.2s ease, margin 0.2s ease", }, // make all elements have a transparent focus border - 'input:focus': { - boxShadow: 'none !important', - borderColor: 'transparent !important' + "input:focus": { + boxShadow: "none !important", + borderColor: "transparent !important", }, // make all elements have a transparent focus border - 'textarea:focus': { - boxShadow: 'none !important', - borderColor: 'transparent !important' + "textarea:focus": { + boxShadow: "none !important", + borderColor: "transparent !important", }, // make all elements have a transparent focus border - 'select:focus': { - boxShadow: 'none !important', - borderColor: 'transparent !important' + "select:focus": { + boxShadow: "none !important", + borderColor: "transparent !important", }, // make all elements have a transparent focus border - 'button:focus': { - boxShadow: 'none !important', - borderColor: 'transparent !important' + "button:focus": { + boxShadow: "none !important", + borderColor: "transparent !important", }, // make all elements have a transparent focus border - 'div:focus': { - boxShadow: 'none !important', - borderColor: 'transparent !important' + "div:focus": { + boxShadow: "none !important", + borderColor: "transparent !important", }, // make all elements have a transparent focus border - 'a:focus': { - boxShadow: 'none !important', - borderColor: 'transparent !important' + "a:focus": { + boxShadow: "none !important", + borderColor: "transparent !important", }, // make all elements have a transparent focus border - 'span:focus': { - boxShadow: 'none !important', - borderColor: 'transparent !important' - } - } + "span:focus": { + boxShadow: "none !important", + borderColor: "transparent !important", + }, + }, }, components: { Input: { defaultProps: { - focusBorderColor: 'transparent' - } - } - } + // focusBorderColor: "transparent", + // outline: "0px solid", + // border: "0px solid", + }, + baseStyle: { + // "padding-inline-start": "0px", + field: { + // "padding-inline-start": "0px", + }, + }, + }, + Select: { + baseStyle: { + field: { + // "padding-inline-start": "0px", + }, + icon: { + // height: "8px", + width: "14px", + }, + }, + }, + Switch: { + baseStyle: { + track: { + background: "grays.medium", + _checked: { + background: "chakras.throat", + }, + }, + }, + }, + }, }) + +console.log("nik Select", Select) + +Switch.defaultProps = { + ...Switch.defaultProps, + as: "div", +} + +Select.defaultProps = { + ...Select.defaultProps, + focusBorderColor: "transparent", + outline: "0px solid", + border: "none", + ps: "0px", + px: "0px", + sx: { + paddingInlineStart: "0px", + paddingInlineEnd: "24px", + }, +} diff --git a/remix/app/Providers/ThingtimeProvider.tsx b/remix/app/Providers/ThingtimeProvider.tsx index 40fae90..7ac29c2 100644 --- a/remix/app/Providers/ThingtimeProvider.tsx +++ b/remix/app/Providers/ThingtimeProvider.tsx @@ -105,10 +105,15 @@ export const ThingtimeProvider = (props: any): JSX.Element => { ...prevThingtime, } + newThingtime.tt = newThingtime + newThingtime.thingtime = newThingtime + // check if first characters of path starts with thingtime or tt and strip from path // path = sanitise(path) + console.log("nik setting newThingtime value at path", path, value) + smarts.setsmart(newThingtime, path, value) // subtract last path part from dot delimitted path @@ -118,6 +123,7 @@ export const ThingtimeProvider = (props: any): JSX.Element => { const parentPath = pathParts.join(".") if (parentPath?.length) { + console.log("nik updating parentPath dependancies", parentPath) const parent = smarts.getsmart(newThingtime, parentPath) const newParent = Array.isArray(parent) ? [...parent] : { ...parent } @@ -127,7 +133,7 @@ export const ThingtimeProvider = (props: any): JSX.Element => { set(newThingtime) }, - [thingtime] + [thingtime, set] ) const getThingtime = React.useCallback( @@ -137,6 +143,7 @@ export const ThingtimeProvider = (props: any): JSX.Element => { // do we need to sanitise? // const path = sanitise(rawPath) console.log("Getting thingtime at path", path) + // console.trace("Getting thingtime at path", path) return smarts.getsmart(thingtime, path) }, [thingtime] @@ -221,10 +228,10 @@ export const ThingtimeProvider = (props: any): JSX.Element => { } else { try { console.log("Setting thingtime to localStorage", thingtime) - setTimeout(() => { - const stringified = stringify(thingtime) - window.localStorage.setItem("thingtime", stringified) - }, 600) + // setTimeout(() => { + const stringified = stringify(thingtime) + window.localStorage.setItem("thingtime", stringified) + // }, 600) } catch (err) { console.error("There was an error saving thingtime to localStorage") } diff --git a/remix/app/components/Commander/Commander.tsx b/remix/app/components/Commander/Commander.tsx index f3b94f9..d0bd627 100644 --- a/remix/app/components/Commander/Commander.tsx +++ b/remix/app/components/Commander/Commander.tsx @@ -197,11 +197,13 @@ export const Commander = (props) => { const closeCommander = React.useCallback( (e?: any) => { - console.log("nik e", e) - if (thingtime?.settings?.commanderActive) { - console.log("nik commander closing commander") - console.log("nik setting commanderActive to false") - setThingtime("settings.commanderActive", false) + if (!e?.defaultPrevented) { + console.log("nik 123123 commander event closeCommander ", e) + if (thingtime?.settings?.commanderActive) { + console.log("nik commander closing commander") + console.log("nik setting commanderActive to false") + setThingtime("settings.commanderActive", false) + } } }, [setThingtime, thingtime?.settings?.commanderActive] @@ -267,18 +269,46 @@ export const Commander = (props) => { if (commandIsAction) { // nothing try { - const fn = `() => { return ${escapedCommandValue} }` + // first try to execute literal javscript + const fn = `() => { return ${commandValue} }` const evalFn = eval(fn) const realVal = evalFn() const prevVal = getThingtime(commandPath) const parentPath = getParentPath(commandPath) + console.log("nik realVal", realVal) + console.log("nik prevVal", prevVal) + console.log("nik parentPath", parentPath) + console.log("nik commandPath", commandPath) setThingtime(commandPath, realVal) if (!prevVal) { setContextPath(parentPath) setShowContext(true, "commandIsAction check") } } catch (err) { - console.log("setThingtime errored in Commander", err) + console.log( + "Caught error after trying to execute literal javascript", + err + ) + + // likely literaly javascript wasn't valid + try { + const fn = `() => { return ${escapedCommandValue} }` + const evalFn = eval(fn) + const realVal = evalFn() + const prevVal = getThingtime(commandPath) + const parentPath = getParentPath(commandPath) + setThingtime(commandPath, realVal) + if (!prevVal) { + setContextPath(parentPath) + setShowContext(true, "commandIsAction check") + } + } catch { + // something very bad went wrong + console.log( + "Caught error after trying to execute escaped literal javascript", + err + ) + } } } else if (commandContainsPath) { // const prevValue = getThingtime(commandPath) @@ -305,6 +335,7 @@ export const Commander = (props) => { commandIsAction, commandContainsPath, commandPath, + commandValue, escapedCommandValue, getThingtime, setThingtime, diff --git a/remix/app/components/Icon/Icon.tsx b/remix/app/components/Icon/Icon.tsx index d226308..6211597 100644 --- a/remix/app/components/Icon/Icon.tsx +++ b/remix/app/components/Icon/Icon.tsx @@ -1,22 +1,59 @@ import React from "react" import { Center } from "@chakra-ui/react" -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" export const Icon = (props) => { - const icon = React.useMemo(() => { - if (props?.name === "gear") { - return { - prefix: "fas", - iconName: props?.name, - } - } + const name = props?.name - return props?.name - }, [props?.name]) + const icon = React.useMemo(() => { + // nothing + if (["gear", "cog"]?.includes(name)) { + return "⚙️" + } + if (["crystal"]?.includes(name)) { + return "🔮" + } + if (["sparke", "magic"]?.includes(name)) { + return "✨" + } + if (["box", "thing", "object"]?.includes(name)) { + return "📦" + } + if (["book", "books"]?.includes(name)) { + return "📚" + } + if (["book-open", "books-open"]?.includes(name)) { + return "📖" + } + if (["book-reader", "books-reader"]?.includes(name)) { + return "👩‍🏫" + } + if (["number", "hundred"]?.includes(name)) { + return "💯" + } + if (["heart"]?.includes(name)) { + return "❤️" + } + if (["heart-broken"]?.includes(name)) { + return "💔" + } + if (["heart-pulse"]?.includes(name)) { + return "💗" + } + if (["string", "text"]?.includes(name)) { + return "💬" + } + if (["array", "list"]?.includes(name)) { + return "📚" + } + if (["boolean", "bool"]?.includes(name)) { + return "🌗" + // return "⚖️" + } + }, [name]) return ( -
- +
+ {icon}
) } diff --git a/remix/app/components/Thingtime/Thingtime.tsx b/remix/app/components/Thingtime/Thingtime.tsx index 573d24b..8e71c5a 100644 --- a/remix/app/components/Thingtime/Thingtime.tsx +++ b/remix/app/components/Thingtime/Thingtime.tsx @@ -1,5 +1,5 @@ import React from "react" -import { Box, Flex } from "@chakra-ui/react" +import { Box, Flex, Select, Switch } from "@chakra-ui/react" import { Icon } from "../Icon/Icon" import { Safe } from "../Safety/Safe" @@ -10,7 +10,7 @@ export const Thingtime = (props) => { // and add button to expand circular reference // up to 1 level deep - const { thingtime } = useThingtime() + const { thingtime, setThingtime } = useThingtime() const [uuid, setUuid] = React.useState() @@ -73,6 +73,23 @@ export const Thingtime = (props) => { return typeof thing }, [thing]) + const typeIcon = React.useMemo(() => { + const size = 7 + if (thing instanceof Array) { + return + } else if (type === "object") { + return + } else if (type === "string") { + return + } else if (type === "number") { + return + } else if (type === "boolean") { + return + } else { + return + } + }, [type, thing]) + const valuePl = React.useMemo(() => { if (typeof props?.valuePl === "number") { return props?.valuePl @@ -124,7 +141,7 @@ export const Thingtime = (props) => { return ["view", "edit"] }, []) - const value = React.useMemo(() => { + const thingtimeChildren = React.useMemo(() => { if (template1Modes?.includes(mode)) { if (keys?.length && !circular) { return ( @@ -155,13 +172,17 @@ export const Thingtime = (props) => { nextSeen.push(nextThing) } + const fullPath = props?.fullPath || props?.path + return ( { template1Modes, ]) - const editableValue = React.useMemo(() => { - if (template1Modes?.includes(mode)) { + const AtomicWrapper = React.useCallback( + (props) => { return ( - - {renderableValue} - + {props?.children} + ) + }, + [pl] + ) + + const updateValue = React.useCallback( + (args) => { + const { value } = args + + console.log("nik value", value) + console.log("nik props?.fullPath", props?.fullPath) + + setThingtime(props?.fullPath, value) + }, + [props?.fullPath, setThingtime] + ) + + const atomicValue = React.useMemo(() => { + if (props?.edit) { + if (type === "boolean") { + return ( + + { + e?.preventDefault?.() + e?.stopPropagation?.() + // cancel bubble + e?.nativeEvent?.stopImmediatePropagation?.() + console.log("nik 123123 clicked", !thing) + setTimeout(() => { + updateValue({ value: !thing }) + console.log("nik 123123 changed", e) + }, 1) + }} + > + + + {/* */} + + ) + } } - }, [renderableValue, mode, template1Modes, pl]) + return {renderableValue} + }, [renderableValue, AtomicWrapper, type, props?.edit, thing, updateValue]) const contextMenu = ( { }, [props?.path]) const renderedPath = React.useMemo(() => { + if (props?.edit) { + return humanPath + } + if (humanPath?.includes?.("hidden")) { return null } @@ -238,19 +313,21 @@ export const Thingtime = (props) => { } return humanPath - }, [humanPath]) + }, [humanPath, props?.edit]) - const path = React.useMemo(() => { - return ( - - {renderedPath} - - ) + const pathDom = React.useMemo(() => { + if (renderedPath) { + return ( + + {renderedPath} + + ) + } }, [renderedPath, pl, props?.pathPl]) const handleMouseEvent = React.useCallback( @@ -265,6 +342,8 @@ export const Thingtime = (props) => { [uuid] ) + const [showContextIcon, setShowContextIcon] = React.useState(false) + return ( { > {/* {uuid?.current} */} - {path} - - + setShowContextIcon(true)} + onMouseLeave={() => setShowContextIcon(false)} + > + {pathDom} + {props?.edit && ( + + {typeIcon} + + )} + {pathDom && ( + + + + )} {/* {showContextMenu && contextMenu} */} - {!value && editableValue} - {value} + {!thingtimeChildren && atomicValue} + {thingtimeChildren} ) diff --git a/remix/app/routes/things$.tsx b/remix/app/components/Thingtime/ThingtimeURL.tsx similarity index 54% rename from remix/app/routes/things$.tsx rename to remix/app/components/Thingtime/ThingtimeURL.tsx index 058c511..149d685 100644 --- a/remix/app/routes/things$.tsx +++ b/remix/app/components/Thingtime/ThingtimeURL.tsx @@ -1,15 +1,11 @@ import React from "react" -import { Box, Flex } from "@chakra-ui/react" +import { Flex } from "@chakra-ui/react" import { useMatches } from "@remix-run/react" -import { ProfileDrawer } from "~/components/Nav/ProfileDrawer" -import { Splash } from "~/components/Splash/Splash" -import { Thingtime } from "~/components/Thingtime/Thingtime" -import { ThingtimeDemo } from "~/components/Thingtime/ThingtimeDemo" -import { useThingtime } from "~/components/Thingtime/useThingtime" -import { GradientPath } from "~/gp/GradientPath" +import { Thingtime } from "./Thingtime" +import { useThingtime } from "./useThingtime" -export default function Index() { +export const ThingtimeURL = (props) => { const { getThingtime } = useThingtime() const matches = useMatches() @@ -18,11 +14,12 @@ export default function Index() { }, [matches]) const path = React.useMemo(() => { - const pathStepOne = location?.pathname?.replace("/things/", "") + const pathPartOne = location?.params?.["*"] + + const path = pathPartOne?.replace(/\//g, ".") - const path = pathStepOne?.replace(/\//g, ".") return path - }, [location?.pathname]) + }, [location]) const thing = React.useMemo(() => { // remove /things/ from path @@ -40,12 +37,12 @@ export default function Index() { maxWidth="100%" > - ) } diff --git a/remix/app/hooks/useIcons.tsx b/remix/app/hooks/useIcons.tsx new file mode 100644 index 0000000..0e58af3 --- /dev/null +++ b/remix/app/hooks/useIcons.tsx @@ -0,0 +1,8 @@ +import { library } from "@fortawesome/fontawesome-svg-core" +import { fas } from "@fortawesome/free-solid-svg-icons" + +library.add(fas) + +export const useIcons = () => { + return null +} diff --git a/remix/app/root.tsx b/remix/app/root.tsx index 30a7a7d..e21c531 100644 --- a/remix/app/root.tsx +++ b/remix/app/root.tsx @@ -10,6 +10,7 @@ import { import { Analytics } from "@vercel/analytics/react" import { Main } from "./components/Layout/Main" +import { useIcons } from "./hooks/useIcons" import { ChakraWrapper } from "./Providers/Chakra/ChakraWrapper" import { ThingtimeProvider } from "./Providers/ThingtimeProvider" @@ -41,6 +42,8 @@ function Document({ } export default function App() { + useIcons() + return ( diff --git a/remix/app/routes/edit/*.tsx b/remix/app/routes/edit/*.tsx new file mode 100644 index 0000000..83490fa --- /dev/null +++ b/remix/app/routes/edit/*.tsx @@ -0,0 +1,7 @@ +import React from "react" + +import { ThingtimeURL } from "~/components/Thingtime/ThingtimeURL" + +export default function Index() { + return +} diff --git a/remix/app/routes/things/*.tsx b/remix/app/routes/things/*.tsx new file mode 100644 index 0000000..fa8b6d0 --- /dev/null +++ b/remix/app/routes/things/*.tsx @@ -0,0 +1,7 @@ +import React from "react" + +import { ThingtimeURL } from "~/components/Thingtime/ThingtimeURL" + +export default function Index() { + return +} diff --git a/remix/package.json b/remix/package.json index 3286425..098cf28 100644 --- a/remix/package.json +++ b/remix/package.json @@ -26,6 +26,7 @@ "react": "^18.2.0", "react-click-away-listener": "^2.2.3", "react-dom": "^18.2.0", + "react-icons": "^4.10.1", "tinygradient": "^1.1.5", "uuid": "^9.0.0" }, diff --git a/remix/pnpm-lock.yaml b/remix/pnpm-lock.yaml index 2d79b98..e63cc1d 100644 --- a/remix/pnpm-lock.yaml +++ b/remix/pnpm-lock.yaml @@ -59,6 +59,9 @@ dependencies: react-dom: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) + react-icons: + specifier: ^4.10.1 + version: 4.10.1(react@18.2.0) tinygradient: specifier: ^1.1.5 version: 1.1.5 @@ -8566,6 +8569,14 @@ packages: use-sidecar: 1.1.2(@types/react@18.0.28)(react@18.2.0) dev: false + /react-icons@4.10.1(react@18.2.0): + resolution: {integrity: sha512-/ngzDP/77tlCfqthiiGNZeYFACw85fUjZtLbedmJ5DTlNDIwETxhwBzdOJ21zj4iJdvc0J3y7yOsX3PpxAJzrw==} + peerDependencies: + react: '*' + dependencies: + react: 18.2.0 + dev: false + /react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}