Merge pull request 'ui' (#22) from ui into main
Reviewed-on: http://185.100.212.76:7776/Dwinzo-Beta/Dwinzo_dev/pulls/22
This commit is contained in:
commit
bb0a6f214a
|
@ -1,14 +1,18 @@
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import { AppDockIcon } from "../../icons/HeaderIcons";
|
import { AppDockIcon } from "../../icons/HeaderIcons";
|
||||||
import orgImg from "../../../assets/orgTemp.png"
|
import orgImg from "../../../assets/orgTemp.png";
|
||||||
|
import { useActiveUsers } from "../../../store/store";
|
||||||
|
import { getAvatarColor } from "../../../modules/collaboration/users/functions/getAvatarColor";
|
||||||
|
import { ActiveUser } from "../../../types/users";
|
||||||
|
|
||||||
const Header: React.FC = () => {
|
const Header: React.FC = () => {
|
||||||
const guestUsers = [
|
const { activeUsers } = useActiveUsers();
|
||||||
{ value: "Nazria", color: "#43C06D" },
|
const userName = localStorage.getItem("userName") || "Anonymous";
|
||||||
{ value: "Name1", color: "#0050EB" },
|
|
||||||
{ value: "Abigail", color: "#FF6600" },
|
const guestUsers: ActiveUser[] = activeUsers.filter(
|
||||||
{ value: "Jack", color: "#488EF6" },
|
(user: ActiveUser) => user.userName !== userName
|
||||||
]; // Example guest users array
|
);
|
||||||
|
console.log('guestUsers: ', guestUsers);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="header-container">
|
<div className="header-container">
|
||||||
|
@ -25,18 +29,23 @@ const Header: React.FC = () => {
|
||||||
<div className="other-guest">+{guestUsers.length - 3}</div>
|
<div className="other-guest">+{guestUsers.length - 3}</div>
|
||||||
)}
|
)}
|
||||||
{guestUsers.slice(0, 3).map((user, index) => (
|
{guestUsers.slice(0, 3).map((user, index) => (
|
||||||
<div
|
<>
|
||||||
key={index}
|
<div
|
||||||
className="user-profile"
|
key={index}
|
||||||
style={{ background: user.color }}
|
className="user-profile"
|
||||||
>
|
style={{ background: getAvatarColor(index) }}
|
||||||
{user.value[0]}
|
>
|
||||||
</div>
|
{user.userName[0]}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="user-profile-container">
|
<div className="user-profile-container">
|
||||||
<div className="user-profile" style={{ background: "#48AC2A" }}>
|
<div
|
||||||
V
|
className="user-profile"
|
||||||
|
style={{ background: "var(--accent-color)" }}
|
||||||
|
>
|
||||||
|
{userName[0]}
|
||||||
</div>
|
</div>
|
||||||
<div className="user-organization">
|
<div className="user-organization">
|
||||||
<img src={orgImg} alt="" />
|
<img src={orgImg} alt="" />
|
||||||
|
|
|
@ -166,8 +166,10 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`zone-wrapper ${selectedZone?.activeSides?.includes("bottom") && "bottom"
|
ref={containerRef}
|
||||||
}`}
|
className={`zone-wrapper ${
|
||||||
|
selectedZone?.activeSides?.includes("bottom") && "bottom"
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
{/* Left Arrow */}
|
{/* Left Arrow */}
|
||||||
{showLeftArrow && (
|
{showLeftArrow && (
|
||||||
|
|
|
@ -1,112 +1,169 @@
|
||||||
import * as THREE from 'three';
|
import * as THREE from "three";
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { useFrame } from '@react-three/fiber';
|
import { useFrame } from "@react-three/fiber";
|
||||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||||
import camModel from '../../assets/gltf-glb/camera face 2.gltf';
|
import camModel from "../../assets/gltf-glb/camera face 2.gltf";
|
||||||
import getActiveUsersData from '../../services/factoryBuilder/collab/getActiveUsers';
|
import getActiveUsersData from "../../services/factoryBuilder/collab/getActiveUsers";
|
||||||
import { useActiveUsers, useSocketStore } from '../../store/store';
|
import { useActiveUsers, useSocketStore } from "../../store/store";
|
||||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from "react-router-dom";
|
||||||
import { Text, Html } from '@react-three/drei';
|
import { Html } from "@react-three/drei";
|
||||||
import CollabUserIcon from './collabUserIcon';
|
import CollabUserIcon from "./collabUserIcon";
|
||||||
import image from '../../assets/image/userImage.png';
|
import { getAvatarColor } from "./users/functions/getAvatarColor";
|
||||||
|
|
||||||
|
|
||||||
const CamModelsGroup = () => {
|
const CamModelsGroup = () => {
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
const groupRef = useRef<THREE.Group>(null);
|
const groupRef = useRef<THREE.Group>(null);
|
||||||
const email = localStorage.getItem('email');
|
const email = localStorage.getItem("email");
|
||||||
const { activeUsers, setActiveUsers } = useActiveUsers();
|
const { activeUsers, setActiveUsers } = useActiveUsers();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const loader = new GLTFLoader();
|
const loader = new GLTFLoader();
|
||||||
const dracoLoader = new DRACOLoader();
|
const dracoLoader = new DRACOLoader();
|
||||||
const [cams, setCams] = useState<any[]>([]);
|
const [cams, setCams] = useState<any[]>([]);
|
||||||
const [models, setModels] = useState<Record<string, { targetPosition: THREE.Vector3; targetRotation: THREE.Euler }>>({});
|
const [models, setModels] = useState<
|
||||||
|
Record<
|
||||||
|
string,
|
||||||
|
{ targetPosition: THREE.Vector3; targetRotation: THREE.Euler }
|
||||||
|
>
|
||||||
|
>({});
|
||||||
|
|
||||||
dracoLoader.setDecoderPath('three/examples/jsm/libs/draco/gltf/');
|
dracoLoader.setDecoderPath("three/examples/jsm/libs/draco/gltf/");
|
||||||
loader.setDRACOLoader(dracoLoader);
|
loader.setDRACOLoader(dracoLoader);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!email) {
|
if (!email) {
|
||||||
navigate('/');
|
navigate("/");
|
||||||
}
|
}
|
||||||
if (!socket) return;
|
if (!socket) return;
|
||||||
const organization = email!.split('@')[1].split('.')[0];
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
|
|
||||||
socket.on('userConnectRespones', (data: any) => {
|
socket.on("userConnectRespones", (data: any) => {
|
||||||
if (!groupRef.current) return;
|
if (!groupRef.current) return;
|
||||||
if (data.data.userData.email === email) return
|
if (data.data.userData.email === email) return;
|
||||||
if (socket.id === data.socketId || organization !== data.organization) return;
|
if (socket.id === data.socketId || organization !== data.organization)
|
||||||
|
return;
|
||||||
|
|
||||||
const model = groupRef.current.getObjectByProperty('uuid', data.data.userData._id);
|
const model = groupRef.current.getObjectByProperty(
|
||||||
|
"uuid",
|
||||||
|
data.data.userData._id
|
||||||
|
);
|
||||||
if (model) {
|
if (model) {
|
||||||
groupRef.current.remove(model);
|
groupRef.current.remove(model);
|
||||||
}
|
}
|
||||||
loader.load(camModel, (gltf) => {
|
loader.load(camModel, (gltf) => {
|
||||||
const newModel = gltf.scene.clone();
|
const newModel = gltf.scene.clone();
|
||||||
newModel.uuid = data.data.userData._id;
|
newModel.uuid = data.data.userData._id;
|
||||||
newModel.position.set(data.data.position.x, data.data.position.y, data.data.position.z);
|
newModel.position.set(
|
||||||
newModel.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z);
|
data.data.position.x,
|
||||||
|
data.data.position.y,
|
||||||
|
data.data.position.z
|
||||||
|
);
|
||||||
|
newModel.rotation.set(
|
||||||
|
data.data.rotation.x,
|
||||||
|
data.data.rotation.y,
|
||||||
|
data.data.rotation.z
|
||||||
|
);
|
||||||
newModel.userData = data.data.userData;
|
newModel.userData = data.data.userData;
|
||||||
setCams((prev) => [...prev, newModel]);
|
setCams((prev) => [...prev, newModel]);
|
||||||
setActiveUsers([...activeUsers, data.data.userData]);
|
setActiveUsers([...activeUsers, data.data.userData]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('userDisConnectRespones', (data: any) => {
|
socket.on("userDisConnectRespones", (data: any) => {
|
||||||
if (!groupRef.current) return;
|
if (!groupRef.current) return;
|
||||||
if (socket.id === data.socketId || organization !== data.organization) return;
|
if (socket.id === data.socketId || organization !== data.organization)
|
||||||
|
return;
|
||||||
|
|
||||||
setCams((prev) => prev.filter((cam) => cam.uuid !== data.data.userData._id));
|
setCams((prev) =>
|
||||||
setActiveUsers(activeUsers.filter((user: any) => user._id !== data.data.userData._id));
|
prev.filter((cam) => cam.uuid !== data.data.userData._id)
|
||||||
|
);
|
||||||
|
setActiveUsers(
|
||||||
|
activeUsers.filter((user: any) => user._id !== data.data.userData._id)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('cameraUpdateResponse', (data: any) => {
|
socket.on("cameraUpdateResponse", (data: any) => {
|
||||||
if (!groupRef.current || socket.id === data.socketId || organization !== data.organization) return;
|
if (
|
||||||
|
!groupRef.current ||
|
||||||
|
socket.id === data.socketId ||
|
||||||
|
organization !== data.organization
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
setModels((prev) => ({
|
setModels((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
[data.data.userId]: {
|
[data.data.userId]: {
|
||||||
targetPosition: new THREE.Vector3(data.data.position.x, data.data.position.y, data.data.position.z),
|
targetPosition: new THREE.Vector3(
|
||||||
targetRotation: new THREE.Euler(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z),
|
data.data.position.x,
|
||||||
|
data.data.position.y,
|
||||||
|
data.data.position.z
|
||||||
|
),
|
||||||
|
targetRotation: new THREE.Euler(
|
||||||
|
data.data.rotation.x,
|
||||||
|
data.data.rotation.y,
|
||||||
|
data.data.rotation.z
|
||||||
|
),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
socket.off('userConnectRespones');
|
socket.off("userConnectRespones");
|
||||||
socket.off('userDisConnectRespones');
|
socket.off("userDisConnectRespones");
|
||||||
socket.off('cameraUpdateResponse');
|
socket.off("cameraUpdateResponse");
|
||||||
};
|
};
|
||||||
}, [socket, activeUsers]);
|
}, [socket, activeUsers]);
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (!groupRef.current) return;
|
if (!groupRef.current) return;
|
||||||
Object.keys(models).forEach((uuid) => {
|
Object.keys(models).forEach((uuid) => {
|
||||||
const model = groupRef.current!.getObjectByProperty('uuid', uuid);
|
const model = groupRef.current!.getObjectByProperty("uuid", uuid);
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const { targetPosition, targetRotation } = models[uuid];
|
const { targetPosition, targetRotation } = models[uuid];
|
||||||
model.position.lerp(targetPosition, 0.1);
|
model.position.lerp(targetPosition, 0.1);
|
||||||
model.rotation.x = THREE.MathUtils.lerp(model.rotation.x, targetRotation.x, 0.1);
|
model.rotation.x = THREE.MathUtils.lerp(
|
||||||
model.rotation.y = THREE.MathUtils.lerp(model.rotation.y, targetRotation.y, 0.1);
|
model.rotation.x,
|
||||||
model.rotation.z = THREE.MathUtils.lerp(model.rotation.z, targetRotation.z, 0.1);
|
targetRotation.x,
|
||||||
|
0.1
|
||||||
|
);
|
||||||
|
model.rotation.y = THREE.MathUtils.lerp(
|
||||||
|
model.rotation.y,
|
||||||
|
targetRotation.y,
|
||||||
|
0.1
|
||||||
|
);
|
||||||
|
model.rotation.z = THREE.MathUtils.lerp(
|
||||||
|
model.rotation.z,
|
||||||
|
targetRotation.z,
|
||||||
|
0.1
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!groupRef.current) return;
|
if (!groupRef.current) return;
|
||||||
const organization = email!.split('@')[1].split('.')[0];
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
getActiveUsersData(organization).then((data) => {
|
getActiveUsersData(organization).then((data) => {
|
||||||
const filteredData = data.cameraDatas.filter((camera: any) => camera.userData.email !== email);
|
const filteredData = data.cameraDatas.filter(
|
||||||
|
(camera: any) => camera.userData.email !== email
|
||||||
|
);
|
||||||
if (filteredData.length > 0) {
|
if (filteredData.length > 0) {
|
||||||
loader.load(camModel, (gltf) => {
|
loader.load(camModel, (gltf) => {
|
||||||
const newCams = filteredData.map((cam: any) => {
|
const newCams = filteredData.map((cam: any) => {
|
||||||
const newModel = gltf.scene.clone();
|
const newModel = gltf.scene.clone();
|
||||||
newModel.uuid = cam.userData._id;
|
newModel.uuid = cam.userData._id;
|
||||||
newModel.position.set(cam.position.x, cam.position.y, cam.position.z);
|
newModel.position.set(
|
||||||
newModel.rotation.set(cam.rotation.x, cam.rotation.y, cam.rotation.z);
|
cam.position.x,
|
||||||
|
cam.position.y,
|
||||||
|
cam.position.z
|
||||||
|
);
|
||||||
|
newModel.rotation.set(
|
||||||
|
cam.rotation.x,
|
||||||
|
cam.rotation.y,
|
||||||
|
cam.rotation.z
|
||||||
|
);
|
||||||
newModel.userData = cam.userData;
|
newModel.userData = cam.userData;
|
||||||
|
console.log('cam.userData: ', cam.userData);
|
||||||
setActiveUsers([...activeUsers, cam.userData]);
|
setActiveUsers([...activeUsers, cam.userData]);
|
||||||
return newModel;
|
return newModel;
|
||||||
});
|
});
|
||||||
|
@ -119,7 +176,7 @@ const CamModelsGroup = () => {
|
||||||
return (
|
return (
|
||||||
<group ref={groupRef} name="Cam-Model-Group">
|
<group ref={groupRef} name="Cam-Model-Group">
|
||||||
{cams.map((cam, index) => (
|
{cams.map((cam, index) => (
|
||||||
<primitive key={index} object={cam} >
|
<primitive key={index} object={cam}>
|
||||||
<Html
|
<Html
|
||||||
as="div"
|
as="div"
|
||||||
center
|
center
|
||||||
|
@ -130,8 +187,14 @@ const CamModelsGroup = () => {
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
fontFamily: "Arial, sans-serif",
|
fontFamily: "Arial, sans-serif",
|
||||||
}}
|
}}
|
||||||
position={[-0.015, 0, 0.7]}>
|
position={[-0.015, 0, 0.7]}
|
||||||
<CollabUserIcon color={"#ff0000"} userImage={image} userName={cam.userData.userName} />
|
>
|
||||||
|
<CollabUserIcon
|
||||||
|
userImage={""}
|
||||||
|
userName={cam.userData.userName}
|
||||||
|
index={index}
|
||||||
|
color={getAvatarColor(index)}
|
||||||
|
/>
|
||||||
</Html>
|
</Html>
|
||||||
</primitive>
|
</primitive>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -1,53 +1,33 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import CustomAvatar from "./users/Avatar";
|
||||||
|
|
||||||
interface CollabUserIconProps {
|
interface CollabUserIconProps {
|
||||||
color: string;
|
userName: string;
|
||||||
userImage: string;
|
userImage?: string;
|
||||||
userName: string;
|
index?: number;
|
||||||
|
color: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CollabUserIcon: React.FC<CollabUserIconProps> = ({
|
const CollabUserIcon: React.FC<CollabUserIconProps> = ({
|
||||||
color,
|
userImage,
|
||||||
userImage,
|
userName,
|
||||||
userName,
|
index = 0,
|
||||||
|
color,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div className="collab-user-live-container">
|
||||||
style={{
|
<div className="user-image-container">
|
||||||
display: "flex",
|
{userImage ? (
|
||||||
justifyContent: "center",
|
<img className="user-image" src={userImage} alt={userName} />
|
||||||
alignItems: "center",
|
) : (
|
||||||
flexDirection: "column",
|
<CustomAvatar name={userName} index={index} />
|
||||||
gap: "6px",
|
)}
|
||||||
// transform:"translate(-20%, 0%)",
|
</div>
|
||||||
}}
|
<div className="user-name" style={{ backgroundColor: color }}>
|
||||||
>
|
{userName}
|
||||||
<img
|
</div>
|
||||||
src={userImage}
|
</div>
|
||||||
alt={userName}
|
);
|
||||||
style={{
|
|
||||||
width: "30px",
|
|
||||||
height: "30px",
|
|
||||||
outline: `2px solid ${color}`,
|
|
||||||
borderRadius: "50%",
|
|
||||||
objectFit: 'cover'
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
padding: "3px 5px",
|
|
||||||
backgroundColor: color,
|
|
||||||
borderRadius: "6px",
|
|
||||||
color: "white",
|
|
||||||
fontSize: "14px",
|
|
||||||
fontWeight: 400
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{userName}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CollabUserIcon;
|
export default CollabUserIcon;
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { getInitials } from "./functions/getInitials";
|
||||||
|
import { getAvatarColor } from "./functions/getAvatarColor";
|
||||||
|
|
||||||
|
interface AvatarProps {
|
||||||
|
name: string; // Name can be a full name or initials
|
||||||
|
size?: number;
|
||||||
|
index?: number;
|
||||||
|
textColor?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CustomAvatar: React.FC<AvatarProps> = ({
|
||||||
|
name,
|
||||||
|
size = 100,
|
||||||
|
index = 0,
|
||||||
|
textColor = "#ffffff",
|
||||||
|
}) => {
|
||||||
|
const [imageSrc, setImageSrc] = useState<string | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const canvas = document.createElement("canvas"); // Create an offscreen canvas
|
||||||
|
canvas.width = size;
|
||||||
|
canvas.height = size;
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
if (ctx) {
|
||||||
|
const initials = getInitials(name); // Convert name to initials if needed
|
||||||
|
|
||||||
|
// Draw background
|
||||||
|
ctx.fillStyle = getAvatarColor(index);
|
||||||
|
ctx.fillRect(0, 0, size, size);
|
||||||
|
|
||||||
|
// Draw initials
|
||||||
|
ctx.fillStyle = textColor;
|
||||||
|
ctx.font = `bold ${size / 2}px Arial`;
|
||||||
|
ctx.textAlign = "center";
|
||||||
|
ctx.textBaseline = "middle";
|
||||||
|
ctx.fillText(initials, size / 2, size / 2);
|
||||||
|
|
||||||
|
// Generate image source
|
||||||
|
const dataURL = canvas.toDataURL("image/png");
|
||||||
|
setImageSrc(dataURL);
|
||||||
|
}
|
||||||
|
}, [name, size, textColor]);
|
||||||
|
|
||||||
|
if (!imageSrc) {
|
||||||
|
return null; // Return null while the image is being generated
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
className="user-image"
|
||||||
|
src={imageSrc}
|
||||||
|
alt="User Avatar"
|
||||||
|
style={{ width: "100%", height: "100%" }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CustomAvatar;
|
|
@ -0,0 +1,26 @@
|
||||||
|
const avatarColors: string[] = [
|
||||||
|
"#FF5733", // Red Orange
|
||||||
|
"#48ac2a", // Leaf Green
|
||||||
|
"#0050eb", // Royal Blue
|
||||||
|
"#FF33A1", // Hot Pink
|
||||||
|
"#FF8C33", // Deep Orange
|
||||||
|
"#8C33FF", // Violet
|
||||||
|
"#FF3333", // Bright Red
|
||||||
|
"#43c06d", // Emerald Green
|
||||||
|
"#A133FF", // Amethyst Purple
|
||||||
|
"#C70039", // Crimson
|
||||||
|
"#900C3F", // Maroon
|
||||||
|
"#581845", // Plum
|
||||||
|
"#3498DB", // Sky Blue
|
||||||
|
"#2ECC71", // Green Mint
|
||||||
|
"#E74C3C", // Tomato Red
|
||||||
|
"#00adff", // Azure
|
||||||
|
"#DBAD05", // Amber Yellow
|
||||||
|
"#FF5733", // Red Orange
|
||||||
|
"#FF33A1", // Hot Pink
|
||||||
|
"#900C3F", // Maroon
|
||||||
|
];
|
||||||
|
|
||||||
|
export function getAvatarColor(index: number): string {
|
||||||
|
return avatarColors[index % avatarColors.length];
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
export const getInitials = (fullName: string): string => {
|
||||||
|
// Extract initials from the name
|
||||||
|
const words = fullName.split(" ");
|
||||||
|
const initials = words
|
||||||
|
.map((word) => word[0])
|
||||||
|
.slice(0, 2)
|
||||||
|
.join("")
|
||||||
|
.toUpperCase();
|
||||||
|
return initials;
|
||||||
|
};
|
|
@ -110,3 +110,29 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.collab-user-live-container{
|
||||||
|
@include flex-center;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
.user-image-container{
|
||||||
|
height: 30px;
|
||||||
|
width: 30px;
|
||||||
|
border-radius: #{$border-radius-circle};
|
||||||
|
overflow: hidden;
|
||||||
|
.user-image{
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.user-name{
|
||||||
|
padding: 4px 6px;
|
||||||
|
border-radius: #{$border-radius-small};
|
||||||
|
color: white;
|
||||||
|
font-size: var(--font-size-regulaar);
|
||||||
|
font-weight: var(--font-size-regulaar);
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -225,11 +225,13 @@
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
font-weight: var(--font-weight-bold);
|
font-weight: var(--font-weight-bold);
|
||||||
color: white;
|
color: white;
|
||||||
|
text-transform: capitalize;
|
||||||
}
|
}
|
||||||
|
|
||||||
.guest-users-container {
|
.guest-users-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: flex-end;
|
||||||
.other-guest {
|
.other-guest {
|
||||||
@include flex-center;
|
@include flex-center;
|
||||||
height: 26px;
|
height: 26px;
|
||||||
|
@ -249,7 +251,8 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
.user-organization {
|
.user-organization {
|
||||||
height: 100%;
|
height: 26px;
|
||||||
|
width: 52px;
|
||||||
max-width: 52px;
|
max-width: 52px;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
|
@ -8,4 +8,11 @@ export interface User {
|
||||||
|
|
||||||
type AccessOption = {
|
type AccessOption = {
|
||||||
option: string;
|
option: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ActiveUser = {
|
||||||
|
_id: string;
|
||||||
|
userName: string;
|
||||||
|
email: string;
|
||||||
|
activeStatus?: string; // Optional property
|
||||||
};
|
};
|
Loading…
Reference in New Issue