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",