top right buttons styling fixes and tooltip (profile dropdown/activity/settings)

This commit is contained in:
bflatastic committed 2025-05-02 12:12:18 +07:00
1 parent a1aacad7dd
commit 9d6b31200e
3 files changed
+142 -174

No files matched your search

@@ -1,12 +1,12 @@
import { faGear, faImages } from "@fortawesome/pro-solid-svg-icons";
import { twMerge } from "tailwind-merge";
import { Activity } from "~/components/ui/Activity/Activity";
import { GalleryModal } from "@storyteller/ui-gallery-modal";
import { Button } from "@storyteller/ui-button";
import { SettingsModal } from "@storyteller/ui-settings-modal";
import { useState } from "react";
import { AuthButtons } from "~/components/shared_authentication/AuthButtons";
import { Tooltip } from "@storyteller/ui-tooltip";
export const ToolbarTopRight = () => {
const [isSettingsModalOpen, setIsSettingsModalOpen] = useState(false);
@@ -18,11 +18,13 @@ export const ToolbarTopRight = () => {
<div
className={twMerge("relative z-50 flex h-fit w-fit items-center gap-2")}
>
<Button
icon={faGear}
className="h-[42px] w-[42px] bg-[#5F5F68]/60 backdrop-blur-lg hover:bg-[#5F5F68]/90"
onClick={() => setIsSettingsModalOpen(true)}
/>
<Tooltip content="Settings" position="bottom">
<Button
icon={faGear}
className="h-[42px] w-[42px] bg-[#5F5F68]/60 backdrop-blur-lg hover:bg-[#5F5F68]/90"
onClick={() => setIsSettingsModalOpen(true)}
/>
</Tooltip>
<Button
icon={faImages}
className="h-[42px] bg-[#5F5F68]/60 backdrop-blur-lg hover:bg-[#5F5F68]/90"
@@ -31,7 +33,7 @@ export const ToolbarTopRight = () => {
My Gallery
</Button>
<Activity />
<AuthButtons/>
<AuthButtons />
</div>
<SettingsModal
isOpen={isSettingsModalOpen}
@@ -1,5 +1,4 @@
import { twMerge } from "tailwind-merge";
import { Fragment } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faChevronDown,
@@ -8,10 +7,7 @@ import {
} from "@fortawesome/pro-solid-svg-icons";
import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
import { Gravatar } from "../../ui/Gravatar";
import { authentication } from "~/signals";
// style constants
import {
paperWrapperStyles,
transitionTimingStyles,
@@ -35,71 +31,79 @@ export function ProfileDropdown() {
return (
<Menu as="div" className="relative">
<MenuButton
className={twMerge(
"flex cursor-pointer items-center gap-1.5",
"data-[hover]:opacity-70",
)}
>
<Gravatar
size={34}
username={userInfo.value.display_name}
email_hash={userInfo.value.email_gravatar_hash}
avatarIndex={
Number(userInfo.value.core_info.default_avatar.image_index) || 0
}
backgroundIndex={
Number(userInfo.value.core_info.default_avatar.color_index) || 0
}
/>
<FontAwesomeIcon icon={faChevronDown} />
</MenuButton>
<MenuItems
anchor="bottom end"
transition
className={twMerge(
paperWrapperStyles,
"mt-4 flex w-48 flex-col rounded-xl shadow-lg",
transitionTimingStyles,
"data-[closed]:scale-95 data-[closed]:opacity-0",
)}
>
<MenuItem
as="button"
href={profileUrl}
target="_blank"
rel="noreferrer"
className={twMerge(
"flex w-full items-center gap-3 rounded-lg px-3 py-2",
"text-md font-medium text-white hover:bg-gray-100 hover:text-gray-700",
"transition-colors duration-150",
)}
>
<FontAwesomeIcon icon={faUser} className="w-4" />
My Profile
</MenuItem>
{menuOptions.map((option, index) => (
<MenuItem
key={index}
as="button"
{({ close }) => (
<>
<MenuButton
className={twMerge(
"flex w-full items-center gap-3 rounded-lg px-3 py-2",
"text-md font-medium text-white hover:bg-gray-100 hover:text-gray-700",
"transition-colors duration-150",
"flex cursor-pointer items-center gap-1.5",
"data-[hover]:opacity-70",
)}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
option.onClick();
}}
>
<FontAwesomeIcon icon={option.icon} className="w-4" />
<span>{option.label}</span>
</MenuItem>
))}
</MenuItems>
<Gravatar
size={34}
username={userInfo.value!.display_name}
email_hash={userInfo.value!.email_gravatar_hash}
avatarIndex={
Number(userInfo.value!.core_info.default_avatar.image_index) ||
0
}
backgroundIndex={
Number(userInfo.value!.core_info.default_avatar.color_index) ||
0
}
/>
<FontAwesomeIcon icon={faChevronDown} />
</MenuButton>
<MenuItems
anchor="bottom end"
transition
className={twMerge(
paperWrapperStyles,
"mt-4 flex w-40 flex-col rounded-lg shadow-lg",
transitionTimingStyles,
"data-[closed]:scale-95 data-[closed]:opacity-0",
"focus:outline-none focus:ring-0",
)}
>
<MenuItem
as="a"
href={profileUrl}
target="_blank"
rel="noreferrer"
className={twMerge(
"flex w-full items-center gap-2.5 rounded-lg px-3 py-2",
"text-sm font-medium !text-white hover:bg-[#63636B]/60",
"transition-colors duration-150",
)}
>
<FontAwesomeIcon icon={faUser} className="w-4" />
My Profile
</MenuItem>
{menuOptions.map((option, index) => (
<MenuItem
key={index}
as="button"
className={twMerge(
"flex w-full items-center gap-2.5 rounded-lg px-3 py-2",
"text-sm font-medium text-white hover:bg-[#63636B]/60",
"transition-colors duration-150",
)}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
option.onClick();
close();
}}
>
<FontAwesomeIcon icon={option.icon} className="w-4" />
<span>{option.label}</span>
</MenuItem>
))}
</MenuItems>
</>
)}
</Menu>
);
}
@@ -7,6 +7,7 @@ import { InProgressCard } from "./InProgressCard";
import { useJobContext } from "~/components/JobContext";
import { Api } from "~/KonvaApp/Api";
import { toast } from "sonner";
import { Tooltip } from "@storyteller/ui-tooltip";
// Dummy data types
interface CompletedItem {
@@ -27,48 +28,8 @@ interface ActiveJob {
};
}
// Dummy data for testing
const dummyCompletedItems: CompletedItem[] = [
{
token: "1",
maybe_title: "Completed Item 1",
public_bucket_path: "/test1",
updated_at: new Date().toISOString(),
},
{
token: "2",
maybe_title: "Completed Item 2",
public_bucket_path: "/test2",
updated_at: new Date().toISOString(),
},
];
// const dummyJobs: ActiveJob[] = [
// {
// job_token: "job1",
// request: {
// maybe_model_title: "In Progress Job 1",
// },
// status: {
// status: "STARTED",
// progress_percentage: 45,
// },
// },
// {
// job_token: "job2",
// request: {
// maybe_model_title: "In Progress Job 2",
// },
// status: {
// status: "PENDING",
// progress_percentage: 0,
// },
// },
// ];
export function Activity() {
const { jobTokens, addJobToken, removeJobToken, clearJobTokens } =
useJobContext();
const { jobTokens, removeJobToken } = useJobContext();
const [completedItems, setCompletedItems] = useState<CompletedItem[]>([]);
const [jobs, setJobs] = useState<ActiveJob[]>([]);
const [loading, setLoading] = useState(true);
@@ -150,68 +111,69 @@ export function Activity() {
}, [jobTokens, removeJobToken]);
return (
<PopoverMenu
mode="default"
buttonClassName="h-[42px] px-4"
panelClassName="w-[360px] p-2"
position="bottom"
align="end"
triggerIcon={
<div>
<span className="text-md flex items-center gap-2">
<>
{jobs.length > 0 ? (
<FontAwesomeIcon
icon={faSpinnerThird}
className="animate-spin"
/>
) : (
<FontAwesomeIcon icon={faBell} />
)}
Activity
</>
</span>
<Tooltip content="Activity" position="bottom">
<PopoverMenu
mode="default"
buttonClassName="h-[42px] w-[42px] px-4"
panelClassName="w-[360px] p-2"
position="bottom"
align="end"
triggerIcon={
<div>
<span className="text-md flex items-center gap-2">
<>
{jobs.length > 0 ? (
<FontAwesomeIcon
icon={faSpinnerThird}
className="animate-spin"
/>
) : (
<FontAwesomeIcon icon={faBell} />
)}
</>
</span>
{jobs.length > 0 && (
<div className="absolute -right-1 -top-1 h-3 w-3 animate-pulse rounded-full bg-blue-500" />
)}
</div>
}
>
<div className="max-h-[480px] overflow-y-auto">
{/* In progress */}
{jobs.length > 0 && (
<div className="absolute -right-1 -top-1 h-3 w-3 animate-pulse rounded-full bg-blue-500" />
)}
</div>
}
>
<div className="max-h-[480px] overflow-y-auto">
{/* In progress */}
{jobs.length > 0 && (
<div>
{jobs.map((job) => (
<InProgressCard key={job.job_token} job={job} />
))}
</div>
)}
{loading ? (
<div className="flex h-48 w-full flex-col justify-center gap-4 p-4 text-center align-middle">
<FontAwesomeIcon
icon={faSpinnerThird}
spin
size="2x"
className="text-gray-400"
/>
<h3 className="text-gray-300">Retrieving Activities</h3>
</div>
) : completedItems.length === 0 && jobs.length === 0 ? (
<div className="flex h-48 w-full flex-col justify-center gap-4 p-4 text-center align-middle">
<h3 className="text-gray-300">No activities yet</h3>
</div>
) : (
<div>
{/* Completed */}
<div className="flex flex-col">
{completedItems.map((item) => (
<CompletedCard key={item.token} job={item} />
<div>
{jobs.map((job) => (
<InProgressCard key={job.job_token} job={job} />
))}
</div>
</div>
)}
</div>
</PopoverMenu>
)}
{loading ? (
<div className="flex h-48 w-full flex-col justify-center gap-4 p-4 text-center align-middle">
<FontAwesomeIcon
icon={faSpinnerThird}
spin
size="2x"
className="text-gray-400"
/>
<h3 className="text-gray-300">Retrieving Activities</h3>
</div>
) : completedItems.length === 0 && jobs.length === 0 ? (
<div className="flex h-48 w-full flex-col justify-center gap-4 p-4 text-center align-middle">
<h3 className="text-gray-300">No activities yet</h3>
</div>
) : (
<div>
{/* Completed */}
<div className="flex flex-col">
{completedItems.map((item) => (
<CompletedCard key={item.token} job={item} />
))}
</div>
</div>
)}
</div>
</PopoverMenu>
</Tooltip>
);
}