This is an automated email from the ASF dual-hosted git repository.

dimuthuupe pushed a commit to branch cybershuttle-staging
in repository https://gitbox.apache.org/repos/asf/airavata.git

commit ab35f657967129881b94e569d29ff481609fc0f0
Author: ganning127 <[email protected]>
AuthorDate: Fri Apr 4 13:01:54 2025 -0400

    refactoring UI and responsive changes
---
 modules/research-framework/portal/src/App.tsx      |  21 ++-
 .../portal/src/components/NavBar.tsx               |  90 ------------
 .../src/components/datasets/DatasetDetails.tsx     |   2 +-
 .../portal/src/components/datasets/index.tsx       |   3 -
 .../home/NotebooksAndRepositoriesSection.tsx       |  49 -------
 .../portal/src/components/home/ResourceCard.tsx    |   1 -
 .../portal/src/components/home/index.tsx           |   3 -
 .../portal/src/components/models/ModelCard.tsx     |  34 -----
 .../portal/src/components/models/ModelDetails.tsx  |  96 -------------
 .../portal/src/components/models/index.tsx         |   3 -
 .../src/components/notebooks/NotebookCard.tsx      |  64 ---------
 .../portal/src/components/notebooks/index.tsx      |   3 -
 .../repositories/RepositorySpecificDetails.tsx     | 152 +++++++++++----------
 .../portal/src/components/repositories/index.tsx   |   3 -
 .../src/components/resources/ResourceDetails.tsx   |   4 +-
 .../portal/src/layouts/NavBar.tsx                  | 142 +++++++++++++++++++
 .../portal/src/layouts/NavBarFooterLayout.tsx      |  14 ++
 17 files changed, 259 insertions(+), 425 deletions(-)

diff --git a/modules/research-framework/portal/src/App.tsx 
b/modules/research-framework/portal/src/App.tsx
index 42206ac062..ebeb14af3b 100644
--- a/modules/research-framework/portal/src/App.tsx
+++ b/modules/research-framework/portal/src/App.tsx
@@ -11,6 +11,7 @@ import ProtectedComponent from 
"./components/auth/ProtectedComponent";
 import { useAuth } from "react-oidc-context";
 import { useEffect } from "react";
 import { setUserProvider } from "./lib/api";
