Avatar component; Indicators components.
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
import clsx from "clsx";
|
||||
import CrownIcon from "../icons/CrownIcon";
|
||||
|
||||
export default function Admin({ className }: { className?: string }) {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"size-[1.111vw] border-[1px] border-white rounded-full flex items-center justify-center bg-[#141414]",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className="size-[0.694vw]">
|
||||
<CrownIcon />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import clsx from "clsx";
|
||||
import BookedIcon from "../icons/BookedIcon";
|
||||
|
||||
export default function Booked({ className }: { className?: string }) {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"size-[1.389vw] rounded-full flex items-center justify-center bg-[#F3F1FD]",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className="size-[0.833vw] text-[#7B60F3]">
|
||||
<BookedIcon />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import clsx from "clsx";
|
||||
|
||||
export default function Counter({
|
||||
count,
|
||||
className,
|
||||
}: {
|
||||
count?: number;
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"size-[1.389vw] rounded-full flex items-center justify-center bg-[#F3F1FD]",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className="text-[0.694vw] text-[#7B60F3]">{count || "#"}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import clsx from "clsx";
|
||||
import HearthFilledIcon from "../icons/HearthFilledIcon";
|
||||
|
||||
export default function Favorites({ className }: { className?: string }) {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"size-[1.389vw] rounded-full flex items-center justify-center bg-[#FEF3F2]",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className="size-[0.833vw] text-[#FF4517]">
|
||||
<HearthFilledIcon />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import clsx from "clsx";
|
||||
|
||||
export default function Warning({
|
||||
type,
|
||||
className,
|
||||
}: {
|
||||
type: "caution" | "critical";
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"size-[1.111vw] border-[1px] border-white rounded-full flex items-center justify-center ",
|
||||
type === "caution" && "bg-[#F9A530]",
|
||||
type === "critical" && "bg-[#FF4517]",
|
||||
className
|
||||
)}
|
||||
>
|
||||
!
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -4,11 +4,12 @@ import MicrophoneFilledIcon from "../icons/MicrophoneFilledIcon";
|
||||
import VideoOffFilledIcon from "../icons/VideoOffFilledIcon";
|
||||
import HandRaisedFilledIcon from "../icons/HandRaisedFilledIcon";
|
||||
import XMarkFilledIcon from "../icons/XMarkFilledIcon";
|
||||
import Avatar from "../ui/Avatar";
|
||||
|
||||
export default function ParticipantsPopup() {
|
||||
const participants = [1, 2, 3];
|
||||
return (
|
||||
<PopupWrapper title="Чат" draggable className="h-max">
|
||||
<PopupWrapper title="Участники" draggable className="h-max">
|
||||
<div className="flex flex-col w-[21.667vw] relative">
|
||||
<ul className="flex flex-col gap-[1.111vw]">
|
||||
{participants.map((participant, index) => (
|
||||
@@ -29,13 +30,7 @@ function ParticipantItem({ id }: { id: string }) {
|
||||
return (
|
||||
<div className="flex items-center justify-between w-full h-[2.5vw]">
|
||||
<div className="flex items-center gap-[0.833vw]">
|
||||
<div className="size-[2.5vw] rounded-full bg-[#F6F6F6]">
|
||||
<img
|
||||
src="/img/popups/MessageUserPfp.png"
|
||||
className="size-full object-cover"
|
||||
alt="user"
|
||||
/>
|
||||
</div>
|
||||
<Avatar size="medium" />
|
||||
<div className="flex flex-col gap-[0.278vw]">
|
||||
<span className="button-m">Иван Иванович {id}</span>
|
||||
<span className="caption-s text-[#CCCCCC]">Роль</span>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import Button from "./Button";
|
||||
import MoreIcon from "../icons/MoreIcon";
|
||||
|
||||
interface ActionsPopoverProps {
|
||||
options: {
|
||||
@@ -37,9 +39,6 @@ export default function ActionsPopover({ options }: ActionsPopoverProps) {
|
||||
const buttonRect = buttonRef.current.getBoundingClientRect();
|
||||
const spaceBelow = window.innerHeight - buttonRect.bottom;
|
||||
const spaceAbove = buttonRect.top;
|
||||
|
||||
console.log(spaceBelow, menuHeight, spaceAbove);
|
||||
// Если снизу недостаточно места, но сверху достаточно - открываем вверх
|
||||
if (spaceBelow < menuHeight && spaceAbove > menuHeight) {
|
||||
setOpenUpwards(true);
|
||||
} else {
|
||||
@@ -52,12 +51,12 @@ export default function ActionsPopover({ options }: ActionsPopoverProps) {
|
||||
<div className="relative" ref={popoverRef}>
|
||||
<button
|
||||
ref={buttonRef}
|
||||
className="flex items-center justify-center gap-[0.139vw] size-[1.667vw]"
|
||||
className="flex items-center justify-center gap-[0.139vw] size-[1.667vw] rounded-[0.556vw] text-[#CCCCCC] hover:text-[#7D7D7D] hover:bg-[#F3F3F3] active:text-[#141414] "
|
||||
onClick={() => setIsOpened(!isOpened)}
|
||||
>
|
||||
<div className="size-[0.208vw] rounded-full bg-[#CCCCCC]" />
|
||||
<div className="size-[0.208vw] rounded-full bg-[#CCCCCC]" />
|
||||
<div className="size-[0.208vw] rounded-full bg-[#CCCCCC]" />
|
||||
<div className="size-[1.111vw] rounded-[0.556vw]">
|
||||
<MoreIcon />
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{isOpened && (
|
||||
@@ -65,24 +64,21 @@ export default function ActionsPopover({ options }: ActionsPopoverProps) {
|
||||
ref={(el) => {
|
||||
setMenuHeight(el?.offsetHeight || 0);
|
||||
}}
|
||||
className={`absolute z-10 right-0 w-[13.333vw] bg-white rounded-[1.111vw] shadow-[0_4px_40px_0_rgba(15,16,17,0.1)] ${
|
||||
className={`absolute z-10 right-0 w-[13.333vw] bg-white rounded-[1.111vw] shadow-[0_4px_40px_0_rgba(15,16,17,0.1)] overflow-hidden ${
|
||||
openUpwards ? "bottom-[100%]" : "top-[100%]"
|
||||
}`}
|
||||
>
|
||||
{options.map((option) => (
|
||||
<button
|
||||
className="p-[0.833vw] button-s text-[#7D7D7D] w-full flex items-center gap-[0.556vw]"
|
||||
<Button
|
||||
variant="tertiary"
|
||||
className="p-[0.833vw] button-s w-full flex items-center !rounded-none !justify-start gap-[0.556vw]"
|
||||
key={option.label}
|
||||
onClick={option.onClick}
|
||||
disabled={option.disabled}
|
||||
style={{
|
||||
backgroundColor: option.disabled ? "#F6F6F6" : "transparent",
|
||||
opacity: option.disabled ? 0.5 : 1,
|
||||
}}
|
||||
>
|
||||
<div className="size-[1.111vw] ">{option.icon}</div>
|
||||
{option.label}
|
||||
</button>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import clsx from "clsx";
|
||||
import Warning from "../indicators/Warning";
|
||||
import Admin from "../indicators/Admin";
|
||||
|
||||
interface AvatarProps {
|
||||
size: "small" | "medium" | "large";
|
||||
status?: "caution" | "admin";
|
||||
src?: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export default function Avatar({ size, status, src, name }: AvatarProps) {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"rounded-full text-white relative",
|
||||
size === "small" && "size-[2.222vw] button-s",
|
||||
size === "medium" && "size-[2.5vw] button-m",
|
||||
size === "large" && "size-[3.333vw] title-s"
|
||||
)}
|
||||
>
|
||||
{GetAvatarImage(src, name)}
|
||||
<div
|
||||
className={clsx(
|
||||
"absolute",
|
||||
size === "small" && "bottom-[1.389vw] left-[1.389vw]",
|
||||
size === "medium" && "bottom-[1.667vw] left-[1.667vw]",
|
||||
size === "large" && "bottom-[2.5vw] left-[2.5vw]"
|
||||
)}
|
||||
>
|
||||
{status === "caution" && <Warning type="caution" />}
|
||||
{status === "admin" && <Admin />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function GetAvatarImage(src?: string, name?: string) {
|
||||
// Aninymous avatar
|
||||
if (!src && !name) {
|
||||
return <img src="/img/popups/MessageUserPfp.png" alt="avatar" />;
|
||||
}
|
||||
|
||||
// Name avatar
|
||||
if (name && !src) {
|
||||
const nameParts = name.split(" ");
|
||||
const firstLetter = nameParts[0][0].toUpperCase();
|
||||
const secondLetter =
|
||||
nameParts.length > 1
|
||||
? nameParts[nameParts.length - 1][0].toUpperCase()
|
||||
: "";
|
||||
|
||||
return (
|
||||
<div className="bg-[#7B60F3] size-full rounded-full flex items-center justify-center">
|
||||
<span className="">
|
||||
{firstLetter}
|
||||
{secondLetter}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Src avatar
|
||||
return <img src={src} alt="avatar" />;
|
||||
}
|
||||
@@ -4,13 +4,10 @@ import { useMe, useLogout } from "../hooks/useAuth";
|
||||
import { useNavigate } from "react-router";
|
||||
import ShareFilledIcon from "../components/icons/ShareFilledIcon";
|
||||
import usePopupStore from "../store/popupStore";
|
||||
<<<<<<< HEAD
|
||||
import ParticipantsPopup from "../components/popups/ParticipantsPopup";
|
||||
=======
|
||||
import SettingsModal from "../components/modals/SettingsModal";
|
||||
import useModalStore from "../store/modalStore";
|
||||
import CogFilledIcon from "../components/icons/CogFilledIcon";
|
||||
>>>>>>> 79fb7f2748fcb76e887daa397ff450afc389a2b3
|
||||
import ParticipantsPopup from "../components/popups/ParticipantsPopup";
|
||||
|
||||
function HomePage() {
|
||||
const { data: user } = useMe();
|
||||
@@ -35,15 +32,7 @@ function HomePage() {
|
||||
|
||||
<FloatingActionButton
|
||||
variant="default"
|
||||
<<<<<<< HEAD
|
||||
onClick={() => setPopup(<ParticipantsPopup />)}
|
||||
=======
|
||||
onClick={() =>
|
||||
setPopup(
|
||||
<SharePopup link={"https://estate.stream/ahdy12jdco1"} />
|
||||
)
|
||||
}
|
||||
>>>>>>> 79fb7f2748fcb76e887daa397ff450afc389a2b3
|
||||
>
|
||||
<div className="2xl:size-[1.111vw] size-4 text-white">
|
||||
<ShareFilledIcon />
|
||||
|
||||
Reference in New Issue
Block a user