Implement thread UI update ()

* Implement thread UI update

* remove comment
This commit is contained in:
Timothy Carambat 2024-02-14 12:31:43 -08:00 committed by GitHub
parent ee3a79fdcf
commit 161dc5f901
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 78 additions and 31 deletions
frontend/src/components/Sidebar/ActiveWorkspaces
ThreadContainer
index.jsx

View file

@ -7,13 +7,20 @@ import { useParams } from "react-router-dom";
import truncate from "truncate";
const THREAD_CALLOUT_DETAIL_WIDTH = 26;
export default function ThreadItem({ workspace, thread, onRemove, hasNext }) {
export default function ThreadItem({
idx,
activeIdx,
isActive,
workspace,
thread,
onRemove,
hasNext,
}) {
const optionsContainer = useRef(null);
const { slug, threadSlug = null } = useParams();
const { slug } = useParams();
const [showOptions, setShowOptions] = useState(false);
const [name, setName] = useState(thread.name);
const isActive = threadSlug === thread.slug;
const linkTo = !thread.slug
? paths.workspace.chat(slug)
: paths.workspace.thread(slug, thread.slug);
@ -23,33 +30,48 @@ export default function ThreadItem({ workspace, thread, onRemove, hasNext }) {
{/* Curved line Element and leader if required */}
<div
style={{ width: THREAD_CALLOUT_DETAIL_WIDTH / 2 }}
className="border-l border-b border-slate-300 h-[50%] absolute top-0 left-2 rounded-bl-lg"
className={`${
isActive
? "border-l-2 border-b-2 border-white"
: "border-l border-b border-slate-300"
} h-[50%] absolute top-0 left-2 rounded-bl-lg`}
></div>
{/* Downstroke border for next item */}
{hasNext && (
<div
style={{ width: THREAD_CALLOUT_DETAIL_WIDTH / 2 }}
className="border-l border-slate-300 h-[100%] absolute top-0 left-2"
className={`${
idx <= activeIdx && !isActive
? "border-l-2 border-white"
: "border-l border-slate-300"
} h-[100%] absolute top-0 left-2`}
></div>
)}
{/* Curved line inline placeholder for spacing */}
{/* Curved line inline placeholder for spacing - not visible */}
<div
style={{ width: THREAD_CALLOUT_DETAIL_WIDTH }}
className="w-[26px] h-full"
/>
<div className="flex w-full items-center justify-between pr-2 group relative">
<a href={isActive ? "#" : linkTo} className="w-full">
<p
className={`text-left text-sm ${
isActive
? "font-semibold text-slate-300"
: "text-slate-400 italic"
}`}
>
{truncate(name, 25)}
</p>
</a>
{!!thread.slug && (
{thread.deleted ? (
<a className="w-full">
<p className={`text-left text-sm text-slate-400/50 italic`}>
deleted thread
</p>
</a>
) : (
<a href={isActive ? "#" : linkTo} className="w-full">
<p
className={`text-left text-sm ${
isActive ? "font-bold text-white" : "text-slate-400"
}`}
>
{truncate(name, 25)}
</p>
</a>
)}
{!!thread.slug && !thread.deleted && (
<div ref={optionsContainer}>
<div className="flex items-center w-fit group-hover:visible md:invisible gap-x-1">
<button

View file

@ -4,8 +4,10 @@ import showToast from "@/utils/toast";
import { Plus, CircleNotch } from "@phosphor-icons/react";
import { useEffect, useState } from "react";
import ThreadItem from "./ThreadItem";
import { useParams } from "react-router-dom";
export default function ThreadContainer({ workspace }) {
const { threadSlug = null } = useParams();
const [threads, setThreads] = useState([]);
const [loading, setLoading] = useState(true);
@ -20,7 +22,12 @@ export default function ThreadContainer({ workspace }) {
}, [workspace.slug]);
function removeThread(threadId) {
setThreads((prev) => prev.filter((thread) => thread.id !== threadId));
setThreads((prev) =>
prev.map((_t) => {
if (_t.id !== threadId) return _t;
return { ..._t, deleted: true };
})
);
}
if (loading) {
@ -33,15 +40,26 @@ export default function ThreadContainer({ workspace }) {
);
}
const activeThreadIdx = !!threads.find(
(thread) => thread?.slug === threadSlug
)
? threads.findIndex((thread) => thread?.slug === threadSlug) + 1
: 0;
return (
<div className="flex flex-col">
<ThreadItem
idx={0}
activeIdx={activeThreadIdx}
isActive={activeThreadIdx === 0}
thread={{ slug: null, name: "default" }}
hasNext={threads.length > 0}
/>
{threads.map((thread, i) => (
<ThreadItem
key={thread.slug}
idx={i + 1}
activeIdx={activeThreadIdx}
isActive={activeThreadIdx === i + 1}
workspace={workspace}
onRemove={removeThread}
thread={thread}
@ -54,7 +72,7 @@ export default function ThreadContainer({ workspace }) {
}
function NewThreadButton({ workspace }) {
const [loading, setLoading] = useState();
const [loading, setLoading] = useState(false);
const onClick = async () => {
setLoading(true);
const { thread, error } = await Workspace.threads.new(workspace.slug);
@ -74,15 +92,22 @@ function NewThreadButton({ workspace }) {
className="w-full relative flex h-[40px] items-center border-none hover:bg-slate-600/20 rounded-lg"
>
<div className="flex w-full gap-x-2 items-center pl-4">
<div className="bg-zinc-600 p-2 rounded-lg h-[24px] w-[24px] flex items-center justify-center">
{loading ? (
<CircleNotch
weight="bold"
size={14}
className="shrink-0 animate-spin text-slate-100"
/>
) : (
<Plus weight="bold" size={14} className="shrink-0 text-slate-100" />
)}
</div>
{loading ? (
<CircleNotch className="animate-spin text-slate-300" />
<p className="text-left text-slate-100 text-sm">Starting Thread...</p>
) : (
<Plus className="text-slate-300" />
)}
{loading ? (
<p className="text-left text-slate-300 text-sm">starting thread...</p>
) : (
<p className="text-left text-slate-300 text-sm">new thread</p>
<p className="text-left text-slate-100 text-sm">New Thread</p>
)}
</div>
</button>

View file

@ -80,12 +80,12 @@ export default function ActiveWorkspaces() {
href={isActive ? null : paths.workspace.chat(workspace.slug)}
className={`
transition-all duration-[200ms]
flex flex-grow w-[75%] gap-x-2 py-[6px] px-[12px] rounded-lg text-slate-200 justify-start items-center border
hover:bg-workspace-item-selected-gradient hover:border-slate-100 hover:border-opacity-50
flex flex-grow w-[75%] gap-x-2 py-[6px] px-[12px] rounded-lg text-slate-200 justify-start items-center
hover:bg-workspace-item-selected-gradient
${
isActive
? "bg-workspace-item-selected-gradient border-slate-100 border-opacity-50"
: "bg-workspace-item-gradient bg-opacity-60 border-transparent"
? "border-2 bg-workspace-item-selected-gradient border-white"
: "border bg-workspace-item-gradient bg-opacity-60 border-transparent hover:border-slate-100 hover:border-opacity-50"
}`}
>
<div className="flex flex-row justify-between w-full">