mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-01-07 11:08:52 +01:00
complete renaming functions, abstracts more svg, sets title to current convo title, adds a try again feature to errors
This commit is contained in:
parent
592b7629aa
commit
5af5a97d8f
24 changed files with 512 additions and 82 deletions
108
src/components/Conversations/Conversation copy.jsx
Normal file
108
src/components/Conversations/Conversation copy.jsx
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
import React from 'react';
|
||||
import RenameButton from './RenameButton';
|
||||
import DeleteButton from './DeleteButton';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { setConversation } from '~/store/convoSlice';
|
||||
import { setMessages } from '~/store/messageSlice';
|
||||
import { setText } from '~/store/textSlice';
|
||||
import manualSWR from '~/utils/fetchers';
|
||||
|
||||
{
|
||||
/* <div class="flex py-3 px-3 items-center gap-3 relative rounded-md cursor-pointer hover:pr-14 break-all pr-14 bg-gray-800 hover:bg-gray-800"><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4 flex-shrink-0" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path></svg><input type="text" class="text-sm border-none bg-transparent p-0 m-0 w-full mr-0" value="titleeeeeeeeeeeeeeeee"><div class="absolute flex right-1 z-10 text-gray-300 visible"><button class="p-1 hover:text-white"><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><polyline points="20 6 9 17 4 12"></polyline></svg></button><button class="p-1 hover:text-white"><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button></div></div> */
|
||||
}
|
||||
|
||||
export default function Conversation({ id, parentMessageId, title = 'New conversation' }) {
|
||||
const dispatch = useDispatch();
|
||||
const { conversationId } = useSelector((state) => state.convo);
|
||||
const { trigger, isMutating } = manualSWR(`http://localhost:3050/messages/${id}`, 'get');
|
||||
|
||||
const clickHandler = async () => {
|
||||
if (conversationId === id) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(setConversation({ error: false, conversationId: id, parentMessageId }));
|
||||
const data = await trigger();
|
||||
dispatch(setMessages(data));
|
||||
dispatch(setText(''));
|
||||
};
|
||||
|
||||
const aProps = {
|
||||
className:
|
||||
'animate-flash group relative flex cursor-pointer items-center gap-3 break-all rounded-md bg-gray-800 py-3 px-3 pr-14 hover:bg-gray-800'
|
||||
};
|
||||
|
||||
if (conversationId !== id) {
|
||||
aProps.className =
|
||||
'group relative flex cursor-pointer items-center gap-3 break-all rounded-md py-3 px-3 hover:bg-[#2A2B32] hover:pr-4';
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="relative flex cursor-pointer items-center gap-3 break-all rounded-md bg-gray-800 py-3 px-3 pr-14 hover:bg-gray-800 hover:pr-14">
|
||||
<svg
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="h-4 w-4 flex-shrink-0"
|
||||
height="1em"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
|
||||
</svg>
|
||||
<input
|
||||
type="text"
|
||||
class="m-0 mr-0 w-full border-none bg-transparent p-0 text-sm"
|
||||
value="titleeeeeeeeeeeeeeeee"
|
||||
/>
|
||||
<div class="visible absolute right-1 z-10 flex text-gray-300">
|
||||
<button class="p-1 hover:text-white">
|
||||
<svg
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="h-4 w-4"
|
||||
height="1em"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<polyline points="20 6 9 17 4 12"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="p-1 hover:text-white">
|
||||
<svg
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="h-4 w-4"
|
||||
height="1em"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<line
|
||||
x1="18"
|
||||
y1="6"
|
||||
x2="6"
|
||||
y2="18"
|
||||
></line>
|
||||
<line
|
||||
x1="6"
|
||||
y1="6"
|
||||
x2="18"
|
||||
y2="18"
|
||||
></line>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import React from 'react';
|
||||
import React, { useState, useRef } from 'react';
|
||||
import RenameButton from './RenameButton';
|
||||
import DeleteButton from './DeleteButton';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
|
|
@ -6,23 +6,56 @@ import { setConversation } from '~/store/convoSlice';
|
|||
import { setMessages } from '~/store/messageSlice';
|
||||
import { setText } from '~/store/textSlice';
|
||||
import manualSWR from '~/utils/fetchers';
|
||||
import ConvoIcon from '../svg/ConvoIcon';
|
||||
|
||||
export default function Conversation({ id, parentMessageId, title = 'New conversation' }) {
|
||||
const [renaming, setRenaming] = useState(false);
|
||||
const [titleInput, setTitleInput] = useState(title);
|
||||
const inputRef = useRef(null);
|
||||
const dispatch = useDispatch();
|
||||
const { conversationId } = useSelector((state) => state.convo);
|
||||
const { trigger, isMutating } = manualSWR(`http://localhost:3050/messages/${id}`, 'get');
|
||||
const rename = manualSWR(`http://localhost:3050/update_convo`, 'post');
|
||||
|
||||
const clickHandler = async () => {
|
||||
if (conversationId === id) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(setConversation({ error: false, conversationId: id, parentMessageId }));
|
||||
dispatch(setConversation({ title, error: false, conversationId: id, parentMessageId }));
|
||||
const data = await trigger();
|
||||
dispatch(setMessages(data));
|
||||
dispatch(setText(''));
|
||||
};
|
||||
|
||||
const renameHandler = (e) => {
|
||||
e.preventDefault();
|
||||
setRenaming(true);
|
||||
setTimeout(() => {
|
||||
inputRef.current.focus();
|
||||
}, 25);
|
||||
};
|
||||
|
||||
const cancelHandler = (e) => {
|
||||
e.preventDefault();
|
||||
setRenaming(false);
|
||||
};
|
||||
|
||||
const onRename = (e) => {
|
||||
e.preventDefault();
|
||||
setRenaming(false);
|
||||
if (titleInput === title) {
|
||||
return;
|
||||
}
|
||||
rename.trigger({ conversationId, title: titleInput });
|
||||
};
|
||||
|
||||
const handleKeyPress = (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
onRename(e);
|
||||
}
|
||||
};
|
||||
|
||||
const aProps = {
|
||||
className:
|
||||
'animate-flash group relative flex cursor-pointer items-center gap-3 break-all rounded-md bg-gray-800 py-3 px-3 pr-14 hover:bg-gray-800'
|
||||
|
|
@ -38,27 +71,35 @@ export default function Conversation({ id, parentMessageId, title = 'New convers
|
|||
onClick={() => clickHandler()}
|
||||
{...aProps}
|
||||
>
|
||||
<svg
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeWidth="2"
|
||||
viewBox="0 0 24 24"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="h-4 w-4"
|
||||
height="1em"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
|
||||
</svg>
|
||||
<ConvoIcon />
|
||||
<div className="relative max-h-5 flex-1 overflow-hidden text-ellipsis break-all">
|
||||
{title}
|
||||
{renaming === true ? (
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
className="m-0 mr-0 w-full leading-tight border border-blue-500 bg-transparent p-0 text-sm outline-none"
|
||||
value={titleInput}
|
||||
onChange={(e) => setTitleInput(e.target.value)}
|
||||
onBlur={onRename}
|
||||
onKeyPress={handleKeyPress}
|
||||
/>
|
||||
) : (
|
||||
title
|
||||
)}
|
||||
</div>
|
||||
{conversationId === id ? (
|
||||
<div className="visible absolute right-1 z-10 flex text-gray-300">
|
||||
<RenameButton conversationId={id} />
|
||||
<DeleteButton conversationId={id} />
|
||||
<RenameButton
|
||||
conversationId={id}
|
||||
renaming={renaming}
|
||||
renameHandler={renameHandler}
|
||||
onRename={onRename}
|
||||
/>
|
||||
<DeleteButton
|
||||
conversationId={id}
|
||||
renaming={renaming}
|
||||
cancelHandler={cancelHandler}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="absolute inset-y-0 right-0 z-10 w-8 bg-gradient-to-l from-gray-900 group-hover:from-[#2A2B32]" />
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import React from 'react';
|
||||
import TrashIcon from '../svg/TrashIcon';
|
||||
import CrossIcon from '../svg/CrossIcon';
|
||||
import manualSWR from '~/utils/fetchers';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { setConversation } from '~/store/convoSlice';
|
||||
import { setMessages } from '~/store/messageSlice';
|
||||
|
||||
export default function DeleteButton({ conversationId }) {
|
||||
export default function DeleteButton({ conversationId, renaming, cancelHandler }) {
|
||||
const dispatch = useDispatch();
|
||||
const { trigger, isMutating } = manualSWR(
|
||||
'http://localhost:3050/clear_convos',
|
||||
|
|
@ -17,13 +18,14 @@ export default function DeleteButton({ conversationId }) {
|
|||
);
|
||||
|
||||
const clickHandler = () => trigger({ conversationId });
|
||||
const handler = renaming ? cancelHandler : clickHandler;
|
||||
|
||||
return (
|
||||
<button
|
||||
className="p-1 hover:text-white"
|
||||
onClick={clickHandler}
|
||||
onClick={handler}
|
||||
>
|
||||
<TrashIcon />
|
||||
{ renaming ? <CrossIcon/> : <TrashIcon />}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,13 @@
|
|||
import React from 'react';
|
||||
import RenameIcon from '../svg/RenameIcon';
|
||||
import CheckMark from '../svg/CheckMark';
|
||||
|
||||
export default function RenameButton({ onClick, renaming, renameHandler, onRename }) {
|
||||
const handler = renaming ? onRename : renameHandler;
|
||||
|
||||
export default function RenameButton({ onClick, disabled }) {
|
||||
return (
|
||||
<button className="p-1 hover:text-white">
|
||||
<svg
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeWidth="2"
|
||||
viewBox="0 0 24 24"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="h-4 w-4"
|
||||
height="1em"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M12 20h9" />
|
||||
<path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z" />
|
||||
</svg>
|
||||
<button className="p-1 hover:text-white" onClick={handler}>
|
||||
{renaming ? <CheckMark /> : <RenameIcon />}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export default function NewChat() {
|
|||
const clickHandler = () => {
|
||||
dispatch(setText(''));
|
||||
dispatch(setMessages([]));
|
||||
dispatch(setConversation({ error: false, conversationId: null, parentMessageId: null }));
|
||||
dispatch(setConversation({ title: 'New Chat', error: false, conversationId: null, parentMessageId: null }));
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
|||
20
src/components/Prompts/Prompt.jsx
Normal file
20
src/components/Prompts/Prompt.jsx
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import React from 'react';
|
||||
|
||||
export default function Prompt({ title, prompt, id }) {
|
||||
return (
|
||||
<div
|
||||
// onclick="selectPromptTemplate(0)"
|
||||
className="flex w-full flex-col gap-2 rounded-md bg-gray-50 p-4 text-left hover:bg-gray-200 dark:bg-white/5 "
|
||||
>
|
||||
<h2 className="m-auto flex items-center gap-3 text-lg font-normal md:flex-col md:gap-2">
|
||||
{ title }
|
||||
</h2>
|
||||
<button>
|
||||
<p className="w-full rounded-md bg-gray-50 p-3 hover:bg-gray-200 dark:bg-white/5 dark:hover:bg-gray-900">
|
||||
{prompt}
|
||||
</p>
|
||||
</button>
|
||||
<span className="font-medium">Use prompt →</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@ export default function Templates() {
|
|||
</span>
|
||||
<div
|
||||
// onclick="selectPromptTemplate(0)"
|
||||
className="flex w-full flex-col gap-2 rounded-md bg-gray-50 p-4 text-left hover:bg-gray-200 dark:bg-white/5 dark:hover:bg-gray-900"
|
||||
className="flex w-full flex-col gap-2 rounded-md bg-gray-50 p-4 text-left hover:bg-gray-200 dark:bg-white/5 "
|
||||
>
|
||||
<h2 className="m-auto flex items-center gap-3 text-lg font-normal md:flex-col md:gap-2">
|
||||
DAN (Do Anything Now)
|
||||
|
|
@ -1,13 +1,15 @@
|
|||
import React from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { setText } from '~/store/textSlice';
|
||||
import Templates from './Templates';
|
||||
import useDocumentTitle from '~/hooks/useDocumentTitle';
|
||||
import Templates from '../Prompts/Templates';
|
||||
import SunIcon from '../svg/SunIcon';
|
||||
import LightningIcon from '../svg/LightningIcon';
|
||||
import CautionIcon from '../svg/CautionIcon';
|
||||
|
||||
export default function Landing() {
|
||||
export default function Landing({ title }) {
|
||||
const dispatch = useDispatch();
|
||||
useDocumentTitle(title);
|
||||
|
||||
const clickHandler = (e) => {
|
||||
e.preventDefault();
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
import React, { useEffect, useRef } from 'react';
|
||||
import useDocumentTitle from '~/hooks/useDocumentTitle';
|
||||
import Message from './Message';
|
||||
import Landing from './Landing';
|
||||
|
||||
export default function Messages({ messages }) {
|
||||
export default function Messages({ messages, title }) {
|
||||
if (messages.length === 0) {
|
||||
return <Landing />;
|
||||
return <Landing title={title}/>;
|
||||
}
|
||||
|
||||
useDocumentTitle(title);
|
||||
|
||||
const messagesEndRef = useRef(null);
|
||||
|
||||
const scrollToBottom = () => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import RegenerateIcon from '../svg/RegenerateIcon';
|
||||
|
||||
export default function Regenerate({ submitMessage }) {
|
||||
export default function Regenerate({ submitMessage, tryAgain }) {
|
||||
const clickHandler = (e) => {
|
||||
e.preventDefault();
|
||||
submitMessage();
|
||||
|
|
@ -8,31 +9,22 @@ export default function Regenerate({ submitMessage }) {
|
|||
|
||||
return (
|
||||
<>
|
||||
<span className="mb-auto block flex justify-center text-xs md:mb-auto">
|
||||
<span className="mb-2 block flex justify-center text-xs md:mb-2">
|
||||
There was an error generating a response
|
||||
</span>
|
||||
<button
|
||||
onClick={clickHandler}
|
||||
className="btn btn-primary m-auto flex justify-center gap-2"
|
||||
>
|
||||
<svg
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeWidth="1.5"
|
||||
viewBox="0 0 24 24"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="h-3 w-3"
|
||||
height="1em"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
<span className="m-auto flex justify-center">
|
||||
<button
|
||||
onClick={clickHandler}
|
||||
className="btn btn-primary m-auto flex justify-center gap-2"
|
||||
>
|
||||
<polyline points="1 4 1 10 7 10" />
|
||||
<polyline points="23 20 23 14 17 14" />
|
||||
<path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15" />
|
||||
</svg>
|
||||
Regenerate response
|
||||
</button>
|
||||
<RegenerateIcon />
|
||||
Regenerate response
|
||||
</button>
|
||||
<button onClick={tryAgain} className="btn btn-neutral flex justify-center gap-2 border-0 md:border">
|
||||
<RegenerateIcon />
|
||||
Try another message
|
||||
</button>
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,6 +88,11 @@ export default function TextChat({ messages, reloadConvos }) {
|
|||
dispatch(setText(value));
|
||||
};
|
||||
|
||||
const tryAgain = (e) => {
|
||||
e.preventDefault();
|
||||
dispatch(setError(false));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="md:bg-vert-light-gradient dark:md:bg-vert-dark-gradient absolute bottom-0 left-0 w-full border-t bg-white dark:border-white/20 dark:bg-gray-800 md:border-t-0 md:border-transparent md:!bg-transparent md:dark:border-transparent">
|
||||
<form className="stretch mx-2 flex flex-row gap-3 pt-2 last:mb-2 md:last:mb-6 lg:mx-auto lg:max-w-3xl lg:pt-6">
|
||||
|
|
@ -97,7 +102,10 @@ export default function TextChat({ messages, reloadConvos }) {
|
|||
{/* removed this prop shadow-[0_0_10px_rgba(0,0,0,0.10)] dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] */}
|
||||
|
||||
{!!error ? (
|
||||
<Regenerate submitMessage={submitMessage} />
|
||||
<Regenerate
|
||||
submitMessage={submitMessage}
|
||||
tryAgain={tryAgain}
|
||||
/>
|
||||
) : (
|
||||
<div className="relative flex w-full flex-grow flex-col rounded-md border border-black/10 bg-white py-2 shadow-md dark:border-gray-900/50 dark:bg-gray-700 dark:text-white dark:shadow-lg md:py-3 md:pl-4">
|
||||
<TextareaAutosize
|
||||
|
|
|
|||
20
src/components/svg/CheckMark.jsx
Normal file
20
src/components/svg/CheckMark.jsx
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import React from 'react';
|
||||
|
||||
export default function CheckMark() {
|
||||
return (
|
||||
<svg
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeWidth="2"
|
||||
viewBox="0 0 24 24"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="h-4 w-4"
|
||||
height="1em"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<polyline points="20 6 9 17 4 12" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
20
src/components/svg/ConvoIcon.jsx
Normal file
20
src/components/svg/ConvoIcon.jsx
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import React from 'react';
|
||||
|
||||
export default function ConvoIcon() {
|
||||
return (
|
||||
<svg
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeWidth="2"
|
||||
viewBox="0 0 24 24"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="h-4 w-4"
|
||||
height="1em"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
31
src/components/svg/CrossIcon.jsx
Normal file
31
src/components/svg/CrossIcon.jsx
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import React from 'react';
|
||||
|
||||
export default function CrossIcon() {
|
||||
return (
|
||||
<svg
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeWidth="2"
|
||||
viewBox="0 0 24 24"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="h-4 w-4"
|
||||
height="1em"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<line
|
||||
x1="18"
|
||||
y1="6"
|
||||
x2="6"
|
||||
y2="18"
|
||||
/>
|
||||
<line
|
||||
x1="6"
|
||||
y1="6"
|
||||
x2="18"
|
||||
y2="18"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
22
src/components/svg/RegenerateIcon.jsx
Normal file
22
src/components/svg/RegenerateIcon.jsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import React from 'react';
|
||||
|
||||
export default function Regenerate() {
|
||||
return (
|
||||
<svg
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeWidth="1.5"
|
||||
viewBox="0 0 24 24"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="h-3 w-3"
|
||||
height="1em"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<polyline points="1 4 1 10 7 10" />
|
||||
<polyline points="23 20 23 14 17 14" />
|
||||
<path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
21
src/components/svg/RenameIcon.jsx
Normal file
21
src/components/svg/RenameIcon.jsx
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import React from 'react';
|
||||
|
||||
export default function RenameIcon() {
|
||||
return (
|
||||
<svg
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeWidth="2"
|
||||
viewBox="0 0 24 24"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="h-4 w-4"
|
||||
height="1em"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M12 20h9" />
|
||||
<path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue