diff --git a/package.json b/package.json
index cf998d0..7bf93d3 100644
--- a/package.json
+++ b/package.json
@@ -45,6 +45,7 @@
"i18next-http-backend": "^2.1.1",
"jspdf": "^2.5.1",
"match-sorter": "^6.3.1",
+ "papaparse": "^5.4.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^12.2.0",
@@ -59,6 +60,7 @@
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.9",
+ "@types/papaparse": "^5.3.7",
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10",
"@types/react-scroll-to-bottom": "^4.2.0",
diff --git a/src/components/PromptLibraryMenu/ExportPrompt.tsx b/src/components/PromptLibraryMenu/ExportPrompt.tsx
new file mode 100644
index 0000000..366eb81
--- /dev/null
+++ b/src/components/PromptLibraryMenu/ExportPrompt.tsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import useStore from '@store/store';
+import { exportPrompts } from '@utils/prompt';
+
+const ExportPrompt = () => {
+ const { t } = useTranslation();
+ const prompts = useStore.getState().prompts;
+
+ return (
+
+
+ {t('export')}
+
+
+
+ );
+};
+
+export default ExportPrompt;
diff --git a/src/components/PromptLibraryMenu/ImportPrompt.tsx b/src/components/PromptLibraryMenu/ImportPrompt.tsx
new file mode 100644
index 0000000..661c99c
--- /dev/null
+++ b/src/components/PromptLibraryMenu/ImportPrompt.tsx
@@ -0,0 +1,84 @@
+import React, { useRef, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { v4 as uuidv4 } from 'uuid';
+import useStore from '@store/store';
+
+import { importPromptCSV } from '@utils/prompt';
+
+const ImportPrompt = () => {
+ const { t } = useTranslation();
+
+ const inputRef = useRef(null);
+ const [alert, setAlert] = useState<{
+ message: string;
+ success: boolean;
+ } | null>(null);
+
+ const handleFileUpload = () => {
+ if (!inputRef || !inputRef.current) return;
+ const file = inputRef.current.files?.[0];
+ if (file) {
+ const reader = new FileReader();
+
+ reader.onload = (event) => {
+ const csvString = event.target?.result as string;
+
+ try {
+ const results = importPromptCSV(csvString);
+
+ const prompts = useStore.getState().prompts;
+ const setPrompts = useStore.getState().setPrompts;
+
+ const newPrompts = results.map((data) => {
+ const columns = Object.values(data);
+ return {
+ id: uuidv4(),
+ name: columns[0],
+ prompt: columns[1],
+ };
+ });
+
+ setPrompts(prompts.concat(newPrompts));
+
+ setAlert({ message: 'Succesfully imported!', success: true });
+ } catch (error: unknown) {
+ setAlert({ message: (error as Error).message, success: false });
+ }
+ };
+
+ reader.readAsText(file);
+ }
+ };
+
+ return (
+
+
+
+
+ {alert && (
+
+ {alert.message}
+
+ )}
+
+ );
+};
+
+export default ImportPrompt;
diff --git a/src/components/PromptLibraryMenu/PromptLibraryMenu.tsx b/src/components/PromptLibraryMenu/PromptLibraryMenu.tsx
index 568c431..f7d2d52 100644
--- a/src/components/PromptLibraryMenu/PromptLibraryMenu.tsx
+++ b/src/components/PromptLibraryMenu/PromptLibraryMenu.tsx
@@ -7,6 +7,8 @@ import { Prompt } from '@type/prompt';
import PlusIcon from '@icon/PlusIcon';
import CrossIcon from '@icon/CrossIcon';
import { v4 as uuidv4 } from 'uuid';
+import ImportPrompt from './ImportPrompt';
+import ExportPrompt from './ExportPrompt';
const PromptLibraryMenu = () => {
const { t } = useTranslation();
@@ -31,8 +33,10 @@ const PromptLibraryMenuPopUp = ({
const { t } = useTranslation();
const setPrompts = useStore((state) => state.setPrompts);
+ const prompts = useStore((state) => state.prompts);
+
const [_prompts, _setPrompts] = useState(
- JSON.parse(JSON.stringify(useStore.getState().prompts))
+ JSON.parse(JSON.stringify(prompts))
);
const container = useRef(null);
@@ -74,6 +78,10 @@ const PromptLibraryMenuPopUp = ({
e.target.style.maxHeight = '2.5rem';
};
+ useEffect(() => {
+ _setPrompts(prompts);
+ }, [prompts]);
+
return (
+
+
+
+
{t('name')}
diff --git a/src/utils/prompt.ts b/src/utils/prompt.ts
new file mode 100644
index 0000000..e78ceb1
--- /dev/null
+++ b/src/utils/prompt.ts
@@ -0,0 +1,31 @@
+import { Prompt } from '@type/prompt';
+import { getToday } from './date';
+
+import Papa from 'papaparse';
+
+export const importPromptCSV = (csvString: string, header: boolean = true) => {
+ const results = Papa.parse(csvString, {
+ header,
+ delimiter: ',',
+ newline: '\n',
+ skipEmptyLines: true,
+ });
+
+ return results.data as Record
[];
+};
+
+export const exportPrompts = (prompts: Prompt[]) => {
+ const csvString = Papa.unparse(
+ prompts.map((prompt) => ({ name: prompt.name, prompt: prompt.prompt }))
+ );
+
+ const blob = new Blob([csvString], {
+ type: 'text/csv;charset=utf-8;',
+ });
+ const url = URL.createObjectURL(blob);
+ const link = document.createElement('a');
+ link.href = url;
+ link.download = `${getToday()}.csv`;
+ link.click();
+ link.remove();
+};
diff --git a/yarn.lock b/yarn.lock
index 7a86cde..79e8583 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -609,6 +609,13 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.23.tgz#b6e934fe427eb7081d0015aad070acb3373c3c90"
integrity sha512-XAMpaw1s1+6zM+jn2tmw8MyaRDIJfXxqmIQIS0HfoGYPuf7dUWeiUKopwq13KFX9lEp1+THGtlaaYx39Nxr58g==
+"@types/papaparse@^5.3.7":
+ version "5.3.7"
+ resolved "https://registry.yarnpkg.com/@types/papaparse/-/papaparse-5.3.7.tgz#8d3bf9e62ac2897df596f49d9ca59a15451aa247"
+ integrity sha512-f2HKmlnPdCvS0WI33WtCs5GD7X1cxzzS/aduaxSu3I7TbhWlENjSPs6z5TaB9K0J+BH1jbmqTaM+ja5puis4wg==
+ dependencies:
+ "@types/node" "*"
+
"@types/parse-json@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
@@ -2992,6 +2999,11 @@ p-cancelable@^2.0.0:
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf"
integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==
+papaparse@^5.4.1:
+ version "5.4.1"
+ resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-5.4.1.tgz#f45c0f871853578bd3a30f92d96fdcfb6ebea127"
+ integrity sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==
+
parent-module@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"