diff --git a/app/src/assets/image/banner.png b/app/src/assets/image/banner.png new file mode 100644 index 0000000..d267ac2 Binary files /dev/null and b/app/src/assets/image/banner.png differ diff --git a/app/src/assets/image/image.png b/app/src/assets/image/image.png index 61d4cdb..34d7e55 100644 Binary files a/app/src/assets/image/image.png and b/app/src/assets/image/image.png differ diff --git a/app/src/components/icons/DashboardIcon.tsx b/app/src/components/icons/DashboardIcon.tsx new file mode 100644 index 0000000..83c997b --- /dev/null +++ b/app/src/components/icons/DashboardIcon.tsx @@ -0,0 +1,255 @@ +export function NotificationIcon() { + return ( + + + + + ); +} + +export function HomeIcon() { + return ( + + + + ); +} + +export function ProjectsIcon() { + return ( + + + + ); +} + +export function TutorialsIcon() { + return ( + + + + + + + + + + + + + + + + + + + + ); +} + +export function DocumentationIcon() { + return ( + + + + + ); +} + +export function HelpIcon() { + return ( + + + + + + + + + + + ); +} + +export function LogoutIcon() { + return ( + + + + + + ); +} diff --git a/app/src/components/icons/ExportCommonIcons.tsx b/app/src/components/icons/ExportCommonIcons.tsx index d2c9970..6e73c0e 100644 --- a/app/src/components/icons/ExportCommonIcons.tsx +++ b/app/src/components/icons/ExportCommonIcons.tsx @@ -526,21 +526,21 @@ export const KebabIcon = () => { cy="1.35112" rx="1.4993" ry="1.27477" - fill="#E1E1E1" + fill="var(--text-color)" /> ); @@ -559,7 +559,7 @@ export const DublicateIcon = () => { fillRule="evenodd" clipRule="evenodd" d="M14.3125 11.375C14.3125 11.7545 14.0045 12.0625 13.625 12.0625H8.125C7.7455 12.0625 7.4375 11.7545 7.4375 11.375V5.875C7.4375 5.4955 7.7455 5.1875 8.125 5.1875H13.625C14.0045 5.1875 14.3125 5.4955 14.3125 5.875V11.375ZM13.625 4.5H8.125C7.36566 4.5 6.75 5.11566 6.75 5.875V11.375C6.75 12.1343 7.36566 12.75 8.125 12.75H13.625C14.3843 12.75 15 12.1343 15 11.375V5.875C15 5.11566 14.3843 4.5 13.625 4.5ZM11.5625 14.125C11.5625 14.5045 11.2545 14.8125 10.875 14.8125H5.375C4.9955 14.8125 4.6875 14.5045 4.6875 14.125V8.625C4.6875 8.2455 4.9955 7.9375 5.375 7.9375H6.0625V7.25H5.375C4.61566 7.25 4 7.86566 4 8.625V14.125C4 14.8843 4.61566 15.5 5.375 15.5H10.875C11.6343 15.5 12.25 14.8843 12.25 14.125V13.4375H11.5625V14.125Z" - fill="#6F42C1" + fill="var(--text-color)" /> ); @@ -576,31 +576,31 @@ export const DeleteIcon = () => { > diff --git a/app/src/components/icons/SimulationIcons.tsx b/app/src/components/icons/SimulationIcons.tsx index 28ce559..4879ea4 100644 --- a/app/src/components/icons/SimulationIcons.tsx +++ b/app/src/components/icons/SimulationIcons.tsx @@ -179,8 +179,8 @@ export function MoveArrowRight() { ); @@ -198,8 +198,8 @@ export function MoveArrowLeft() { ); diff --git a/app/src/components/layout/Dashboard/DashboardCard.tsx b/app/src/components/layout/Dashboard/DashboardCard.tsx new file mode 100644 index 0000000..0e5df0d --- /dev/null +++ b/app/src/components/layout/Dashboard/DashboardCard.tsx @@ -0,0 +1,25 @@ +import React from "react"; +import { KebabIcon } from "../../icons/ExportCommonIcons"; +import img from "../../../assets/image/image.png" + +const DashboardCard:React.FC = () => { + return ( +
+
+ +
+
+
+
Untitled
+
24-12-2025
+
+
+
V
+ +
+
+
+ ); +}; + +export default DashboardCard; diff --git a/app/src/components/layout/Dashboard/DashboardHome.tsx b/app/src/components/layout/Dashboard/DashboardHome.tsx new file mode 100644 index 0000000..9d6672c --- /dev/null +++ b/app/src/components/layout/Dashboard/DashboardHome.tsx @@ -0,0 +1,21 @@ +import React from "react"; +import DashboardCard from "./DashboardCard"; +import DashboardNavBar from "./DashboardNavBar"; +import MarketPlaceBanner from "./MarketPlaceBanner"; + +const DashboardHome: React.FC = () => { + return ( +
+ + +
+
Recents
+
+ +
+
+
+ ); +}; + +export default DashboardHome; diff --git a/app/src/components/layout/Dashboard/DashboardNavBar.tsx b/app/src/components/layout/Dashboard/DashboardNavBar.tsx new file mode 100644 index 0000000..add0656 --- /dev/null +++ b/app/src/components/layout/Dashboard/DashboardNavBar.tsx @@ -0,0 +1,21 @@ +import React from "react"; +import { CartIcon } from "../../icons/ExportModuleIcons"; +import Search from "../../ui/inputs/Search"; + +interface DashboardNavBarProps { + page: React.ReactNode; +} + +const DashboardNavBar: React.FC = ({ page }) => { + return ( +
+
{page}
+
+ Market Place +
+ {}} /> +
+ ); +}; + +export default DashboardNavBar; diff --git a/app/src/components/layout/Dashboard/MarketPlaceBanner.tsx b/app/src/components/layout/Dashboard/MarketPlaceBanner.tsx new file mode 100644 index 0000000..b0d151a --- /dev/null +++ b/app/src/components/layout/Dashboard/MarketPlaceBanner.tsx @@ -0,0 +1,44 @@ +import React from "react"; +import banner from "../../../assets/image/banner.png"; + +const MarketPlaceBanner = () => { + return ( +
+ {/* market place banner */} + +
+ NEW +
FALL +
COLLECTION +
+
Unlock Creativity with Premium 3D Assets!
+
+ + + + +
+
Explore Now
+
+ ); +}; + +export default MarketPlaceBanner; diff --git a/app/src/components/layout/Dashboard/SidePannel.tsx b/app/src/components/layout/Dashboard/SidePannel.tsx new file mode 100644 index 0000000..00e3e14 --- /dev/null +++ b/app/src/components/layout/Dashboard/SidePannel.tsx @@ -0,0 +1,69 @@ +import React from "react"; +import { + DocumentationIcon, + HelpIcon, + HomeIcon, + LogoutIcon, + NotificationIcon, + ProjectsIcon, + TutorialsIcon, +} from "../../icons/DashboardIcon"; +import { SettingsIcon, TrashIcon } from "../../icons/ExportCommonIcons"; + +const SidePannel: React.FC = () => { + const userName = localStorage.getItem("userName") || "Anonymous"; + return ( +
+
+
+
{userName[0]}
+
{userName}
+
+
+ +
+
+
+ New project
+
+
+
+ + Home +
+
+ + Projects +
+
+ + Trash +
+
+ + Tutorials +
+
+ + Documentation +
+
+
+
+ + Settings +
+
+ + Log out +
+
+ + Help & Feedback +
+
+
+
+ ); +}; + +export default SidePannel; diff --git a/app/src/components/layout/sidebarRight/Header.tsx b/app/src/components/layout/sidebarRight/Header.tsx index 9abf096..eac15e0 100644 --- a/app/src/components/layout/sidebarRight/Header.tsx +++ b/app/src/components/layout/sidebarRight/Header.tsx @@ -1,9 +1,10 @@ -import React, { useEffect } from "react"; +import React, { useState } from "react"; import { AppDockIcon } from "../../icons/HeaderIcons"; import orgImg from "../../../assets/orgTemp.png"; import { useActiveUsers } from "../../../store/store"; import { getAvatarColor } from "../../../modules/collaboration/users/functions/getAvatarColor"; import { ActiveUser } from "../../../types/users"; +import CollaborationPopup from "../../templates/CollaborationPopup"; const Header: React.FC = () => { const { activeUsers } = useActiveUsers(); @@ -12,47 +13,60 @@ const Header: React.FC = () => { const guestUsers: ActiveUser[] = activeUsers.filter( (user: ActiveUser) => user.userName !== userName ); - console.log('guestUsers: ', guestUsers); + + const [userManagement, setUserManagement] = useState(false); return ( -
-
-
Share
-
- -
-
-
-
-
- {guestUsers.length > 3 && ( -
+{guestUsers.length - 3}
- )} - {guestUsers.slice(0, 3).map((user, index) => ( - <> -
- {user.userName[0]} -
- - ))} -
-
+ <> + {userManagement && ( + + )} +
+
{ + setUserManagement(true); + }} > - {userName[0]} + Share
-
- +
+ +
+
+
+
+
+ {guestUsers.length > 3 && ( +
+{guestUsers.length - 3}
+ )} + {guestUsers.slice(0, 3).map((user, index) => ( + <> +
+ {user.userName[0]} +
+ + ))} +
+
+
+ {userName[0]} +
+
+ +
-
+ ); }; diff --git a/app/src/components/templates/CollaborationPopup.tsx b/app/src/components/templates/CollaborationPopup.tsx index 34e3669..8312fe7 100644 --- a/app/src/components/templates/CollaborationPopup.tsx +++ b/app/src/components/templates/CollaborationPopup.tsx @@ -50,7 +50,14 @@ const UserListTemplate: React.FC = ({ user }) => { ); }; -const CollaborationPopup: React.FC = () => { +interface CollaborateProps { + setUserManagement: (value: boolean) => void; +} + +const CollaborationPopup: React.FC = ({ + setUserManagement, +}) => { + const userName = localStorage.getItem("userName") || "Anonymous"; const users = [ { name: "Alice Johnson", @@ -81,16 +88,31 @@ const CollaborationPopup: React.FC = () => { access: "Viewer", }, ]; - return ( -
-
+
{ + setUserManagement(false); + }} + > +
{ + e.preventDefault(); + e.stopPropagation(); + }} + >
Share this file
copy link
-
+
{ + setUserManagement(false); + }} + >
@@ -111,7 +133,10 @@ const CollaborationPopup: React.FC = () => {
-
User 1
+
+
{userName[0]}
+ {userName} +
you
{users.map((user, index) => ( diff --git a/app/src/components/ui/inputs/MultiEmailInvite.tsx b/app/src/components/ui/inputs/MultiEmailInvite.tsx index 7cfa1a0..a16de66 100644 --- a/app/src/components/ui/inputs/MultiEmailInvite.tsx +++ b/app/src/components/ui/inputs/MultiEmailInvite.tsx @@ -58,12 +58,15 @@ const MultiEmailInvite: React.FC = () => { onFocus={() => setInputFocus(true)} onBlur={() => setInputFocus(false)} onKeyDown={handleKeyDown} - placeholder="Enter email and press Enter or comma" + placeholder="Enter email and press Enter or comma to seperate" />
Invite
+
+ {/* list available users */} +
); }; diff --git a/app/src/modules/collaboration/collabCams.tsx b/app/src/modules/collaboration/collabCams.tsx index af135a7..bae58c2 100644 --- a/app/src/modules/collaboration/collabCams.tsx +++ b/app/src/modules/collaboration/collabCams.tsx @@ -163,8 +163,9 @@ const CamModelsGroup = () => { cam.rotation.z ); newModel.userData = cam.userData; - console.log('cam.userData: ', cam.userData); - setActiveUsers([...activeUsers, cam.userData]); + if (!activeUsers.includes(cam.userData)) { + setActiveUsers([...activeUsers, cam.userData]); + } return newModel; }); setCams((prev) => [...prev, ...newCams]); diff --git a/app/src/modules/market/AssetPreview.tsx b/app/src/modules/market/AssetPreview.tsx index 864c5e5..f0b6fbd 100644 --- a/app/src/modules/market/AssetPreview.tsx +++ b/app/src/modules/market/AssetPreview.tsx @@ -24,7 +24,7 @@ interface AssetPreviewProps { function Ui() { return ( - Loading your model... + Loading preview... ); } diff --git a/app/src/pages/Dashboard.tsx b/app/src/pages/Dashboard.tsx index 9df13a0..02ce030 100644 --- a/app/src/pages/Dashboard.tsx +++ b/app/src/pages/Dashboard.tsx @@ -1,8 +1,13 @@ import React from 'react'; +import SidePannel from '../components/layout/Dashboard/SidePannel'; +import DashboardHome from '../components/layout/Dashboard/DashboardHome'; const Dashboard: React.FC = () => { return ( -
Dashboard
+
+ + +
); }; diff --git a/app/src/styles/layout/popup.scss b/app/src/styles/layout/popup.scss index 20ea3f2..9d22e64 100644 --- a/app/src/styles/layout/popup.scss +++ b/app/src/styles/layout/popup.scss @@ -86,7 +86,18 @@ } .project-name, .your-name { + @include flex-center; + gap: 6px; color: var(--accent-color); + .user-profile{ + height: 24px; + width: 24px; + text-align: center; + line-height: 25px; + background-color: var(--accent-color); + color: var(--primary-color); + border-radius: #{$border-radius-circle}; + } } .number-of-peoples-have-access { padding: 4px 12px; @@ -115,6 +126,7 @@ @include flex-center; flex-direction: column; gap: 6px; + transform: translateY(15px); .user-image-container{ height: 30px; width: 30px; diff --git a/app/src/styles/main.scss b/app/src/styles/main.scss index 34c0074..05342f9 100644 --- a/app/src/styles/main.scss +++ b/app/src/styles/main.scss @@ -31,6 +31,7 @@ @use 'layout/toast'; // pages +@use 'pages/dashboard.scss'; @use 'pages/home'; @use 'pages/realTimeViz'; @use 'pages/userAuth'; \ No newline at end of file diff --git a/app/src/styles/pages/dashboard.scss b/app/src/styles/pages/dashboard.scss new file mode 100644 index 0000000..e5b07a4 --- /dev/null +++ b/app/src/styles/pages/dashboard.scss @@ -0,0 +1,221 @@ +@use "../abstracts/variables.scss" as *; +@use "../abstracts/mixins.scss" as *; + +.dashboard-main { + height: 100vh; + width: 100vw; + display: flex; + .side-pannel-container { + padding: 32px; + min-width: 240px; + height: 100vh; + display: flex; + flex-direction: column; + gap: 16px; + border-right: 1px solid var(--border-color); + .side-pannel-header { + @include flex-space-between; + .user-container { + @include flex-center; + gap: 6px; + .user-profile { + height: 32px; + width: 32px; + line-height: 32px; + text-align: center; + font-weight: var(--font-weight-medium); + background: var(--accent-color); + color: var(--primary-color); + border-radius: #{$border-radius-circle}; + } + .user-name { + color: var(--accent-color); + } + } + .notifications-container { + @include flex-center; + height: 24px; + width: 24px; + cursor: pointer; + } + } + .new-project-button { + padding: 12px 16px; + cursor: not-allowed; + color: var(--accent-color); + background-color: var(--background-color-secondary); + border-radius: #{$border-radius-large}; + } + .side-bar-content-container { + display: flex; + flex-direction: column; + justify-content: space-between; + height: 100%; + .side-bar-options-container { + .option-list { + display: flex; + align-items: center; + gap: 8px; + padding: 6px 10px; + margin: 4px 0; + border-radius: #{$border-radius-medium}; + &:hover { + background: var(--background-color-secondary); + } + } + .active { + color: var(--accent-color); + font-weight: var(--font-weight-medium); + background-color: var(--highlight-accent-color); + &:hover { + background-color: var(--highlight-accent-color); + } + } + } + } + } + .dashboard-home-container { + width: 100%; + .dashboard-navbar-container { + margin-top: 28px; + padding: 8px 34px 8px 12px; + @include flex-center; + .title { + text-transform: capitalize; + font-size: var(--font-size-large); + width: 100%; + } + .market-place-button { + @include flex-center; + gap: 6px; + padding: 8px 14px; + background: var(--accent-gradient-color); + white-space: nowrap; + border-radius: #{$border-radius-large}; + color: var(--primary-color); + } + .search-wrapper { + width: 400px; + } + } + .container { + margin: 22px 0; + width: 100%; + padding: 0 12px; + .header { + font-size: var(--font-size-large); + } + .cards-container { + display: flex; + flex-wrap: wrap; + position: relative; + width: 100%; + padding: 8px; + gap: 18px; + } + } + } +} + +.dashboard-card-container { + height: 242px; + width: calc((100% / 5) - 23px); + min-width: 260px; + position: relative; + border: 1px solid var(--border-color); + border-radius: #{$border-radius-large}; + overflow: hidden; + .preview-container { + height: 100%; + width: 100%; + img { + height: 100%; + width: 100%; + object-fit: cover; + vertical-align: top; + border: none; + outline: none; + } + } + .project-details-container { + @include flex-space-between; + position: absolute; + bottom: 0; + width: 100%; + padding: 8px 16px; + background: var(--primary-color); + border-radius: 10px; + .project-details { + .project-name { + margin-bottom: 2px; + } + .project-data { + color: var(--accent-color); + } + } + .users-list-container { + @include flex-center; + gap: 6px; + .user-profile { + height: 26px; + width: 26px; + line-height: 26px; + text-align: center; + background-color: var(--accent-color); + color: var(--primary-color); + border-radius: #{$border-radius-circle}; + } + } + } +} + +.market-place-banner-container { + width: 100%; + height: 230px; + overflow: hidden; + position: relative; + padding: 0 24px; + img { + height: 100%; + width: 100%; + object-fit: cover; + border-radius: 30px; + } + .hero-text { + position: absolute; + left: 52px; + bottom: 25px; + font-size: 48px; + font-family: #{$font-roboto}; + font-weight: 800; + color: #ffffff; + text-transform: uppercase; + } + .context { + position: absolute; + top: 20px; + right: 58px; + text-transform: uppercase; + font-size: 22px; + width: 300px; + color: #ffffff; + font-family: #{$font-roboto}; + } + .arrow-context { + position: absolute; + bottom: 27px; + right: 300px; + } + .explore-button { + position: absolute; + top: 95px; + right: 52px; + padding: 10px 20px; + text-transform: uppercase; + font-size: 24px; + border: 1px solid #ffffff; + color: #ffffff; + font-family: #{$font-roboto}; + cursor: pointer; + } +}