summaryrefslogtreecommitdiff
path: root/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'frontend')
-rw-r--r--frontend/.dockerignore1
-rw-r--r--frontend/Dockerfile12
-rw-r--r--frontend/package-lock.json71
-rw-r--r--frontend/package.json4
-rw-r--r--frontend/src/App.tsx29
-rw-r--r--frontend/src/components/Dialog.tsx54
-rw-r--r--frontend/src/components/ElementCreator.tsx203
-rw-r--r--frontend/src/components/ElementList.tsx76
-rw-r--r--frontend/src/components/ElementView.tsx58
-rw-r--r--frontend/src/main.tsx24
-rw-r--r--frontend/src/store.ts0
-rw-r--r--frontend/src/stores.ts12
-rw-r--r--frontend/src/types.ts96
13 files changed, 591 insertions, 49 deletions
diff --git a/frontend/.dockerignore b/frontend/.dockerignore
new file mode 100644
index 0000000..b512c09
--- /dev/null
+++ b/frontend/.dockerignore
@@ -0,0 +1 @@
+node_modules \ No newline at end of file
diff --git a/frontend/Dockerfile b/frontend/Dockerfile
index 0b93a16..4b54f33 100644
--- a/frontend/Dockerfile
+++ b/frontend/Dockerfile
@@ -2,17 +2,7 @@ FROM node:21-alpine as builder
WORKDIR /app
-COPY package.json ./
-COPY package-lock.json ./
-COPY src ./src/
-COPY index.html ./
-COPY public ./
-COPY .env ./
-COPY postcss.config.js ./
-COPY tailwind.config.js ./
-COPY tsconfig.json ./
-COPY tsconfig.node.json ./
-COPY vite.config.ts ./
+COPY . .
RUN npm ci
RUN npm run build
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 258779e..c53b51b 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -10,7 +10,9 @@
"dependencies": {
"@react-oauth/google": "^0.11.1",
"react": "^18.2.0",
- "react-dom": "^18.2.0"
+ "react-dom": "^18.2.0",
+ "react-hot-toast": "^2.4.1",
+ "zustand": "^4.4.7"
},
"devDependencies": {
"@types/react": "^18.2.15",
@@ -991,13 +993,13 @@
"version": "15.7.9",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.9.tgz",
"integrity": "sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g==",
- "dev": true
+ "devOptional": true
},
"node_modules/@types/react": {
"version": "18.2.33",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.33.tgz",
"integrity": "sha512-v+I7S+hu3PIBoVkKGpSYYpiBT1ijqEzWpzQD62/jm4K74hPpSP7FF9BnKG6+fg2+62weJYkkBWDJlZt5JO/9hg==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@@ -1017,7 +1019,7 @@
"version": "0.16.5",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.5.tgz",
"integrity": "sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==",
- "dev": true
+ "devOptional": true
},
"node_modules/@types/semver": {
"version": "7.5.4",
@@ -1835,8 +1837,7 @@
"node_modules/csstype": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
- "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==",
- "dev": true
+ "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
},
"node_modules/debug": {
"version": "4.3.4",
@@ -2727,6 +2728,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/goober": {
+ "version": "2.1.13",
+ "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.13.tgz",
+ "integrity": "sha512-jFj3BQeleOoy7t93E9rZ2de+ScC4lQICLwiAQmKMg9F6roKGaLSHoCDYKkWlSafg138jejvq/mTdvmnwDQgqoQ==",
+ "peerDependencies": {
+ "csstype": "^3.0.10"
+ }
+ },
"node_modules/gopd": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
@@ -3997,6 +4006,21 @@
"react": "^18.2.0"
}
},
+ "node_modules/react-hot-toast": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.1.tgz",
+ "integrity": "sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==",
+ "dependencies": {
+ "goober": "^2.1.10"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "react": ">=16",
+ "react-dom": ">=16"
+ }
+ },
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@@ -4722,6 +4746,14 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/use-sync-external-store": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
+ "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -4906,6 +4938,33 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
+ },
+ "node_modules/zustand": {
+ "version": "4.4.7",
+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.4.7.tgz",
+ "integrity": "sha512-QFJWJMdlETcI69paJwhSMJz7PPWjVP8Sjhclxmxmxv/RYI7ZOvR5BHX+ktH0we9gTWQMxcne8q1OY8xxz604gw==",
+ "dependencies": {
+ "use-sync-external-store": "1.2.0"
+ },
+ "engines": {
+ "node": ">=12.7.0"
+ },
+ "peerDependencies": {
+ "@types/react": ">=16.8",
+ "immer": ">=9.0",
+ "react": ">=16.8"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "immer": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ }
+ }
}
}
}
diff --git a/frontend/package.json b/frontend/package.json
index 4334002..cb56e00 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -12,7 +12,9 @@
"dependencies": {
"@react-oauth/google": "^0.11.1",
"react": "^18.2.0",
- "react-dom": "^18.2.0"
+ "react-dom": "^18.2.0",
+ "react-hot-toast": "^2.4.1",
+ "zustand": "^4.4.7"
},
"devDependencies": {
"@types/react": "^18.2.15",
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 7aae66c..49e6992 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1,10 +1,13 @@
import { CredentialResponse, GoogleLogin } from '@react-oauth/google';
-import { FC, useEffect, useState } from 'react';
+import { FC, useEffect } from 'react';
import { LoginRequest, LoginResponse, User } from './types';
import ElementList from './components/ElementList';
+import { userStore } from './stores';
+import toast from 'react-hot-toast';
const App: FC = () => {
- const [user, setUser] = useState<User | undefined>(undefined);
+ const user = userStore((store) => store.user);
+ const setUser = userStore((store) => store.setUser);
useEffect(() => {
const userString = localStorage.getItem('user');
@@ -12,8 +15,21 @@ const App: FC = () => {
return;
}
- setUser(JSON.parse(userString));
- }, []);
+ const userObject = JSON.parse(userString) as User;
+ fetch(`/api/user/${userObject.id}`).then((resp) => {
+ if (resp.status == 401) {
+ toast.error(
+ 'Your authorization has expired. You have to log in again.',
+ );
+ localStorage.removeItem('user');
+ } else if (resp.status == 404) {
+ toast.error("Your account doesn't exist anymore.");
+ localStorage.removeItem('user');
+ } else {
+ setUser(JSON.parse(userString));
+ }
+ });
+ }, [setUser]);
const login = async (credentials: CredentialResponse) => {
if (credentials.credential == null) {
@@ -25,6 +41,7 @@ const App: FC = () => {
const loginRequest: LoginRequest = {
googleToken: credentials.credential,
};
+
const loginResponse = await fetch('/api/auth/login', {
method: 'POST',
credentials: 'include',
@@ -48,8 +65,8 @@ const App: FC = () => {
console.log('Error connecting to API. Code: ', userInfoResponse.status);
return;
}
- const userResponse: User = await userInfoResponse.json();
+ const userResponse: User = await userInfoResponse.json();
localStorage.setItem('user', JSON.stringify(userResponse));
setUser(userResponse);
};
@@ -89,6 +106,6 @@ const App: FC = () => {
<ElementList />
</div>
);
-}
+};
export default App;
diff --git a/frontend/src/components/Dialog.tsx b/frontend/src/components/Dialog.tsx
new file mode 100644
index 0000000..4fa6bf7
--- /dev/null
+++ b/frontend/src/components/Dialog.tsx
@@ -0,0 +1,54 @@
+import { FC, PropsWithChildren, useEffect, useRef } from 'react';
+
+interface DialogProps {
+ visible: boolean;
+ closeDialog: () => void;
+}
+
+const Dialog: FC<PropsWithChildren<DialogProps>> = ({
+ visible,
+ closeDialog,
+ children,
+}) => {
+ const dialogRef = useRef<HTMLDialogElement>(null);
+
+ useEffect(() => {
+ if (visible) {
+ dialogRef.current?.showModal();
+ } else {
+ dialogRef.current?.close();
+ }
+ }, [visible]);
+
+ const handleButtonClick = (e: React.MouseEvent<HTMLButtonElement>) => {
+ e.preventDefault();
+ closeDialog();
+ };
+
+ return (
+ <dialog ref={dialogRef}>
+ <div className="p-4 flex flex-col max-w-[90vw] md:max-w-[50vw] bg-white shadow">
+ <div className="flex w-full">
+ <button className="ml-auto" onClick={handleButtonClick}>
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ strokeWidth={1.5}
+ stroke="currentColor"
+ className="w-6 h-6">
+ <path
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ d="M6 18 18 6M6 6l12 12"
+ />
+ </svg>
+ </button>
+ </div>
+ {children}
+ </div>
+ </dialog>
+ );
+};
+
+export default Dialog;
diff --git a/frontend/src/components/ElementCreator.tsx b/frontend/src/components/ElementCreator.tsx
new file mode 100644
index 0000000..61f5aba
--- /dev/null
+++ b/frontend/src/components/ElementCreator.tsx
@@ -0,0 +1,203 @@
+import { FC, useEffect, useState } from 'react';
+import {
+ Element,
+ Color,
+ ColorBitmap,
+ ElementState,
+ ElementSuggestion,
+ ColorCode,
+} from '../types';
+import toast from 'react-hot-toast';
+import ElementView from './ElementView';
+import { userStore } from '../stores';
+
+interface ElementCreatorProps {
+ firstElementId: number | undefined;
+ secondElementId: number | undefined;
+ closeDialog: () => void;
+}
+
+const ElementCreator: FC<ElementCreatorProps> = ({
+ firstElementId,
+ secondElementId,
+ closeDialog,
+}) => {
+ const [elementName, setElementName] = useState<string>('');
+ const [color, setColor] = useState<Color>(Color.Air);
+ const [firstElement, setFirstElement] = useState<Element | null>(null);
+ const [secondElement, setSecondElement] = useState<Element | null>(null);
+ const setUser = userStore((store) => store.setUser);
+
+ const fetchElement = async (elementId: number): Promise<Element> => {
+ const elementResponse = await fetch(`/api/element/${elementId}`);
+ return await elementResponse.json();
+ };
+
+ useEffect(() => {
+ if (firstElementId == undefined || secondElementId == undefined) {
+ return;
+ }
+
+ setElementName('');
+ setColor(Color.Air);
+
+ fetchElement(firstElementId).then((elem) => {
+ setFirstElement(elem);
+ });
+ fetchElement(secondElementId).then((elem) => {
+ setSecondElement(elem);
+ });
+ }, [firstElementId, secondElementId]);
+
+ const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+ setElementName(e.target.value);
+ };
+
+ const createHandleColorClick = (color: Color) => {
+ return (e: React.MouseEvent<HTMLButtonElement>) => {
+ e.preventDefault();
+ setColor(color);
+ };
+ };
+
+ const handleSubmitButton = async (e: React.MouseEvent<HTMLButtonElement>) => {
+ e.preventDefault();
+
+ if (elementName == '') {
+ toast.error('No name selected');
+ return;
+ }
+ if (!(color in Color)) {
+ toast.error('Bad color value');
+ return;
+ }
+
+ const request: ElementSuggestion = {
+ name: elementName,
+ iconBitmap: ColorBitmap[color],
+ firstElementId: firstElementId!,
+ secondElementId: secondElementId!,
+ };
+
+ console.log(request);
+
+ const createVoteResponse = await fetch(`/api/suggestion/create`, {
+ method: 'POST',
+ credentials: 'include',
+ body: JSON.stringify(request),
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+
+ if (createVoteResponse.status == 401) {
+ console.log('Session expired');
+ toast.error('Your authorization has expired. You have to log in again.');
+ localStorage.removeItem('user');
+ setUser(undefined);
+ return;
+ }
+ console.log(createVoteResponse.status);
+ console.log('Vote started');
+ closeDialog();
+ };
+
+ return (
+ <form className="flex flex-col items-center">
+ <div className="flex items-center">
+ {firstElement != null && secondElement != null && (
+ <>
+ <ElementView
+ element={firstElement!}
+ onElementCombine={() => {}}
+ isPreview={false}
+ interactive={false}
+ />
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ strokeWidth={1.5}
+ stroke="currentColor"
+ className="w-6 h-6">
+ <path
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ d="M12 4.5v15m7.5-7.5h-15"
+ />
+ </svg>
+ <ElementView
+ element={secondElement!}
+ onElementCombine={() => {}}
+ isPreview={false}
+ interactive={false}
+ />
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ strokeWidth={1.5}
+ stroke="currentColor"
+ className="w-6 h-6">
+ <path
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ d="M3.75 9h16.5m-16.5 6.75h16.5"
+ />
+ </svg>
+ </>
+ )}
+ <ElementView
+ element={{
+ name: elementName,
+ icon: ColorCode[color],
+ id: 0,
+ userId: 0,
+ state: ElementState.HasColor,
+ }}
+ onElementCombine={() => {}}
+ isPreview={true}
+ interactive={false}
+ />
+ </div>
+ <div className="mb-5 w-full">
+ <label
+ htmlFor="element-name"
+ className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
+ Element name
+ </label>
+ <input
+ type="text"
+ id="element-name"
+ value={elementName}
+ onChange={handleNameChange}
+ className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
+ required
+ />
+ </div>
+ <div className="flex flex-wrap mb-3 gap-2 border p-2 rounded shadow justify-center">
+ {(Object.keys(Color) as Array<keyof typeof Color>)
+ .filter((color) => Number.isNaN(Number(color)))
+ .map((color) => {
+ return (
+ <button
+ key={color}
+ onClick={createHandleColorClick(Color[color])}>
+ <div
+ className="border border-gray-200 w-8 h-8"
+ style={{ backgroundColor: ColorCode[Color[color]] }}></div>
+ </button>
+ );
+ })}
+ </div>
+ <button
+ onClick={handleSubmitButton}
+ type="submit"
+ className=" text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
+ Submit
+ </button>
+ </form>
+ );
+};
+
+export default ElementCreator;
diff --git a/frontend/src/components/ElementList.tsx b/frontend/src/components/ElementList.tsx
index 20b27dd..04650c4 100644
--- a/frontend/src/components/ElementList.tsx
+++ b/frontend/src/components/ElementList.tsx
@@ -1,22 +1,35 @@
import { FC, useEffect, useState } from 'react';
-import {Element} from '../types';
+import { Element } from '../types';
import ElementView from './ElementView';
+import Dialog from './Dialog';
+import ElementCreator from './ElementCreator';
+import { userStore } from '../stores';
+import toast from 'react-hot-toast';
const ElementList: FC = () => {
const [elements, setElements] = useState<Element[]>([]);
+ const [elementCreatorVisible, setElementCreatorVisible] =
+ useState<boolean>(false);
+ const [creatorFirstElementId, setCreatorFirstElementId] = useState<
+ number | undefined
+ >(undefined);
+ const [creatorSecondElementId, setCreatorSecondElementId] = useState<
+ number | undefined
+ >(undefined);
+ const user = userStore((store) => store.user);
useEffect(() => {
const initialElements: number[] = [1, 2, 3, 4];
const elementStateString = localStorage.getItem('elementState');
if (elementStateString != null) {
- setElements(JSON.parse(elementStateString));
- return;
+ setElements(JSON.parse(elementStateString));
+ return;
}
const fetchElements = async () => {
const elems: Element[] = [];
-
+
for (const elemId of initialElements) {
const response = await fetch(`/api/element/${elemId}`);
const elem: Element = await response.json();
@@ -32,14 +45,59 @@ const ElementList: FC = () => {
useEffect(() => {
if (elements.length != 0) {
- localStorage.setItem('elementState', JSON.stringify(elements));
+ localStorage.setItem('elementState', JSON.stringify(elements));
}
- }, [elements])
+ }, [elements]);
+
+ const createOnElementCombine = (firstElementId: number) => {
+ return async (secondElementId: number) => {
+ const combineResponse = await fetch(
+ `/api/element/combine?firstElementId=${firstElementId}&secondElementId=${secondElementId}`,
+ );
+ if (combineResponse.status == 404) {
+ console.log("Element doesn't exist");
+ if (!user) {
+ toast("You have discovered a new element but need to log in to name it");
+ return;
+ }
+ setCreatorFirstElementId(firstElementId);
+ setCreatorSecondElementId(secondElementId);
+ setElementCreatorVisible(true);
+ return;
+ }
+
+ const newElem: Element = await combineResponse.json();
+ if (elements.find((e) => e.id == newElem.id)) {
+ toast(`You have already discovered ${newElem.name}`);
+ return;
+ }
+ setElements((elems) => elems.concat(newElem));
+ };
+ };
return (
- <>
- {elements.map(elem => <ElementView key={elem.id} element={elem} />)}
- </>
+ <div className="p-3 flex gap-3">
+ {elements.map((elem) => (
+ <ElementView
+ key={elem.id}
+ interactive={true}
+ isPreview={false}
+ element={elem}
+ onElementCombine={createOnElementCombine(elem.id)}
+ />
+ ))}
+ <Dialog
+ visible={elementCreatorVisible}
+ closeDialog={() => {
+ setElementCreatorVisible(false);
+ }}>
+ <ElementCreator
+ firstElementId={creatorFirstElementId}
+ secondElementId={creatorSecondElementId}
+ closeDialog={() => setElementCreatorVisible(false)}
+ />
+ </Dialog>
+ </div>
);
};
diff --git a/frontend/src/components/ElementView.tsx b/frontend/src/components/ElementView.tsx
index 4f9d489..1b11ffb 100644
--- a/frontend/src/components/ElementView.tsx
+++ b/frontend/src/components/ElementView.tsx
@@ -2,15 +2,63 @@ import { FC } from 'react';
import { Element } from '../types';
interface ElementViewProps {
+ onElementCombine: (elementId: number) => void;
element: Element;
+ interactive: boolean;
+ isPreview: boolean;
}
-const ElementView: FC<ElementViewProps> = ({ element }) => {
+const ElementView: FC<ElementViewProps> = ({
+ onElementCombine,
+ element,
+ interactive,
+ isPreview,
+}) => {
+ const onDragStart = (e: React.DragEvent<HTMLDivElement>) => {
+ e.stopPropagation();
+
+ e.dataTransfer.setData('text/plain', element.name);
+ e.dataTransfer.setData('id', element.id.toString());
+ };
+
+ const onDragOver = (e: React.DragEvent<HTMLDivElement>) => {
+ e.preventDefault();
+ };
+
+ const onDrop = (e: React.DragEvent<HTMLDivElement>) => {
+ const elementId = e.dataTransfer.getData('id');
+ onElementCombine(Number.parseInt(elementId));
+ e.preventDefault();
+ };
+
return (
- <div className='flex flex-row m-2 rounded-md border border-gray-300 bg-gray-100 w-fit h-fit'>
- <div className='flex flex-col items-center'>
- <img src={`data:image/png;base64,${element.icon}`} width='80px' height='80px'/>
- <p className='my-1 mx-2 text-sm'>{element.name}</p>
+ <div
+ draggable={interactive}
+ onDragStart={interactive ? onDragStart : undefined}
+ onDragOver={interactive ? onDragOver : undefined}
+ onDrop={interactive ? onDrop : undefined}
+ className="element flex flex-row rounded-md border border-gray-300 bg-gray-100 w-[96px] h-fit">
+ <div draggable={false} className="flex flex-col items-center w-full">
+ {isPreview ? (
+ <div
+ style={{
+ backgroundColor: element.icon,
+ }}
+ className="rounded-t w-full h-[96px]"></div>
+ ) : (
+ <img
+ draggable={false}
+ className="rounded-t"
+ src={`data:image/png;base64,${element.icon}`}
+ width="96px"
+ height="96px"
+ />
+ )}
+ <span
+ draggable={false}
+ className="my-1 mx-2 text-sm leading-tight text-center w-full">
+ {element.name.length > 0 ? element.name : '\u00A0'}
+ </span>
</div>
</div>
);
diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx
index 4e3e75d..38088a9 100644
--- a/frontend/src/main.tsx
+++ b/frontend/src/main.tsx
@@ -1,13 +1,15 @@
-import React from 'react'
-import ReactDOM from 'react-dom/client'
-import App from './App.tsx'
-import './index.css'
-import {GoogleOAuthProvider} from '@react-oauth/google';
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import App from './App.tsx';
+import './index.css';
+import { GoogleOAuthProvider } from '@react-oauth/google';
+import { Toaster } from 'react-hot-toast';
ReactDOM.createRoot(document.getElementById('root')!).render(
- <GoogleOAuthProvider clientId={import.meta.env.VITE_GOOGLE_CLIENT_ID}>
- <React.StrictMode>
- <App />
- </React.StrictMode>
- </GoogleOAuthProvider>,
-)
+ <GoogleOAuthProvider clientId={import.meta.env.VITE_GOOGLE_CLIENT_ID}>
+ <React.StrictMode>
+ <Toaster />
+ <App />
+ </React.StrictMode>
+ </GoogleOAuthProvider>,
+);
diff --git a/frontend/src/store.ts b/frontend/src/store.ts
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/frontend/src/store.ts
diff --git a/frontend/src/stores.ts b/frontend/src/stores.ts
new file mode 100644
index 0000000..d5a7ffe
--- /dev/null
+++ b/frontend/src/stores.ts
@@ -0,0 +1,12 @@
+import { create } from 'zustand';
+import { User } from './types';
+
+interface UserStore {
+ user: User | undefined;
+ setUser: (user: User | undefined) => void;
+}
+
+export const userStore = create<UserStore>()((set) => ({
+ user: undefined,
+ setUser: (user) => set({ user: user }),
+}));
diff --git a/frontend/src/types.ts b/frontend/src/types.ts
index ecdd808..35ee7f5 100644
--- a/frontend/src/types.ts
+++ b/frontend/src/types.ts
@@ -20,7 +20,103 @@ export interface Element {
icon: string;
}
+export interface ElementSuggestion {
+ name: string;
+ iconBitmap: string;
+ firstElementId: number;
+ secondElementId: number;
+}
+
export enum ElementState {
HasColor,
HasIcon,
}
+
+export enum Color {
+ Air,
+ Ground,
+ Fire,
+ Water,
+ Navy,
+ Silver,
+ Purple,
+ Maroon,
+ Gray,
+ Green,
+ Lime,
+ Yellow,
+ Olive,
+ White,
+ Tan,
+ Black,
+ Red,
+ Lavender,
+ Pink,
+ Magenta,
+}
+
+export const ColorCode: { [key in Color]: string } = {
+ [Color.Air]: '#bbdefb',
+ [Color.Ground]: '#5d4037',
+ [Color.Fire]: '#ff7043',
+ [Color.Water]: '#2196f3',
+ [Color.Navy]: '#303f9f',
+ [Color.Silver]: '#bdbdbd',
+ [Color.Purple]: '#7b1fa2',
+ [Color.Maroon]: '#b71c1c',
+ [Color.Gray]: '#424242',
+ [Color.Green]: '#4caf50',
+ [Color.Lime]: '#76ff03',
+ [Color.Yellow]: '#ffee58',
+ [Color.Olive]: '#afb42b',
+ [Color.White]: '#ffffff',
+ [Color.Tan]: '#d3b8ae',
+ [Color.Black]: '#212121',
+ [Color.Red]: '#ef5350',
+ [Color.Lavender]: '#b39ddb',
+ [Color.Pink]: '#ff80ab',
+ [Color.Magenta]: '#e040fb',
+};
+
+export const ColorBitmap: { [key in Color]: string } = {
+ [Color.Air]:
+ '/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+/+73vv/u977/7ve+w==',
+ [Color.Ground]:
+ '/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKv+lKir/pSoq/6UqKg==',
+ [Color.Fire]:
+ '//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAP//pQD//6UA//+lAA==',
+ [Color.Water]:
+ '/wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA/w==',
+ [Color.Navy]:
+ '/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgP8AAID/AACA/wAAgA==',
+ [Color.Silver]:
+ '/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwA==',
+ [Color.Purple]:
+ '/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgP+AAID/gACA/4AAgA==',
+ [Color.Maroon]:
+ '/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAAA==',
+ [Color.Gray]:
+ '/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgA==',
+ [Color.Green]:
+ '/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAP8AgAD/AIAA/wCAAA==',
+ [Color.Lime]:
+ '/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AA==',
+ [Color.Yellow]:
+ '////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AA==',
+ [Color.Olive]:
+ '/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAP+AgAD/gIAA/4CAAA==',
+ [Color.White]:
+ '/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////w==',
+ [Color.Tan]:
+ '/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jP/StIz/0rSM/9K0jA==',
+ [Color.Black]:
+ '/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAA==',
+ [Color.Red]:
+ '//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAA==',
+ [Color.Lavender]:
+ '/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+v/m5vr/5ub6/+bm+g==',
+ [Color.Pink]:
+ '///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ay///wMv//8DL///Ayw==',
+ [Color.Magenta]:
+ '//8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/w==',
+};