+import NavBarFooterLayout from "./layouts/NavBarFooterLayout";
 function App() {
   const colorMode = useColorMode();
   if (colorMode.colorMode === "dark") {
@@ -28,7 +29,7 @@ function App() {
   return (
     <>
       <BrowserRouter>
-        <Routes>
+        {/* <Routes>
           <Route path="/" element={<Login />} />
 
           <Route
@@ -53,12 +54,28 @@ function App() {
               element={<ProtectedComponent Component={Models} />}
             />
 
-            {/* Dynamic Route for specific resource details */}
             <Route
               path=":type/:id"
               element={<ProtectedComponent Component={ResourceDetails} />}
             />
           </Route>
+        </Routes> */}
+
+        <Routes>
+          {/* Public Route */}
+          <Route path="/" element={<Login />} />
+
+          {/* Protected Routes with Layout */}
+          <Route
+            element={<ProtectedComponent Component={NavBarFooterLayout} />}
+          >
+            <Route path="/projects" element={<Home />} />
+            <Route path="/resources/notebooks" element={<Notebooks />} />
+            <Route path="/resources/datasets" element={<Datasets />} />
+            <Route path="/resources/repositories" element={<Repositories />} />
+            <Route path="/resources/models" element={<Models />} />
+            <Route path="/resources/:type/:id" element={<ResourceDetails />} />
+          </Route>
         </Routes>
       </BrowserRouter>
     </>
diff --git a/modules/research-framework/portal/src/components/NavBar.tsx 
b/modules/research-framework/portal/src/components/NavBar.tsx
deleted file mode 100644
index 6cc402f985..0000000000
--- a/modules/research-framework/portal/src/components/NavBar.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-import {
-  Text,
-  Flex,
-  Spacer,
-  Image,
-  HStack,
-  Avatar,
-  Box,
-} from "@chakra-ui/react";
-import ApacheAiravataLogo from "../assets/airavata-logo.png";
-import { Link } from "react-router";
-import { useAuth } from "react-oidc-context";
-
-const NAV_CONTENT = [
-  {
-    title: "Projects",
-    url: "/projects",
-  },
-  {
-    title: "Datasets",
-    url: "/resources/datasets",
-  },
-  {
-    title: "Repositories",
-    url: "/resources/repositories",
-  },
-  {
-    title: "Notebooks",
-    url: "/resources/notebooks",
-  },
-  {
-    title: "Models",
-    url: "/resources/models",
-  },
-];
-
-const NavBar = () => {
-  const auth = useAuth();
-
-  console.log(auth);
-  return (
-    <Flex
-      as="nav"
-      align="center"
-      p={4}
-      boxShadow="sm"
-      position="sticky"
-      top="0"
-      zIndex="1000"
-      bg="white" // Ensure background is not transparent
-    >
-      {/* Logo */}
-      <Link to="/projects">
-        <Image src={ApacheAiravataLogo} alt="Logo" boxSize="30px" />
-      </Link>
-
-      {/* Navigation Links */}
-      <Flex ml={4} gap={6}>
-        {NAV_CONTENT.map((item) => (
-          <Link key={item.title} to={item.url} color="gray.700">
-            <Text
-              _hover={{
-                color: "blue.400",
-                textDecoration: "underline",
-              }}
-            >
-              {item.title}
-            </Text>
-          </Link>
-        ))}
-      </Flex>
-
-      <Spacer />
-
-      {/* Search Bar */}
-      <HStack>
-        <Avatar.Root variant="subtle">
-          <Avatar.Fallback name={auth.user?.profile.name} />
-        </Avatar.Root>
-        <Box>
-          <Text>{auth.user?.profile.name}</Text>
-          <Text fontSize="sm" color="gray.500">
-            {auth.user?.profile.email}
-          </Text>
-        </Box>
-      </HStack>
-    </Flex>
-  );
-};
-export default NavBar;
diff --git 
a/modules/research-framework/portal/src/components/datasets/DatasetDetails.tsx 
b/modules/research-framework/portal/src/components/datasets/DatasetDetails.tsx
index 79719752aa..975639fcd6 100644
--- 
a/modules/research-framework/portal/src/components/datasets/DatasetDetails.tsx
+++ 
b/modules/research-framework/portal/src/components/datasets/DatasetDetails.tsx
@@ -1,5 +1,5 @@
 import { Metadata } from "../Metadata";
-import NavBar from "../NavBar";
+import NavBar from "../../layouts/NavBar";
 // @ts-expect-error This is fine
 import { MOCK_DATASETS } from "../../data/MOCK_DATA";
 import { DatasetType } from "@/interfaces/DatasetType";
diff --git 
a/modules/research-framework/portal/src/components/datasets/index.tsx 
b/modules/research-framework/portal/src/components/datasets/index.tsx
index 690dd61152..d2b84b5b1b 100644
--- a/modules/research-framework/portal/src/components/datasets/index.tsx
+++ b/modules/research-framework/portal/src/components/datasets/index.tsx
@@ -1,4 +1,3 @@
-import NavBar from "../NavBar";
 import { Container, HStack, Input, SimpleGrid } from "@chakra-ui/react";
 import { PageHeader } from "../PageHeader";
 import { LuSearch } from "react-icons/lu";
@@ -43,8 +42,6 @@ export const Datasets = () => {
 
   return (
     <>
-      <NavBar />
-
       <Container maxW="container.lg" mt={8}>
         <HStack alignItems="flex-end" justify="space-between">
           <PageHeader
diff --git 
a/modules/research-framework/portal/src/components/home/NotebooksAndRepositoriesSection.tsx
 
b/modules/research-framework/portal/src/components/home/NotebooksAndRepositoriesSection.tsx
deleted file mode 100644
index 584d3e6b6e..0000000000
--- 
a/modules/research-framework/portal/src/components/home/NotebooksAndRepositoriesSection.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import { Input } from "@chakra-ui/react";
-import { LuSearch } from "react-icons/lu";
-import { ResourceCard } from "./ResourceCard";
-import { InputGroup } from "../ui/input-group";
-import { GridContainer } from "../GridContainer";
-import { useEffect, useState } from "react";
-import api from "@/lib/api";
-import { Resource } from "@/interfaces/ResourceType";
-
-const fetchNotebooksAndRepositories = async () => {
-  try {
-    const response = await api.get(
-      "/project-management/resources?type=NOTEBOOK&type=REPOSITORY"
-    );
-    const data = response.data;
-    return data;
-  } catch (error) {
-    console.error("Error fetching:", error);
-  }
-};
-
-export const NotebooksAndRepositoriesSection = () => {
-  const [resources, setResources] = useState<Resource[]>([]);
-
-  useEffect(() => {
-    async function init() {
-      const projects = await fetchNotebooksAndRepositories();
-      setResources(projects.content);
-    }
-
-    init();
-  }, []);
-
-  console.log("Resources:", resources);
-
-  return (
-    <>
-      <InputGroup mt={2} endElement={<LuSearch />} w="100%">
-        <Input placeholder="Search" rounded="md" />
-      </InputGroup>
-
-      <GridContainer>
-        {resources.map((resource: Resource) => {
-          return <ResourceCard key={resource.id} resource={resource} />;
-        })}
-      </GridContainer>
-    </>
-  );
-};
diff --git 
a/modules/research-framework/portal/src/components/home/ResourceCard.tsx 
b/modules/research-framework/portal/src/components/home/ResourceCard.tsx
index bceb4bdd92..a5da829aac 100644
--- a/modules/research-framework/portal/src/components/home/ResourceCard.tsx
+++ b/modules/research-framework/portal/src/components/home/ResourceCard.tsx
@@ -17,7 +17,6 @@ import { ModelCardButton } from "../models/ModelCardButton";
 
 export const ResourceCard = ({ resource }: { resource: Resource }) => {
   const author = resource.authors[0];
-  console.log("author" + author);
 
   const isValidImage = isValidImaage(resource.headerImage);
 
diff --git a/modules/research-framework/portal/src/components/home/index.tsx 
b/modules/research-framework/portal/src/components/home/index.tsx
index 3a932951f7..4d81bf39ed 100644
--- a/modules/research-framework/portal/src/components/home/index.tsx
+++ b/modules/research-framework/portal/src/components/home/index.tsx
@@ -1,6 +1,5 @@
 import { Box, HStack, Container } from "@chakra-ui/react";
 
-import NavBar from "../NavBar";
 import { PageHeader } from "../PageHeader";
 import { AddRepositoryButton } from "./AddRepositoryButton";
 import { AddZipButton } from "./AddZipButton";
@@ -12,8 +11,6 @@ import { ProjectsSection } from "./ProjectsSection";
 const Home = () => {
   return (
     <Box>
-      <NavBar />
-
       <Container maxW="container.xl" mt={8}>
         <HStack alignItems="flex-end" justify="space-between">
           <PageHeader
diff --git 
a/modules/research-framework/portal/src/components/models/ModelCard.tsx 
b/modules/research-framework/portal/src/components/models/ModelCard.tsx
deleted file mode 100644
index 9fd0898e54..0000000000
--- a/modules/research-framework/portal/src/components/models/ModelCard.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import { Badge, Box, Card, HStack, Heading } from "@chakra-ui/react";
-import { ModelType } from "@/interfaces/ModelType";
-import { Link } from "react-router";
-export const ModelCard = ({ model }: { model: ModelType }) => {
-  return (
-    <Box>
-      <Card.Root
-        size="sm"
-        _hover={{
-          bg: "gray.100",
-          cursor: "pointer",
-        }}
-      >
-        <Link to={`/models/${model.appModuleId}`}>
-          <Card.Header>
-            <HStack
-              justifyContent="space-between"
-              alignItems="flex-start"
-              flexWrap="wrap"
-            >
-              <Heading size="md"> {model.appModuleName}</Heading>
-              {model.appModuleVersion && (
-                <Badge size="md" colorPalette="green">
-                  {model.appModuleVersion}
-                </Badge>
-              )}
-            </HStack>
-          </Card.Header>
-          <Card.Body color="fg.muted">{model.appModuleDescription}</Card.Body>
-        </Link>
-      </Card.Root>
-    </Box>
-  );
-};
diff --git 
a/modules/research-framework/portal/src/components/models/ModelDetails.tsx 
b/modules/research-framework/portal/src/components/models/ModelDetails.tsx
deleted file mode 100644
index db3eff60ff..0000000000
--- a/modules/research-framework/portal/src/components/models/ModelDetails.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-import { useParams } from "react-router";
-import NavBar from "../NavBar";
-// @ts-expect-error This is fine
-import { MOCK_MODELS } from "../../data/MOCK_DATA";
-import { ModelType } from "@/interfaces/ModelType";
-import { useState, useEffect } from "react";
-import {
-  Badge,
-  Button,
-  Code,
-  Container,
-  HStack,
-  Heading,
-  Text,
-} from "@chakra-ui/react";
-
-async function getModel(id: string | undefined) {
-  return MOCK_MODELS.find((model: ModelType) => model.appModuleId === id);
-}
-
-export const ModelDetails = () => {
-  const { id } = useParams();
-  const [model, setModel] = useState<ModelType | null>(null);
-  const [copyClicked, setCopyClicked] = useState(false);
-
-  useEffect(() => {
-    if (!id) return;
-
-    async function getData() {
-      const n = await getModel(id);
-      setModel(n);
-    }
-    getData();
-  }, [id]);
-
-  if (!model) return null;
-
-  const templateCode = `exp = md.AlphaFold2.initialize(
-    name=...,
-    input_seq=...,
-    max_template_date=...,
-    model_preset=...,
-    multimers_per_model=...,
-)
-exp.create_task()
-exp.plan().launch()`;
-
-  return (
-    <>
-      <NavBar />
-
-      <Container maxW="breakpoint-md" p={4}>
-        <HStack
-          alignItems="center"
-          mt={4}
-          justifyContent="space-between"
-          flexWrap="wrap"
-        >
-          <Heading size="4xl">{model.appModuleName}</Heading>
-          {model.appModuleVersion && (
-            <Badge size="md" colorPalette="green">
-              {model.appModuleVersion}
-            </Badge>
-          )}
-        </HStack>
-        <Text color="fg.muted" mt={2}>
-          {model.appModuleDescription}
-        </Text>
-
-        <Heading size="2xl" mt={4}>
-          Example
-          <Button
-            size="xs"
-            ml={2}
-            colorPalette="teal"
-            onClick={() => {
-              navigator.clipboard.writeText(templateCode);
-              setCopyClicked(true);
-              setTimeout(() => setCopyClicked(false), 2000);
-            }}
-          >
-            {copyClicked ? "Copied!" : "Copy"}
-          </Button>
-        </Heading>
-
-        <Code
-          mt={2}
-          p={2}
-          display="block"
-          whiteSpace="pre"
-          children={templateCode}
-        />
-      </Container>
-    </>
-  );
-};
diff --git a/modules/research-framework/portal/src/components/models/index.tsx 
b/modules/research-framework/portal/src/components/models/index.tsx
index 2ae3cd27b2..dc1cdce827 100644
--- a/modules/research-framework/portal/src/components/models/index.tsx
+++ b/modules/research-framework/portal/src/components/models/index.tsx
@@ -1,4 +1,3 @@
-import NavBar from "../NavBar";
 import { Container, HStack, Input, SimpleGrid } from "@chakra-ui/react";
 import { PageHeader } from "../PageHeader";
 import { LuSearch } from "react-icons/lu";
@@ -43,8 +42,6 @@ export const Models = () => {
 
   return (
     <>
-      <NavBar />
-
       <Container maxW="container.lg" mt={8}>
         <HStack alignItems="flex-end" justify="space-between">
           <PageHeader
diff --git 
a/modules/research-framework/portal/src/components/notebooks/NotebookCard.tsx 
b/modules/research-framework/portal/src/components/notebooks/NotebookCard.tsx
deleted file mode 100644
index d2bda42287..0000000000
--- 
a/modules/research-framework/portal/src/components/notebooks/NotebookCard.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import {
-  Box,
-  Image,
-  Icon,
-  Text,
-  Card,
-  HStack,
-  Avatar,
-  Button,
-} from "@chakra-ui/react";
-import { FaPlay } from "react-icons/fa";
-import { Link } from "react-router";
-
-export const NotebookCard = ({ notebook }: { notebook: any }) => {
-  return (
-    <Box>
-      <Card.Root overflow="hidden">
-        <Image
-          src={notebook.images.headerImage}
-          alt="Green double couch with wooden legs"
-        />
-        <Link to={notebook.slug}>
-          <Card.Body
-            gap="2"
-            _hover={{
-              bg: "gray.100",
-            }}
-          >
-            <Card.Title>{notebook.title}</Card.Title>
-            <HStack>
-              {notebook.tags.map((tag: string) => (
-                <Text key={tag} bg="gray.200" p={1} rounded="md">
-                  {tag}
-                </Text>
-              ))}
-            </HStack>
-            <Card.Description>{notebook.description}.</Card.Description>
-          </Card.Body>
-        </Link>
-
-        <Card.Footer justifyContent="space-between">
-          <HStack mt={4}>
-            <Avatar.Root shape="full" size="xl">
-              <Avatar.Fallback name={notebook.author.name} />
-              <Avatar.Image src={notebook.author.avatar} />
-            </Avatar.Root>
-
-            <Box>
-              <Text fontWeight="bold">{notebook.author.name}</Text>
-              <Text color="gray.500">{notebook.author.role}</Text>
-            </Box>
-          </HStack>
-
-          <Button>
-            Run
-            <Icon ml={1} size={"sm"}>
-              <FaPlay />
-            </Icon>
-          </Button>
-        </Card.Footer>
-      </Card.Root>
-    </Box>
-  );
-};
diff --git 
a/modules/research-framework/portal/src/components/notebooks/index.tsx 
b/modules/research-framework/portal/src/components/notebooks/index.tsx
index 7baa79aee7..ac0dd44507 100644
--- a/modules/research-framework/portal/src/components/notebooks/index.tsx
+++ b/modules/research-framework/portal/src/components/notebooks/index.tsx
@@ -1,5 +1,4 @@
 import { Container, Input, SimpleGrid } from "@chakra-ui/react";
-import NavBar from "../NavBar";
 import { PageHeader } from "../PageHeader";
 import { InputGroup } from "../ui/input-group";
 import { LuSearch } from "react-icons/lu";
@@ -40,8 +39,6 @@ const Notebooks = () => {
 
   return (
     <>
-      <NavBar />
-
       <Container maxW="container.lg" mt={8}>
         <PageHeader
           title="Notebooks"
diff --git 
a/modules/research-framework/portal/src/components/repositories/RepositorySpecificDetails.tsx
 
b/modules/research-framework/portal/src/components/repositories/RepositorySpecificDetails.tsx
index ba1f3f08a3..1bd94b9a53 100644
--- 
a/modules/research-framework/portal/src/components/repositories/RepositorySpecificDetails.tsx
+++ 
b/modules/research-framework/portal/src/components/repositories/RepositorySpecificDetails.tsx
@@ -11,6 +11,7 @@ import {
   Breadcrumb,
 } from "@chakra-ui/react";
 import { Fragment, useEffect, useState } from "react";
+import { FaGithub } from "react-icons/fa";
 import { FiFolder, FiFile } from "react-icons/fi";
 
 interface FileTreeItem {
@@ -22,11 +23,12 @@ interface FileTreeItem {
 }
 
 export const RepositorySpecificDetails = ({
-  dataset,
+  repository,
 }: {
-  dataset: RepositoryResource;
+  repository: RepositoryResource;
 }) => {
-  const githubUrl = dataset.repositoryUrl;
+  console.log(repository);
+  const githubUrl = repository.repositoryUrl;
   const [fileTree, setFileTree] = useState<FileTreeItem[]>([]);
   const [fileTreeLoading, setFileTreeLoading] = useState(false);
   const [currentPath, setCurrentPath] = useState<string>("");
@@ -122,75 +124,85 @@ export const RepositorySpecificDetails = ({
   if (error !== null) return null;
 
   return (
-    <Box
-      bg="white"
-      p={4}
-      borderRadius="md"
-      shadow="md"
-      overflow="auto"
-      height="full"
-    >
-      <Button onClick={handleGoBack} mb={4}>
-        Back
+    <>
+      {/* @ts-expect-error This is fine */}
+      <Button size="sm" as="a" target="_blank" href={repository.repositoryUrl}>
+        <FaGithub />
+        Open {repository.name} on GitHub
       </Button>
-      <Breadcrumb.Root mt={2}>
-        <Breadcrumb.List>
-          <Breadcrumb.Item>
-            <Breadcrumb.Link href="#">root</Breadcrumb.Link>
-          </Breadcrumb.Item>
 
-          {history.length > 0 &&
-            currentPath
-              .split("/")
-              .filter(Boolean) // Remove empty strings
-              .map((path, index) => (
-                <Fragment key={index}>
-                  <Breadcrumb.Separator />
-                  <Breadcrumb.Item>
-                    <Breadcrumb.Link href="#">{path}</Breadcrumb.Link>
-                  </Breadcrumb.Item>
-                </Fragment>
+      <Box
+        mt={4}
+        bg="white"
+        p={4}
+        borderRadius="md"
+        shadow="md"
+        overflow="auto"
+        height="full"
+      >
+        {/* Open in GitHub button */}
+        <Button onClick={handleGoBack} mb={4}>
+          Back
+        </Button>
+        <Breadcrumb.Root mt={2}>
+          <Breadcrumb.List>
+            <Breadcrumb.Item>
+              <Breadcrumb.Link href="#">root</Breadcrumb.Link>
+            </Breadcrumb.Item>
+
+            {history.length > 0 &&
+              currentPath
+                .split("/")
+                .filter(Boolean) // Remove empty strings
+                .map((path, index) => (
+                  <Fragment key={index}>
+                    <Breadcrumb.Separator />
+                    <Breadcrumb.Item>
+                      <Breadcrumb.Link href="#">{path}</Breadcrumb.Link>
+                    </Breadcrumb.Item>
+                  </Fragment>
+                ))}
+          </Breadcrumb.List>
+        </Breadcrumb.Root>{" "}
+        {fileContent ? (
+          <Box p={4} bg="gray.100" borderRadius="md">
+            <Text whiteSpace="pre-wrap" fontSize="sm" fontFamily="monospace">
+              {fileContent}
+            </Text>
+          </Box>
+        ) : (
+          <ListRoot>
+            {Array.isArray(fileTree) &&
+              fileTree.map((file) => (
+                <ListItem
+                  key={file.sha}
+                  display="flex"
+                  alignItems="center"
+                  p={2}
+                  borderRadius="md"
+                  _hover={{ bg: "gray.100", cursor: "pointer" }}
+                  onClick={() =>
+                    file.type === "dir"
+                      ? handleFolderClick(file.path)
+                      : handleFileClick(file.path)
+                  }
+                >
+                  <Icon
+                    as={file.type === "dir" ? FiFolder : FiFile}
+                    color={file.type === "dir" ? "blue.500" : "gray.500"}
+                    mr={2}
+                  />
+                  <p>{file.name}</p>
+                  {file.size !== undefined && file.size > 0 && (
+                    <Text fontSize="xs" color="gray.500" ml={2}>
+                      ({file.size} bytes)
+                    </Text>
+                  )}
+                </ListItem>
               ))}
-        </Breadcrumb.List>
-      </Breadcrumb.Root>{" "}
-      {fileContent ? (
-        <Box p={4} bg="gray.100" borderRadius="md">
-          <Text whiteSpace="pre-wrap" fontSize="sm" fontFamily="monospace">
-            {fileContent}
-          </Text>
-        </Box>
-      ) : (
-        <ListRoot>
-          {Array.isArray(fileTree) &&
-            fileTree.map((file) => (
-              <ListItem
-                key={file.sha}
-                display="flex"
-                alignItems="center"
-                p={2}
-                borderRadius="md"
-                _hover={{ bg: "gray.100", cursor: "pointer" }}
-                onClick={() =>
-                  file.type === "dir"
-                    ? handleFolderClick(file.path)
-                    : handleFileClick(file.path)
-                }
-              >
-                <Icon
-                  as={file.type === "dir" ? FiFolder : FiFile}
-                  color={file.type === "dir" ? "blue.500" : "gray.500"}
-                  mr={2}
-                />
-                <p>{file.name}</p>
-                {file.size !== undefined && file.size > 0 && (
-                  <Text fontSize="xs" color="gray.500" ml={2}>
-                    ({file.size} bytes)
-                  </Text>
-                )}
-              </ListItem>
-            ))}
-        </ListRoot>
-      )}
-    </Box>
+          </ListRoot>
+        )}
+      </Box>
+    </>
   );
 };
diff --git 
a/modules/research-framework/portal/src/components/repositories/index.tsx 
b/modules/research-framework/portal/src/components/repositories/index.tsx
index 665c6ab724..bf593ad0c2 100644
--- a/modules/research-framework/portal/src/components/repositories/index.tsx
+++ b/modules/research-framework/portal/src/components/repositories/index.tsx
@@ -1,5 +1,4 @@
 import { Container, Input, SimpleGrid } from "@chakra-ui/react";
-import NavBar from "../NavBar";
 import { PageHeader } from "../PageHeader";
 import api from "@/lib/api";
 import { useEffect, useState } from "react";
@@ -40,8 +39,6 @@ const Repositories = () => {
 
   return (
     <>
-      <NavBar />
-
       <Container maxW="container.lg" mt={8}>
         <PageHeader
           title="Repositories"
diff --git 
a/modules/research-framework/portal/src/components/resources/ResourceDetails.tsx
 
b/modules/research-framework/portal/src/components/resources/ResourceDetails.tsx
index a475cf302d..73aab50862 100644
--- 
a/modules/research-framework/portal/src/components/resources/ResourceDetails.tsx
+++ 
b/modules/research-framework/portal/src/components/resources/ResourceDetails.tsx
@@ -1,5 +1,4 @@
 import { useNavigate, useParams } from "react-router";
-import NavBar from "../NavBar";
 import {
   Container,
   Spinner,
@@ -60,7 +59,6 @@ const ResourceDetails = () => {
 
   return (
     <>
-      <NavBar />
       <Container maxW="breakpoint-lg" mx="auto" p={4} mt={16}>
         <Box>
           <Button variant="plain" p={0} onClick={() => navigate(-1)}>
@@ -150,7 +148,7 @@ const ResourceDetails = () => {
           {(resource.type as ResourceTypeEnum) ===
             ResourceTypeEnum.REPOSITORY && (
             <RepositorySpecificDetails
-              dataset={resource as RepositoryResource}
+              repository={resource as RepositoryResource}
             />
           )}
 
diff --git a/modules/research-framework/portal/src/layouts/NavBar.tsx 
b/modules/research-framework/portal/src/layouts/NavBar.tsx
new file mode 100644
index 0000000000..be483f7f41
--- /dev/null
+++ b/modules/research-framework/portal/src/layouts/NavBar.tsx
@@ -0,0 +1,142 @@
+import {
+  Text,
+  Flex,
+  Spacer,
+  Image,
+  HStack,
+  Avatar,
+  Box,
+  IconButton,
+  useDisclosure,
+  Collapsible,
+  Button,
+  Stack,
+  ButtonProps,
+} from "@chakra-ui/react";
+import ApacheAiravataLogo from "../assets/airavata-logo.png";
+import { Link, useNavigate } from "react-router";
+import { useAuth } from "react-oidc-context";
+import { RxHamburgerMenu } from "react-icons/rx";
+import { IoClose } from "react-icons/io5";
+
+const NAV_CONTENT = [
+  {
+    title: "Projects",
+    url: "/projects",
+  },
+  {
+    title: "Datasets",
+    url: "/resources/datasets",
+  },
+  {
+    title: "Repositories",
+    url: "/resources/repositories",
+  },
+  {
+    title: "Notebooks",
+    url: "/resources/notebooks",
+  },
+  {
+    title: "Models",
+    url: "/resources/models",
+  },
+];
+
+interface NavLinkProps extends ButtonProps {
+  title: string;
+  url: string;
+}
+
+const NavBar = () => {
+  const auth = useAuth();
+  const { open, onToggle } = useDisclosure();
+  const navigate = useNavigate();
+
+  const NavLink = ({ title, url, ...props }: NavLinkProps) => (
+    <Button
+      variant="plain"
+      px={2}
+      _hover={{ bg: "gray.200" }}
+      onClick={() => {
+        navigate(url);
+        onToggle();
+      }}
+      {...props}
+    >
+      <Text color="gray.700" fontSize="md" textAlign="left">
+        {title}
+      </Text>
+    </Button>
+  );
+
+  return (
+    <Box position="sticky" top="0" zIndex="1000" bg="white" boxShadow="sm">
+      <Flex align="center" p={4}>
+        {/* Hamburger Menu (Mobile Only) */}
+        <IconButton
+          aria-label="Toggle Navigation"
+          display={{ base: "inline-flex", md: "none" }}
+          onClick={onToggle}
+          variant="ghost"
+          mr={2}
+        >
+          {open ? <IoClose size={24} /> : <RxHamburgerMenu size={24} />}
+        </IconButton>
+
+        {/* Logo */}
+        <Link to="/projects">
+          <Image src={ApacheAiravataLogo} alt="Logo" boxSize="30px" />
+        </Link>
+
+        {/* Desktop Nav Links */}
+        <HStack ml={4} display={{ base: "none", md: "flex" }}>
+          {NAV_CONTENT.map((item) => (
+            <NavLink key={item.title} title={item.title} url={item.url} />
+          ))}
+        </HStack>
+
+        <Spacer />
+
+        {/* User Profile */}
+        <HStack gap={3}>
+          <Avatar.Root variant="subtle">
+            <Avatar.Fallback name={auth.user?.profile.name} />
+          </Avatar.Root>
+          <Box textAlign="left">
+            <Text fontSize="sm">{auth.user?.profile.name}</Text>
+            <Text fontSize="xs" color="gray.500">
+              {auth.user?.profile.email}
+            </Text>
+          </Box>
+        </HStack>
+      </Flex>
+
+      {/* Mobile Nav Links (Collapse) */}
+      <Collapsible.Root open={open}>
+        <Collapsible.Content>
+          <Stack
+            direction="column"
+            bg="white"
+            px={4}
+            pb={4}
+            spaceY={2}
+            display={{ md: "none" }}
+          >
+            {NAV_CONTENT.map((item) => (
+              <Box key={item.title} w="100%">
+                <NavLink
+                  key={item.title}
+                  title={item.title}
+                  url={item.url}
+                  width="100%"
+                />
+              </Box>
+            ))}
+          </Stack>
+        </Collapsible.Content>
+      </Collapsible.Root>
+    </Box>
+  );
+};
+
+export default NavBar;
diff --git 
a/modules/research-framework/portal/src/layouts/NavBarFooterLayout.tsx 
b/modules/research-framework/portal/src/layouts/NavBarFooterLayout.tsx
new file mode 100644
index 0000000000..04d80846a6
--- /dev/null
+++ b/modules/research-framework/portal/src/layouts/NavBarFooterLayout.tsx
@@ -0,0 +1,14 @@
+// layout.tsx
+import NavBar from "@/layouts/NavBar";
+import { Outlet } from "react-router";
+
+const NavBarFooterLayout = () => {
+  return (
+    <>
+      <NavBar />
+      <Outlet />
+    </>
+  );
+};
+
+export default NavBarFooterLayout;

Reply via email to