diff --git a/remix/app/Providers/Chakra/Components/Button.tsx b/remix/app/Providers/Chakra/Components/Button.tsx new file mode 100644 index 0000000..b85db21 --- /dev/null +++ b/remix/app/Providers/Chakra/Components/Button.tsx @@ -0,0 +1,14 @@ +// import chakra button type +import type { ButtonProps } from '@chakra-ui/react'; + +interface ChakraButtonProps { + defaultProps: ButtonProps; +} + +export const ChakraButton: ChakraButtonProps = { + defaultProps: { + colorScheme: 'chakra.throat', + size: 'sm', + variant: 'solid' + } +}; diff --git a/remix/app/Providers/Chakra/colors.tsx b/remix/app/Providers/Chakra/colors.tsx index f951d02..0025340 100644 --- a/remix/app/Providers/Chakra/colors.tsx +++ b/remix/app/Providers/Chakra/colors.tsx @@ -1,68 +1,100 @@ -const greys = { - light: "#F1F1F3", - lightt: "#E7E6E8", - medium: "#E0E0E0", - dark: "#BDBDBD", -} +import hexgba from 'hex-to-rgba'; -const grey = "#F1F1F3" +const greys = { + light: '#F1F1F3', + lightt: '#E7E6E8', + medium: '#E0E0E0', + dark: '#BDBDBD' +}; + +const grey = '#F1F1F3'; const g = { gray: grey, grey, grays: greys, - greys, -} + greys +}; // for bad spellers -g.gray = g.grey -g.grays = g.greys +g.gray = g.grey; +g.grays = g.greys; + +const chakrasDark = { + root: '#8E0000', + sacral: '#E65100', + solarPlexus: '#FDD835', + heart: '#33691E', + throat: '#1E88E5', + thirdEye: '#3949AB', + crown: '#6A1B9A', + red: '#8E0000', + orange: '#E65100', + yellow: '#FDD835', + green: '#33691E', + blue: '#1E88E5', + indigo: '#3949AB', + violet: '#6A1B9A' +}; + +const chakrasLight = { + root: '#C62828', + sacral: '#FF7043', + solarPlexus: '#FFEE58', + heart: '#66BB6A', + throat: '#42A5F5', + thirdEye: '#5C6BC0', + crown: '#AB47BC', + red: '#C62828', + orange: '#FF7043', + yellow: '#FFEE58', + green: '#66BB6A', + blue: '#42A5F5', + indigo: '#5C6BC0', + violet: '#AB47BC' +}; + +// map chakra colours and dark version to key.500 and key.600 in an object map + +const chakras = {}; + +for (const key in chakrasLight) { + chakras[key] = { + 500: chakrasLight[key], + 600: chakrasDark[key] + }; +} export const colors = { - white: "#FFFFFF", + white: '#FFFFFF', ...g, - black: "#000000", + black: '#000000', // all colors of the chakras - chakras: { - root: "#C62828", - sacral: "#FF7043", - solarPlexus: "#FFEE58", - heart: "#66BB6A", - throat: "#42A5F5", - thirdEye: "#5C6BC0", - crown: "#AB47BC", - red: "#C62828", - orange: "#FF7043", - yellow: "#FFEE58", - green: "#66BB6A", - blue: "#42A5F5", - indigo: "#5C6BC0", - violet: "#AB47BC", - }, - chakrasDark: { - root: "#8E0000", - sacral: "#E65100", - solarPlexus: "#FDD835", - heart: "#33691E", - throat: "#1E88E5", - thirdEye: "#3949AB", - crown: "#6A1B9A", - red: "#8E0000", - orange: "#E65100", - yellow: "#FDD835", - green: "#33691E", - blue: "#1E88E5", - indigo: "#3949AB", - violet: "#6A1B9A", - }, + chakra: chakras, + chakras: chakrasLight, + chakrasDark, // all colors of the rainbow rainbow: { - red: "#FF0000", - orange: "#FF7F00", - yellow: "#FFFF00", - green: "#00FF00", - blue: "#0000FF", - indigo: "#4B0082", - violet: "#8F00FF", - }, -} + red: '#FF0000', + orange: '#FF7F00', + yellow: '#FFFF00', + green: '#00FF00', + blue: '#0000FF', + indigo: '#4B0082', + violet: '#8F00FF' + } +}; + +// recursively loop all colors and add a dark variant + +const addDark = (color, name) => { + if (typeof color === 'object') { + for (const key in color) { + addDark(color[key], key); + } + } else { + colors[`${name}-dark`] = hexgba(color, 0.5); + } +}; + +// addDark(colors, 'colors'); diff --git a/remix/app/Providers/Chakra/theme.tsx b/remix/app/Providers/Chakra/theme.tsx index 057da69..3551708 100644 --- a/remix/app/Providers/Chakra/theme.tsx +++ b/remix/app/Providers/Chakra/theme.tsx @@ -11,6 +11,7 @@ import { import { colors } from './colors'; import { space } from './space'; +import { ChakraButton } from './Components/Button'; export const theme = extendTheme({ colors, @@ -61,6 +62,7 @@ export const theme = extendTheme({ } }, components: { + Button: ChakraButton, Input: { defaultProps: { // focusBorderColor: "transparent", diff --git a/remix/app/components/API/Test.tsx b/remix/app/components/API/Test.tsx new file mode 100644 index 0000000..dc9ca86 --- /dev/null +++ b/remix/app/components/API/Test.tsx @@ -0,0 +1,33 @@ +import { Suspense } from 'react'; +import { Box, Flex, Button, Spacer } from '@chakra-ui/react'; +import { Editor } from '../Editor/Editor'; +import { TopSpacing } from '../Layout/TopSpacing'; + +export const TestAPI = (props) => { + const defaultValueDefault = ` + { + "username": "thingtime", + "password": "password" + } + `; + + const { defaultValue = defaultValueDefault } = props; + + const run = () => {}; + + const controls = ( + <> + + + + + ); + + return ( + <> + {controls} + + {controls} + + ); +}; diff --git a/remix/app/components/Editor/Editor.tsx b/remix/app/components/Editor/Editor.tsx new file mode 100644 index 0000000..a76b44d --- /dev/null +++ b/remix/app/components/Editor/Editor.tsx @@ -0,0 +1,20 @@ +import { Suspense } from 'react'; +import { Box, Button, Flex } from '@chakra-ui/react'; +import { Editor as MonacoEditor } from '@monaco-editor/react'; + +export const Editor = (props) => { + const { defaultValue = '', defaultLanguage = 'javascript', width = '100%', height = '100%' } = props; + + return ( + <> + + {/* only on client side render editor */} + + Loading...}> + + + + + + ); +}; diff --git a/remix/app/components/Layout/TopSpacing.tsx b/remix/app/components/Layout/TopSpacing.tsx new file mode 100644 index 0000000..13283ad --- /dev/null +++ b/remix/app/components/Layout/TopSpacing.tsx @@ -0,0 +1,5 @@ +import { Box } from '@chakra-ui/react'; + +export const TopSpacing = () => { + return ; +}; diff --git a/remix/app/components/MongoDB/Raw.tsx b/remix/app/components/MongoDB/Raw.tsx index ed9c828..9075947 100644 --- a/remix/app/components/MongoDB/Raw.tsx +++ b/remix/app/components/MongoDB/Raw.tsx @@ -1,6 +1,6 @@ import { Suspense, useState } from 'react'; import { useThingtime } from '../Thingtime/useThingtime'; -import { Flex, Heading, Box } from '@chakra-ui/react'; +import { Flex, Heading, Box, Button } from '@chakra-ui/react'; import Editor from '@monaco-editor/react'; export const Raw = () => { @@ -18,9 +18,12 @@ export const Raw = () => { Loading...}> {/* {editor} */} - - ; - + + + + + + diff --git a/remix/app/components/MongoDB/RawResult.tsx b/remix/app/components/MongoDB/RawResult.tsx new file mode 100644 index 0000000..9e7cb4b --- /dev/null +++ b/remix/app/components/MongoDB/RawResult.tsx @@ -0,0 +1,28 @@ +import React, { Suspense, useState } from 'react'; +import { useThingtime } from '../Thingtime/useThingtime'; +import { Flex, Heading, Box, Button } from '@chakra-ui/react'; +import Editor from '@monaco-editor/react'; + +type RawResultProps = { + result: object; +}; + +export const RawResult = (props: RawResultProps) => { + const { thingtime } = useThingtime(); + + const { result } = props; + + const stringified = React.useMemo(() => { + try { + return
{JSON.stringify(result, null, 2)}
; + } catch (e) { + ('Error stringifying result'); + } + }, []); + + return ( + + {stringified} + + ); +}; diff --git a/remix/app/components/MongoDB/RawResults.tsx b/remix/app/components/MongoDB/RawResults.tsx new file mode 100644 index 0000000..11d9e8d --- /dev/null +++ b/remix/app/components/MongoDB/RawResults.tsx @@ -0,0 +1,30 @@ +import { Suspense, useState } from 'react'; +import { useThingtime } from '../Thingtime/useThingtime'; +import { Flex, Heading, Box, Button } from '@chakra-ui/react'; +import Editor from '@monaco-editor/react'; +import { RawResult } from './RawResult'; + +export const RawResults = () => { + const { thingtime } = useThingtime(); + + const [results, setResults] = useState([]); + + const fetchResults = async () => { + const res = await fetch('/api/v1/mongodb/raw-results'); + const data = await res.json(); + setResults(data); + }; + + return ( + + + Raw Results + + + {results.map((result, index) => { + return ; + })} + + + ); +}; diff --git a/remix/app/hooks/useApi.tsx b/remix/app/hooks/useApi.tsx index 1b969a6..bc1bd7e 100644 --- a/remix/app/hooks/useApi.tsx +++ b/remix/app/hooks/useApi.tsx @@ -9,15 +9,28 @@ export function useApi() { login: useCallback( async (args) => { const { username, password } = args; - + console.log('nik submitting with username', username); console.log('nik submitting with password', password); - + const ret = asyncFetcher.submit({ username, password }, { action: '/api/v1/login' }); return ret; }, [asyncFetcher] - ) + ), + mongodb: { + rawResults: useCallback( + async (args) => { + const { query } = args; + + console.log('submitting query', query); + + const ret = asyncFetcher.submit({ query }, { action: '/api/v1/mongodb/raw-results' }); + return ret; + }, + [asyncFetcher] + ) + } }; const ret = { diff --git a/remix/app/routes/api/v1/mongodb/raw-results/_raw-results.tsx b/remix/app/routes/api/v1/mongodb/raw-results/_raw-results.tsx new file mode 100644 index 0000000..b6f4d2b --- /dev/null +++ b/remix/app/routes/api/v1/mongodb/raw-results/_raw-results.tsx @@ -0,0 +1,52 @@ +import { userCheckExists } from '~/api/utils/userCheckExists'; +import { userValidatePassword } from '~/api/utils/userValidatePassword'; + +export default function Index() { + return
Login
; +} + +export const action = async ({ request }) => { + console.log('nik request', request); + + // get remix action body + + const body = await request.json(); + + const { username, password } = body; + + console.log('nik body', body); + + console.log('nik username', username); + console.log('nik password', password); + + const userExists = userCheckExists(username); + + if (!userExists) { + // validate password + return earlyReturn({ status: 401, message: 'User does not exist' }); + } + + // validate password + const passwordMatches = userValidatePassword({ username, password }); + + if (!passwordMatches) { + return earlyReturn({ status: 401, message: 'Password does not match' }); + } + + return earlyReturn({ status: 200, message: 'Login successful' }); +}; + +const earlyReturn = (args) => { + return { + status: args?.status || 200, + headers: { + 'Content-Type': 'application/json' + }, + body: { + message: 'Early return triggered in login action' + (args?.message ? `: ${args.message}` : '') + }, + cache: { + revalidate: 60 + } + }; +}; diff --git a/remix/app/routes/api/v1/template/_template.tsx b/remix/app/routes/api/v1/template/_template.tsx new file mode 100644 index 0000000..0ab94a5 --- /dev/null +++ b/remix/app/routes/api/v1/template/_template.tsx @@ -0,0 +1,41 @@ +import { Heading } from '@chakra-ui/react'; +import { userCheckExists } from '~/api/utils/userCheckExists'; +import { userValidatePassword } from '~/api/utils/userValidatePassword'; +import { TestAPI } from '~/components/API/Test'; +import { TopSpacing } from '~/components/Layout/TopSpacing'; + +export default function Index() { + return ( + <> + + API V1 Template + + + ); +} + +export const action = async ({ request }) => { + console.log('[tt] request', request); + + // get remix action body + const body = await request.json(); + + const {} = body; + + return earlyReturn({ status: 200, message: 'Template API' }); +}; + +const earlyReturn = (args) => { + return { + status: args?.status || 200, + headers: { + 'Content-Type': 'application/json' + }, + body: { + message: 'Early return triggered in login action' + (args?.message ? `: ${args.message}` : '') + }, + cache: { + revalidate: 60 + } + }; +}; diff --git a/remix/app/routes/raw.tsx b/remix/app/routes/raw.tsx index 8191dc0..e185b51 100644 --- a/remix/app/routes/raw.tsx +++ b/remix/app/routes/raw.tsx @@ -1,9 +1,14 @@ +import { Box } from '@chakra-ui/react'; +import { TopSpacing } from '~/components/Layout/TopSpacing'; import { Raw } from '~/components/MongoDB/Raw'; +import { RawResults } from '~/components/MongoDB/RawResults'; export default function login() { const template = ( <> + + ); diff --git a/remix/package.json b/remix/package.json index ceb3e13..caaf9b8 100644 --- a/remix/package.json +++ b/remix/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "@chakra-ui/react": "^2.7.1", + "@chakra-ui/react-types": "^2.0.6", "@editorjs/editorjs": "^2.27.2", "@emotion/react": "^11.11.4", "@fortawesome/fontawesome-svg-core": "^6.4.0", @@ -30,6 +31,7 @@ "flatted": "^3.2.7", "fuse.js": "^6.6.2", "gradient-path": "^2.3.0", + "hex-to-rgba": "^2.0.1", "isbot": "latest", "lodash-es": "^4.17.21", "mongodb": "^6.5.0",