feature/random-nik-things

This commit is contained in:
Nikolaj Frey 2024-07-16 17:11:03 +08:00
parent e77fe17675
commit 990cd108bd
10 changed files with 403 additions and 120 deletions

2
.gitignore vendored
View File

@ -3,6 +3,8 @@
.env
app/node_modules
remix/node_modules
next/node_modules
app-next/node_modules
api/node_modules
node_modules

View File

@ -93,7 +93,6 @@
"title": "Commander",
"description": "Open Thingtime Commander",
"mode": "view",
"fallbackText": "test2",
"keywords": [
"commander",
"thingtime",
@ -107,7 +106,38 @@
"key": "name",
"title": "Name of Command to run",
"description": "The name of the command/function to run",
"defaultValue": "Menu"
"defaultValue": "MagicInput"
}
]
},
{
"name": "commanderMagicInput",
"title": "Magic Input",
"description": "Evaluates a Magic Input",
"mode": "no-view",
"keywords": [
"commander",
"thingtime",
"ai"
],
"arguments": [
{
"placeholder": "Path",
"name": "path",
"type": "text",
"description": "The path to open the new finder window at",
"required": false
}
],
"preferences": [
{
"name": "name",
"required": false,
"type": "textfield",
"key": "name",
"title": "Name of Command to run",
"description": "The name of the command/function to run",
"defaultValue": "openNewFinderWindow"
}
]
},
@ -116,7 +146,6 @@
"title": "Open New Finder Window",
"description": "Open new finder window",
"mode": "no-view",
"fallbackText": "test2",
"keywords": [
"commander",
"thingtime",
@ -148,7 +177,6 @@
"title": "Trim image",
"description": "Will trim all whitespace from an image",
"mode": "no-view",
"fallbackText": "test2",
"keywords": [
"commander",
"thingtime",
@ -171,7 +199,6 @@
"title": "mp4 to mp3",
"description": "Converts an mp4 into an mp3 using ffmpeg at 320Kbps",
"mode": "no-view",
"fallbackText": "test2",
"keywords": [
"commander",
"thingtime",

View File

@ -0,0 +1,11 @@
import { Box, Heading } from '@chakra-ui/react';
import { Logo } from './Logo';
export const Branding = () => {
return (
<Box w="100%" px={'18px'} maxW={'container'} textAlign={'left'}>
<Heading>Branding</Heading>
<Logo />
</Box>
);
};

View File

@ -0,0 +1,87 @@
import { Box, Center, Flex, Slider, SliderFilledTrack, SliderThumb, SliderTrack } from '@chakra-ui/react';
import React, { useMemo, useState } from 'react';
export const Logo = () => {
// a completely dynamic and interactive logo
// uses borders, border radius, and colour themes to create a simple timeless beautiful logo
// const defaultThemeRaw = ['white', '#F20009', '#FD5F00', '#FFEB03', '#52E013', '#09A7EC', '#982E77', 'white'];
const defaultThemeRaw = ['#F20009', '#FD5F00', '#FFEB03', '#52E013', '#09A7EC', '#982E77', 'white'];
const [reverseColours, setReverseColours] = useState(false);
const defaultTheme = reverseColours ? defaultThemeRaw?.reverse() : defaultThemeRaw;
const [theme, setTheme] = useState('blue');
const [squares, setSquares] = useState(9);
const [width, setWidth] = useState(250);
const [height, setHeight] = useState(250);
// logo is a T/plus shape made of two intersecting squares
// you can toggle border sides on both squares to create different shapes
const [borderWidth, setBorderWidth] = useState(18);
const [borderRadius, setBorderRadius] = useState(12);
const squaresArray = Array.from({ length: squares }, (_, index) => index);
const [spacing, setSpacing] = useState(borderWidth);
// log squaresArray
console.debug('tt.squaresArray', squaresArray);
// basically the 5 squares that make up a plus but with the centre one missing
const [divisions, setDivisions] = useState(3);
const [divisionHeight, setDivisionHeight] = useState(100 / divisions);
const [divisionWidth, setDivisionWidth] = useState(100 / divisions);
const uuid = useMemo(() => {
return Math.random().toString(36).substring(2) + Date.now().toString(36);
}, []);
return (
<>
{/* these are the controls */}
{/* border radius use chakra slider */}
<Center py={12}>
<Slider aria-label="slider-ex-1" defaultValue={borderRadius} onChange={setBorderRadius}>
<SliderTrack>
<SliderFilledTrack />
</SliderTrack>
<SliderThumb>🟡</SliderThumb>
</Slider>
</Center>
<Box className="tt.logo" overflow="hidden" w={width + 'px'} h={height + 'px'} position="relative">
{squaresArray.map((_, idx) => {
// technically not even in programming terms cause it starts at 0 😂
const humanIdx = idx + 1;
const even = humanIdx % 2 === 0;
const colourIndex = Math.round(idx / 2);
// log the colourIndex
console.debug('tt.colourIndex', colourIndex);
return (
<Box
display="inline-block"
key={`logo-${uuid}-${idx}`}
bg={even ? defaultTheme[colourIndex] : 'rgba(0,0,0,0)'}
w={`${divisionHeight}%`}
h={`${divisionWidth}%`}
></Box>
);
})}
</Box>
</>
);
};

View File

@ -0,0 +1,129 @@
import { Box, Center, Flex, Slider, SliderFilledTrack, SliderThumb, SliderTrack } from '@chakra-ui/react';
import React, { useState } from 'react';
export const LogoOld2 = () => {
// a completely dynamic and interactive logo
// uses borders, border radius, and colour themes to create a simple timeless beautiful logo
// const defaultThemeRaw = ['white', '#F20009', '#FD5F00', '#FFEB03', '#52E013', '#09A7EC', '#982E77', 'white'];
const defaultThemeRaw = ['#F20009', '#FD5F00', '#FFEB03', '#52E013', '#09A7EC', '#982E77', 'white'];
const [reverseColours, setReverseColours] = useState(false);
const defaultTheme = reverseColours ? defaultThemeRaw?.reverse() : defaultThemeRaw;
const [theme, setTheme] = useState('blue');
const [squares, setSquares] = useState(8);
const [width, setWidth] = useState(50);
const [height, setHeight] = useState(50);
// logo is a T/plus shape made of two intersecting squares
// you can toggle border sides on both squares to create different shapes
const [borderWidth, setBorderWidth] = useState(18);
const [borderRadius, setBorderRadius] = useState(12);
const squaresArray = Array.from({ length: squares }, (_, index) => index);
const [spacing, setSpacing] = useState(borderWidth);
// log squaresArray
console.debug('tt.squaresArray', squaresArray);
return (
<>
{/* these are the controls */}
{/* border radius use chakra slider */}
<Center py={12}>
<Slider aria-label="slider-ex-1" defaultValue={borderRadius} onChange={setBorderRadius}>
<SliderTrack>
<SliderFilledTrack />
</SliderTrack>
<SliderThumb>🟡</SliderThumb>
</Slider>
</Center>
<Center overflow="hidden" w={width} h={height} position="relative">
{/* border top left squares */}
{squaresArray.map((_, index) => {
const top = index * spacing;
const left = index * spacing;
const colour = defaultTheme[index];
const square = (
<Box
zIndex={2}
backgroundColor={colour}
borderRadius={`${borderRadius}px`}
className="logo-square"
position={'absolute'}
width={width}
top={12}
left={12}
height={height}
transform={`translateY(${top}px) translateX(${left}px)`}
>
{/* another box which acts as a mask */}
{/* <Box
backgroundColor={theme}
borderRadius={`${borderRadius}px`}
className="logo-square"
position={'absolute'}
width={width}
top={12}
left={12}
height={height}
top={`${top}px`}
left={`${left}px`}
/> */}
</Box>
);
return square;
})}
{/* make squares for bottom right */}
{squaresArray.map((_, index) => {
const bottom = index * spacing + height * 2;
const right = index * spacing + width * 2;
const colour = defaultTheme[index];
const square = (
<Box
zIndex={1}
backgroundColor={colour}
borderRadius={`${borderRadius}px`}
className="logo-square"
position={'absolute'}
width={width}
top={14}
left={14}
height={height}
transform={`translateY(${-bottom}px) translateX(${-right}px)`}
>
{/* another box which acts as a mask */}
{/* <Box
backgroundColor={theme}
borderRadius={`${borderRadius}px`}
className="logo-square"
position={'absolute'}
width={width}
height={height}
top={`${top}px`}
left={`${left}px`}
/> */}
</Box>
);
return square;
})}
</Center>
</>
);
};

View File

@ -8,8 +8,8 @@ export const Editor = (props) => {
return (
<>
<Box minH="60vh" w="100%" maxW={'container'} pos={'relative'}>
{/* only on client side render editor */}
<Flex position="absolute" w={width} h={height} top={0} left={0} right={0} bottom={0}>
{/* only on client side render editor */}
<Suspense fallback={<div>Loading...</div>}>
<MonacoEditor defaultLanguage={defaultLanguage} defaultValue={defaultValue} />
</Suspense>

View File

@ -136,11 +136,11 @@ export const Nav = (props) => {
</Center>
)}
{/* TODO - Add conditional only show if loggedIn */}
<Center transform={['', 'scaleX(-100%)']} cursor="pointer">
{/* <Center transform={['', 'scaleX(-100%)']} cursor="pointer">
<Link to="/logout">
<Icon size="12px" name="🗝️"></Icon>
</Link>
</Center>
</Center> */}
<Center transform={['', 'scaleX(-100%)']} cursor="pointer">
<Link to="/login">
<Icon size="12px" name="🌈"></Icon>

View File

@ -1,146 +1,143 @@
import React, { useState } from "react"
import ClickAwayListener from "react-click-away-listener"
import { Center, Flex, Text } from "@chakra-ui/react"
import React, { useState } from 'react';
import ClickAwayListener from 'react-click-away-listener';
import { Center, Flex, Text } from '@chakra-ui/react';
import { Icon } from "../Icon/Icon"
import { useThingtime } from "./useThingtime"
import { Icon } from '../Icon/Icon';
import { useThingtime } from './useThingtime';
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 [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,
})
pinStatus
});
React.useEffect(() => {
stateRef.current.pinStatus = pinStatus
}, [pinStatus])
stateRef.current.pinStatus = pinStatus;
}, [pinStatus]);
const { thingtime, events } = useThingtime()
const { thingtime, events } = useThingtime();
const opacityRef = React.useRef(null)
const opacityRef = React.useRef(null);
const waitTime = 1555
const waitTime = 1555;
const [uuid, setUuid] = React.useState(null)
const [uuid, setUuid] = React.useState(null);
React.useEffect(() => {
setUuid(Math.random().toString(36).substring(7))
}, [])
setUuid(Math.random().toString(36).substring(7));
}, []);
React.useEffect(() => {
const subscription = events.subscribe((event) => {
if (event?.type === "settings-menu-hide" && event?.uuid !== uuid) {
if (event?.type === 'settings-menu-hide' && event?.uuid !== uuid) {
if (!stateRef?.current?.pinStatus || event?.force) {
setShow(false)
setOpacity(0)
setShow(false);
setOpacity(0);
}
}
})
});
return () => {
subscription?.unsubscribe?.()
}
}, [events, uuid])
subscription?.unsubscribe?.();
};
}, [events, uuid]);
React.useEffect(() => {
clearInterval(opacityRef?.current)
clearInterval(opacityRef?.current);
if (props?.opacity) {
setOpacity(props?.opacity)
setOpacity(props?.opacity);
} else {
opacityRef.current = setInterval(() => {
if (!stateRef?.current?.pinStatus) {
setOpacity(props?.opacity)
setShow(false)
setOpacity(props?.opacity);
setShow(false);
}
}, waitTime)
}, waitTime);
}
}, [props?.opacity])
}, [props?.opacity]);
React.useEffect(() => {
if (show || props?.opacity) {
clearInterval(hideRef?.current)
clearInterval(hideRef?.current);
events.next({
type: "settings-menu-hide",
uuid,
})
type: 'settings-menu-hide',
uuid
});
} else if (!show) {
setPinStatus(false)
setPinStatus(false);
}
}, [show, props?.opacity, events, uuid])
}, [show, props?.opacity, events, uuid]);
const maybeHide = React.useCallback(() => {
clearInterval(hideRef?.current)
clearInterval(hideRef?.current);
hideRef.current = setTimeout(() => {
if (!stateRef?.current?.pinStatus) {
setShow(false)
setOpacity(0)
setShow(false);
setOpacity(0);
}
}, waitTime)
}, [])
}, waitTime);
}, []);
const showMenu = React.useCallback(() => {
clearInterval(hideRef?.current)
setShow(true)
}, [])
clearInterval(hideRef?.current);
setShow(true);
}, []);
const hideMenu = React.useCallback(() => {
setShow(false)
}, [])
setShow(false);
}, []);
const basePadding = React.useMemo(() => {
return 4
}, [])
return 4;
}, []);
const types = React.useMemo(() => {
const baseTypes = thingtime?.settings?.types?.javascript || {}
const baseTypeKeys = Object.keys(baseTypes)
const baseTypes = thingtime?.settings?.types?.javascript || {};
const baseTypeKeys = Object.keys(baseTypes);
const customTypes = thingtime?.settings?.types?.custom || {}
const customTypeKeysRaw = Object.keys(customTypes)
const customTypes = thingtime?.settings?.types?.custom || {};
const customTypeKeysRaw = Object.keys(customTypes);
const customTypeKeys = customTypeKeysRaw?.filter((key) => {
return !baseTypeKeys?.includes?.(key)
})
return !baseTypeKeys?.includes?.(key);
});
const types = [
...(baseTypeKeys?.map?.((key) => {
return {
...baseTypes?.[key],
key,
}
key
};
}) || []),
...(customTypeKeys?.map?.((key) => {
return {
...customTypes?.[key],
key,
}
}) || []),
]
key
};
}) || [])
];
return types
}, [
thingtime?.settings?.types?.javascript,
thingtime?.settings?.types?.custom,
])
return types;
}, [thingtime?.settings?.types?.javascript, thingtime?.settings?.types?.custom]);
const onType = React.useCallback(
(args) => {
props?.onType?.(args)
props?.onType?.(args);
},
[props?.onType]
)
);
const onDelete = React.useCallback(
(type) => {
props?.onDelete?.()
props?.onDelete?.();
},
[props?.onDelete]
)
);
const childIconSize = 10
const iconSize = props?.iconSize || 7
const childIconSize = 10;
const iconSize = props?.iconSize || 7;
return (
<ClickAwayListener onClickAway={hideMenu}>
@ -149,7 +146,7 @@ export const SettingsMenu = (props) => {
// width="100%"
paddingRight={36}
opacity={opacity}
transition={props?.transition || "all 0.2s ease-in-out"}
transition={props?.transition || 'all 0.2s ease-in-out'}
onMouseEnter={showMenu}
onMouseLeave={maybeHide}
>
@ -159,6 +156,8 @@ export const SettingsMenu = (props) => {
cursor="pointer"
// onClick={deleteValue}
transition="all 0.2s ease-in-out"
// add title for hover context
title={`Options`}
>
<Icon name="wizard" size={iconSize}></Icon>
</Flex>
@ -169,7 +168,7 @@ export const SettingsMenu = (props) => {
left={0}
flexDirection="column"
opacity={show ? 1 : 0}
pointerEvents={show ? "all" : "none"}
pointerEvents={show ? 'all' : 'none'}
>
<Flex
position="absolute"
@ -178,19 +177,44 @@ export const SettingsMenu = (props) => {
padding="5px"
cursor="pointer"
onClick={() => setPinStatus((prev) => !prev)}
title={`Pin Options`}
>
<Icon
opacity={pinStatus ? 1 : 0.5}
name={pinStatus ? "pinned" : "pin"}
size="8px"
></Icon>
{show === true && <Icon opacity={pinStatus ? 1 : 0.5} name={pinStatus ? 'pinned' : 'pin'} size="8px"></Icon>}
</Flex>
{/* edit mode menu item */}
<Flex
flexDirection="column"
// rowGap={basePadding / 3}
background="greys.lightt"
borderRadius={4}
boxShadow={props?.boxShadow || "0px 2px 7px 0px rgba(0,0,0,0.2)"}
boxShadow={props?.boxShadow || '0px 2px 7px 0px rgba(0,0,0,0.2)'}
paddingY={basePadding}
>
<Flex
alignItems="center"
flexDirection="row"
// paddingRight={basePadding}
paddingLeft={basePadding}
_hover={{
background: 'greys.light'
}}
cursor="pointer"
// paddingX={basePadding * 1}
paddingY={basePadding / 2}
>
<Icon marginBottom="-2px" name="🎨" size={childIconSize}></Icon>
<Text marginTop="-2px" paddingLeft={2} fontSize="xs">
Toggle Edit Mode
</Text>
</Flex>
</Flex>
<Flex
flexDirection="column"
// rowGap={basePadding / 3}
background="greys.lightt"
borderRadius={4}
boxShadow={props?.boxShadow || '0px 2px 7px 0px rgba(0,0,0,0.2)'}
paddingY={basePadding}
>
{!props?.readonly && (
@ -200,17 +224,13 @@ export const SettingsMenu = (props) => {
// paddingRight={basePadding}
paddingLeft={basePadding}
_hover={{
background: "greys.light",
background: 'greys.light'
}}
cursor="pointer"
// paddingX={basePadding * 1}
paddingY={basePadding / 2}
>
<Icon
marginBottom="-2px"
name="cyclone"
size={childIconSize}
></Icon>
<Icon marginBottom="-2px" name="cyclone" size={childIconSize}></Icon>
<Text marginTop="-2px" paddingLeft={2} fontSize="xs">
Types
</Text>
@ -228,12 +248,12 @@ export const SettingsMenu = (props) => {
types.map((type, idx) => {
const ret = (
<Flex
key={props?.uuid + props?.fullPath + "-type-menu-" + idx}
key={props?.uuid + props?.fullPath + '-type-menu-' + idx}
width="100%"
_hover={{
"&>div": {
background: "greys.light",
},
'&>div': {
background: 'greys.light'
}
}}
cursor="pointer"
onClick={() => onType({ type })}
@ -247,11 +267,7 @@ export const SettingsMenu = (props) => {
paddingLeft={basePadding * 2}
paddingY={basePadding / 2}
>
<Icon
marginBottom="-2px"
name={type?.icon || type?.key || type?.label || type}
size={childIconSize}
></Icon>
<Icon marginBottom="-2px" name={type?.icon || type?.key || type?.label || type} size={childIconSize}></Icon>
<Text marginTop="-2px" paddingLeft={2} fontSize="xs">
{type?.label || type?.key || type}
</Text>
@ -259,18 +275,18 @@ export const SettingsMenu = (props) => {
<Flex
marginLeft="auto"
_hover={{
transform: "scale(1.3)",
transform: 'scale(1.3)'
}}
transition="all 0.2s ease-out"
onClick={(e) => {
e?.preventDefault?.()
e?.stopPropagation?.()
e?.preventDefault?.();
e?.stopPropagation?.();
// cancel bubble
e?.nativeEvent?.stopImmediatePropagation?.()
e?.nativeEvent?.stopImmediatePropagation?.();
onType({
type,
wrap: true,
})
wrap: true
});
}}
>
<Icon name="wrap" size={childIconSize}></Icon>
@ -278,8 +294,8 @@ export const SettingsMenu = (props) => {
)}
</Flex>
</Flex>
)
return ret
);
return ret;
})}
</Flex>
{!props?.readonly && props?.onDelete && (
@ -287,18 +303,14 @@ export const SettingsMenu = (props) => {
alignItems="center"
flexDirection="row"
_hover={{
background: "greys.light",
background: 'greys.light'
}}
cursor="pointer"
onClick={onDelete}
paddingX={basePadding * 1}
paddingY={basePadding / 2}
>
<Icon
marginBottom="-2px"
name="bin"
size={childIconSize}
></Icon>
<Icon marginBottom="-2px" name="bin" size={childIconSize}></Icon>
<Text marginTop="-2px" paddingLeft={2} fontSize="xs">
Recycle
</Text>
@ -308,5 +320,5 @@ export const SettingsMenu = (props) => {
</Flex>
</Center>
</ClickAwayListener>
)
}
);
};

View File

@ -0,0 +1,15 @@
import { Box } from '@chakra-ui/react';
import { Branding } from '~/components/Branding/Branding';
import { TopSpacing } from '~/components/Layout/TopSpacing';
import { Raw } from '~/components/MongoDB/Raw';
import { RawResults } from '~/components/MongoDB/RawResults';
export default function branding() {
const template = (
<>
<Branding />
</>
);
return template;
}

0
vercel.json Normal file
View File