From 18375fddfc72d1741a9c302aa284cf6a789428c0 Mon Sep 17 00:00:00 2001
From: liliana <liliana.sanfilippo@uni-bielefeld.de>
Date: Sat, 29 Jun 2024 15:39:44 +0200
Subject: [PATCH] this should at least work with the pipelin

---
 src/App/App.css                   | 689 ++++++++++++++++++++++++++++++
 src/App/App.tsx                   | 100 +++++
 src/components/Footer.tsx         | 186 ++++++++
 src/components/Header.tsx         |  20 +
 src/components/Navbar.tsx         |  66 +++
 src/components/NotFound.tsx       |  16 +
 src/components/Sidebar.tsx        | 109 +++++
 src/components/Villagebuttons.tsx |  27 ++
 src/main.tsx                      |  12 +
 src/utils/getPathMapping.ts       |  36 ++
 src/utils/index.ts                |   2 +
 src/utils/stringToSlug.ts         |   9 +
 src/vite-env.d.ts                 |  13 +
 13 files changed, 1285 insertions(+)
 create mode 100644 src/App/App.css
 create mode 100644 src/App/App.tsx
 create mode 100644 src/components/Footer.tsx
 create mode 100644 src/components/Header.tsx
 create mode 100644 src/components/Navbar.tsx
 create mode 100644 src/components/NotFound.tsx
 create mode 100644 src/components/Sidebar.tsx
 create mode 100644 src/components/Villagebuttons.tsx
 create mode 100644 src/main.tsx
 create mode 100644 src/utils/getPathMapping.ts
 create mode 100644 src/utils/index.ts
 create mode 100644 src/utils/stringToSlug.ts
 create mode 100644 src/vite-env.d.ts

diff --git a/src/App/App.css b/src/App/App.css
new file mode 100644
index 00000000..6a6f7f33
--- /dev/null
+++ b/src/App/App.css
@@ -0,0 +1,689 @@
+/* * * * * * * */
+/* * COLOURS * */
+/* * * * * * * */
+:root {
+  /* our colours*/
+  --text-primary: #850F78; 
+  --mediumpurple: #bc15aa; 
+  /*--purple: #B85BD1; */
+  --accen-secondary: #F57D22; 
+  --accent-primary: #F4CC1E; 
+  --lightyellow: #fae99e; 
+  --lightblue: #A0A7F3 ; 
+  --offblack: #32232C ; 
+  --cebitecgray: #8295A4; 
+  /*--offwhite: #e9dff1; */
+  --ourbeige: #FFF6F2; 
+  --background: white; 
+  /*igem colours*/
+  --igemdarkgreen: #006530; 
+  --igemmediumgreen: #019968; 
+  --igemlightgreen: #99cb9a; 
+}
+/* * * * * * * */
+/* * * BODY* * */
+/* * * * * * * */
+body {
+  padding-top: 56px;
+  background-color: var(--background);
+  color: #493843;
+}
+body.dark-mode {
+  background-color: var(--offblack);
+  color: white;
+}
+p {
+  text-align: justify;
+}
+a {
+  color: var(--lightblue) !important;
+  text-decoration: none !important;
+}
+a:active {
+  background-color: yellow;
+}
+/* * * * * * * */
+/* *SIDEBAR* * */
+/* * * * * * * */
+
+.sidebar{
+  border-left: 6px solid;
+  border-left-color: var(--text-primary);
+  border-color: var(--accent-primary);
+  color: var(--text-primary);
+  list-style-type: none;
+  line-height: 280%;
+  margin: 0px 0px;
+  padding: 0px 0px;
+}
+.sidebar>div>a>span:hover{
+  text-shadow: 5px 5px 15px black;
+  transition: all 0.1s linear;
+}
+.sidebar>div{
+overflow: hidden;
+text-align: center;
+cursor: pointer;
+}
+.sidebar>div>a>span{
+padding: 1rem;
+color: var(--text-primary);
+}
+.active-scroll-spy{
+  background-color: yellowgreen !important;
+}
+
+/* * * * * * * */
+/* * GENERAL * */
+/* * * * * * * */
+.left-aligned {margin-left: auto;}
+.align-items-center{align-items:center!important}
+.zweirem{padding: 2rem;}
+.left{float: left;}
+.right{float: right;}
+.sticky-top {
+  position: -webkit-sticky;
+  position: sticky !important; 
+  top: 0;
+  z-index: 1020;
+  top: 80px !important; 
+  overflow-wrap: break-word;
+}
+.fullsize{
+  max-height: 100% !important;
+  max-width: 100% !important; 
+}
+.null{
+  padding: 0% !important;
+   margin: 0% !important;
+}
+.v-align-m{
+  vertical-align: middle !important; 
+}
+.fit-cont{
+  max-width: fit-content;
+}
+.center{
+  display: flex !important;
+  align-items: center !important;
+}
+/* * * * * * * */
+/* *  NAVBAR * */
+/* * * * * * * */
+.nav-link{
+  color: var(--text-primary) !important; 
+}
+.nav-link:hover {
+  color: white !important;
+  background-color: var(--text-primary) !important;
+  border-radius: 7px;
+}
+.navbar{
+  backdrop-filter: blur(5px);
+  transition: visibility 0s, 0.6s, opacity 0.6s linear, transform 1s;
+}
+  nav.navbar {
+  padding-top: 1rem;
+  padding-bottom: 1rem;
+}
+.dropdown-item{
+  color: var(--text-primary) !important;
+}
+.dropdown-item:hover{
+  color: white !important;
+  background-color: var(--text-primary) !important;
+}
+.nav-item.dropdown:hover .dropdown-menu {
+  display: block;
+  background-color: white;
+  border-color: var(--text-primary);
+  border-radius: 7px;
+}
+.navbar-brand{
+  color: var(--text-primary) !important;
+}
+
+
+
+/* * * * * * * */
+/* BACKGROUND  */
+/* * * * * * * */
+.bg-d{
+  background-color: var(--text-primary) !important;
+}
+.bg-l{
+  background-color: var(--text-primary) !important;
+  color: white;
+}
+.bg-transp{
+  background:transparent;
+  color: var(--text-primary);
+}
+
+/* * * * * * * */
+/* *HEADINGS * */
+/* * * * * * * */
+h2{
+  font-size: 3rem !important;
+  -webkit-background-clip: text !important;
+  -webkit-text-stroke-width: 2px !important;
+  -webkit-text-stroke-color: var(--text-primary) !important;
+  background-clip: text !important;
+  color: transparent !important;
+  padding-top: 15px !important;
+  background-image: repeating-linear-gradient(-45deg, var(--text-primary) 0, var(--text-primary) 2px, white 2px, white 4px) !important;
+}
+
+.underline--magical {
+  background-image: linear-gradient(120deg, var(--lightblue) 0%, var(--mediumpurple) 100%);
+  background-repeat: no-repeat;
+  color: black;
+  background-size: 100% 0.2em;
+  background-position: 0 105%;
+  transition: background-size 0.25s ease-in;
+}
+.underline--magical:hover {
+  background-size: 100% 100%;
+  color: black !important;
+  text-decoration: none !important;
+} 
+
+
+/* * * * * * * */
+/* * CALLOUT * */
+/* * * * * * * */
+.bd-callout {
+  padding: 1.25rem;
+  margin-top: 1.25rem;
+  margin-bottom: 1.25rem;
+  border: 1px solid #e9ecef;
+  border-left-width: 0.25rem;
+  border-radius: 0.25rem;
+}
+
+.bd-callout h4 {
+  margin-bottom: 0.25rem;
+}
+
+.bd-callout p:last-child {
+  margin-bottom: 0;
+}
+
+.bd-callout code {
+  border-radius: 0.25rem;
+}
+
+.bd-callout + .bd-callout {
+  margin-top: -0.25rem;
+}
+
+.bd-callout-info {
+  border-left-color: #ABD2FA;
+}
+
+.bd-callout-warning {
+  border-left-color: #f0ad4e;
+}
+
+.bd-callout-danger {
+  border-left-color: #d9534f;
+}
+
+/* * * * * * * */
+/* *  FOOTER * */
+/* * * * * * * */
+footer{
+  background-color: var(--background);
+}
+footer a {
+  color: white;
+  font-weight: bold;
+  text-decoration: none;
+}
+footer a:hover {
+  color: white;
+  text-decoration: underline;
+}
+
+
+/* * * * * * * * */
+/*VILLAGE BUTTONS*/
+/* * * * * * * * */
+.bottom-buttons{
+  margin-top: 50px !important; 
+  margin-bottom: 20px;
+  padding-left: 30px;
+}
+.village-style-button{
+  box-shadow: 5px 5px 15px gray !important;
+  border-radius: 2rem !important;
+  padding: 0 !important;
+  max-width: 12% !important;
+  aspect-ratio: 2 / 3 !important; 
+  margin-left: 1vw;
+}
+.village-style-button:hover{
+  box-shadow: 5px 5px 15px black !important;
+}
+.village-style-button h3{
+  text-align: center !important;
+  font-size: 10px;
+  font-weight: bold;
+  color: #000;
+}
+.village-style-button img{
+  max-width: 70% !important;
+  max-height: 70% !important;
+  padding-top: 20px !important;
+}
+
+/* * * * * * * * * */
+/* * *  IMAGES * * */
+/* * * * * * * * * */
+img,
+picture,
+svg {
+  max-width: 100%;
+  display: block;
+}
+img .middle{
+  vertical-align:middle;
+}
+.socials{
+  height: 1.5rem;
+  width: auto;
+  margin: 0.5rem;
+}
+.img-sponsor{
+  max-width: 70%;
+  max-height: 150px;
+}
+.img-right{
+  float: right !important;
+  padding-left: 1vw !important;
+  padding-bottom: 1vw !important;
+  padding-top: 1vw !important;
+}
+.img-half{
+  max-width: 50% !important;
+}
+
+.hexagon{
+  clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
+}
+
+/* * * * * * * */
+/* * * SVG * * */
+/* * * * * * * */
+svg{
+  background:transparent
+}
+svg text{
+  font-size: 7vw !important;
+  stroke-width:2px !important;
+  fill:var(--accent-primary) ;
+  stroke:var(--text-primary);
+  /*letter-spacing:4px;*/
+  animation:effect 3s, dash 3s;
+}
+svg text:hover{
+  fill: var(--text-primary)
+}
+
+
+
+
+/* * * * * * * */
+/* MEDIA RULES */
+/* * * * * * * */
+/*For tablet or bigger*/
+@media screen and (min-width: 992px) {
+  /* navbar opens on hover*/ 
+  .dropdown:hover .dropdown-menu {
+      display: block;
+  }
+}
+/*For Tablet and smaller*/
+@media screen and (max-width: 992px){
+
+}
+/*For Smartphones*/
+@media screen and (max-width: 768px){
+  svg text{
+    font-size: 9vw;
+    stroke-width:1px;
+  }
+  .village-style-button h3{
+    display: none !important;
+  }
+  .village-style-button{
+    box-shadow: 1px 1px 1px gray;
+    border-radius: 10px;
+    border-color: black;
+  }
+  .village-style-button:hover{
+    box-shadow: none;
+  }
+  .village-style-button img{
+    max-width: 90%;
+    max-height: 90%;
+    padding-top: 10px;
+    padding-bottom: 5px;
+  }
+  .img-half{
+    max-width: 100% !important;
+  }
+}
+/*Bigger than smartphones*/
+@media only screen and (min-width: 768px) {
+  .col-1 {width: 8.33%;}
+  .col-2 {width: 16.66%;}
+  .col-3 {width: 25%;}
+  .col-4 {width: 33.33%;}
+  .col-5 {width: 41.66%;}
+  .col-6 {width: 50%;}
+  .col-7 {width: 58.33%;}
+  .col-8 {width: 66.66%;}
+  .col-9 {width: 75%;}
+  .col-10 {width: 83.33%;}
+  .col-11 {width: 91.66%;}
+  .col-12 {width: 100%;}
+
+  
+}
+
+
+/* * * * * * * */
+/* * EFFECTS * */
+/* * * * * * * */
+@keyframes effect{
+  0%{
+    stroke-dasharray:0 70%;
+  }
+  100%{
+    stroke-dasharray:10% 0%;
+    stroke-dashoffset:20%;
+  }
+}
+@keyframes dash {
+  0% {
+    stroke-dashoffset: 1300;
+  }
+  35% {
+    fill-opacity: 0;
+  }
+  50% {
+    stroke-dashoffset: 0;
+  }
+  100% {
+    stroke-dashoffset: 0;
+    fill-opacity: 1;
+  }
+}
+
+
+
+
+/* TIMELINE EINS */
+
+.timeline-container {
+  display: flex;
+  flex-direction: column;
+  position: relative;
+  margin: 40px 0;
+}
+
+.timeline-container::after {
+  background-color: var(--text-primary);
+  position: absolute;
+  left: calc(50% - 2px);
+  content: "";
+  width: 4px;
+  height: 100%;
+}
+.timeline-item {
+  display: flex;
+  justify-content: flex-end;
+  padding-right: 30px;
+  position: relative;
+  margin: 10px 0;
+  width: 50%;
+}
+
+.timeline-item:nth-child(odd) {
+  align-self: flex-end;
+  justify-content: flex-start;
+  padding-left: 30px;
+  padding-right: 0;
+}
+.timeline-item-content {
+  box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
+  border-radius: 5px;
+  background-color: #fff;
+  display: flex;
+  flex-direction: column;
+  align-items: flex-end;
+  padding: 15px;
+  position: relative;
+  text-align: right;
+}
+
+.timeline-item-content::after {
+  background-color: #fff;
+  box-shadow: 1px -1px 1px rgba(0, 0, 0, 0.2);
+  position: absolute;
+  right: -7.5px;
+  top: calc(50% - 7.5px);
+  transform: rotate(45deg);
+  width: 15px;
+  height: 15px;
+}
+
+.timeline-item:nth-child(odd) .timeline-item-content {
+  text-align: left;
+  align-items: flex-start;
+}
+
+.timeline-item:nth-child(odd) .timeline-item-content::after {
+  right: auto;
+  left: -7.5px;
+  box-shadow: -1px 1px 1px rgba(0, 0, 0, 0.2);
+}
+.timeline-item-content .tag {
+  color: #fff;
+  font-size: 12px;
+  font-weight: bold;
+  top: 5px;
+  left: 5px;
+  letter-spacing: 1px;
+  padding: 5px;
+  position: absolute;
+  text-transform: uppercase;
+}
+
+.timeline-item:nth-child(odd) .timeline-item-content .tag {
+  left: auto;
+  right: 5px;
+}
+
+.timeline-item-content time {
+  color: var(--lightblue);
+  font-size: 12px;
+  font-weight: bold;
+}
+
+.timeline-item-content p {
+  font-size: 16px;
+  line-height: 24px;
+  margin: 15px 0;
+  max-width: 250px;
+}
+
+.timeline-item-content a {
+  font-size: 14px;
+  font-weight: bold;
+}
+
+.timeline-item-content a::after {
+  font-size: 12px;
+}
+
+.timeline-item-content .circle {
+  background-color: #fff;
+  border: 3px solid var(--text-primary);
+  border-radius: 50%;
+  position: absolute;
+  top: calc(50% - 10px);
+  right: -40px;
+  width: 20px;
+  height: 20px;
+  z-index: 100;
+}
+
+.timeline-item:nth-child(odd) .timeline-item-content .circle {
+  right: auto;
+  left: -40px;
+}
+@media only screen and (max-width: 1023px) {
+  .timeline-item-content {
+      max-width: 100%;
+  }
+}
+
+@media only screen and (max-width: 767px) {
+  .timeline-item-content,
+  .timeline-item:nth-child(odd) .timeline-item-content {
+      padding: 15px 10px;
+      text-align: center;
+      align-items: center;
+  }
+  
+  .timeline-item-content .tag {
+      width: calc(100% - 10px);
+      text-align: center;
+  }
+  
+  .timeline-item-content time {
+      margin-top: 20px;
+  }
+  
+  .timeline-item-content a {
+      text-decoration: underline;
+  }
+  
+  .timeline-item-content a::after {
+      display: none;
+  }
+}
+
+
+.timeline {
+  background-color: inherit; 
+  font-size: 1rem; 
+  }
+
+.card {
+  border-radius: 4px;
+  background-color: #fff;
+  color: #333;
+  padding: 10px;
+  box-shadow: 0 4px 6px 0 hsla(0, 0%, 0%, 0.2);
+  width: 100%;
+  max-width: 560px;
+  
+}
+.date {
+  background-color: var(--text-primary) !important;
+  padding: 4px !important;
+  color: #fff !important;
+  border-radius: 4px !important;
+  font-weight: 500;
+  font-size: .85rem;
+}
+.imageAtom{
+  object-fit: cover;
+  overflow: hidden;
+  width: 100%;
+  max-height: 400px;
+}
+.imageCredit { margin-top: 10px; font-size: 0.85rem }
+.imageText { margin-bottom: 10px; font-size: 1rem }
+.events{ padding: 10px }
+.event { margin-bottom: 20px }
+
+.date-col{
+  position: relative;
+    background-color: #fff ;
+    padding: 10px;
+    width: 10%;
+    border-right: #000;
+    border-right-width: 2px;
+}
+
+.card-col{
+  width: 100%;
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-start;
+  flex-basis: 50%;
+  flex-grow: 1;
+  align-items: flex-end;
+}
+
+.img-text{
+  margin-bottom:10px;
+    font-size:  1rem;
+}
+.img-credit{
+  margin-top: 10px; 
+    font-size: 0.85rem;
+}
+.event{
+  position: relative;
+  display: flex;
+  margin-top: 20px;
+}
+.img-timeline{
+  overflow: hidden;
+   object-fit: cover; 
+    width: 100%;  
+    max-height: 400px; 
+}
+
+
+/*PDF*/
+.container_document{
+  max-width: 40%;
+}
+
+
+.download-butt{
+  background-color: var(--text-primary);
+  padding: 0.5vw;
+  border-radius: 5px;
+  margin: auto !important;
+  width: fit-content !important;
+}
+.download-col{
+  height: 5vw !important;
+  display: flex;
+  align-items: center !important;
+}
+.small-i{
+  width: 80%;
+}
+
+
+/* SHAPES */
+.circle {
+  display: flex;
+  width: 10vw;
+  height: 10vw;
+  background-color: var(--lightblue) !important;
+  border-radius: 50%;
+  margin: 1vw;
+}
+.shape-text {
+  margin: auto;
+  text-align: center;
+}
\ No newline at end of file
diff --git a/src/App/App.tsx b/src/App/App.tsx
new file mode 100644
index 00000000..3525633d
--- /dev/null
+++ b/src/App/App.tsx
@@ -0,0 +1,100 @@
+import "./App.css";
+import "bootstrap/dist/css/bootstrap.min.css";
+import { Route, Routes } from "react-router-dom";
+import { Footer } from "../components/Footer.tsx";
+import { Header } from "../components/Header.tsx";
+import { NotFound } from "../components/NotFound.tsx";
+import { Navbar } from "../components/Navbar.tsx";
+import { getPathMapping } from "../utils/getPathMapping.ts";
+import { stringToSlug } from "../utils/stringToSlug.ts";
+import { useEffect} from "react";
+import Villbuttonrow from "../components/Villagebuttons.tsx";
+import Sidebar from "../components/Sidebar.tsx";
+import "../../utils/highlight.js";
+/* import Sidebar from "../../components/Sidebar.tsx"; */
+
+const App = () => {
+  /* // Dark Mode toggle 
+  const [isDarkMode, setIsDarkMode] = useState(true);
+  useEffect(() => {
+    document.body.className = isDarkMode ? 'dark-mode' : '';
+  }, [isDarkMode]); */
+
+  const pathMapping = getPathMapping();
+  const currentPath =
+    location.pathname
+      .split(`${stringToSlug(import.meta.env.VITE_TEAM_NAME)}`)
+      .pop() || "/";
+
+  // Set Page Title
+  const title =
+    currentPath in pathMapping ? pathMapping[currentPath].title : "Not Found";
+
+  useEffect(() => {
+    document.title = `${title || ""} | ${import.meta.env.VITE_TEAM_NAME} - iGEM ${import.meta.env.VITE_TEAM_YEAR}`;
+  }, [title]);
+
+  return (
+    <>
+      {/* Navigation */}
+      <Navbar /* isDarkMode={isDarkMode} setIsDarkMode={setIsDarkMode} */ />
+
+      {/* Header and PageContent */}
+      <Routes>
+        {Object.entries(pathMapping).map(
+          ([path, { navlist, title, lead, component: Component}]) => (
+            <Route
+              key={path}
+              path={path}
+              element={
+                <>
+                  <Header title={title || ""} lead={lead || ""} />
+                  {/* Page content */}
+                  <div className="container-fluid">
+                    <div className="row ">
+                      <div className="col-2 d-none d-lg-block"> 
+                        <div className="sticky-top sidebar">
+                           <Sidebar nums={navlist || [""]}></Sidebar>
+                        </div>
+                      </div>
+                      <div className="col">
+                        <Component />
+                        <Villbuttonrow/>
+                      </div>
+                      <div className="col-1 d-none d-lg-block" >
+                        {/* <!-- empty so far --> */}
+                        
+                      </div>
+                    </div>
+                  </div>
+
+                  {/* End page content */}
+                  
+
+                </>
+              }
+            />
+          ),
+        )}
+        <Route
+          path="*"
+          element={
+            <>
+              <Header
+                title="Not Found"
+                lead="The requested URL was not found on this server."
+              />
+              <NotFound />
+            </>
+          }
+        />
+      </Routes>
+
+      {/* Footer */}
+      {/* MUST mention license AND have a link to team wiki's repository on gitlab.igem.org */}
+      <Footer />
+    </>
+  );
+};
+
+export default App;
diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx
new file mode 100644
index 00000000..57e6f69f
--- /dev/null
+++ b/src/components/Footer.tsx
@@ -0,0 +1,186 @@
+import { stringToSlug } from "../utils";
+
+
+export function Footer() {
+  const teamYear = import.meta.env.VITE_TEAM_YEAR;
+  const teamName = import.meta.env.VITE_TEAM_NAME;
+  const teamSlug = stringToSlug(teamName);
+
+
+  return (
+    <footer className="pt-5 pb-5 footer py-5 mt-5 bg-d text-white">
+      <div className="container">
+      <div className="col zweirem">
+        <span className="left"> 
+          <a href="{{ url_for('pages', page='impressum') }}" className="middle">Impressum</a>
+        </span>
+        <span className="right">
+        <a href="https://www.linkedin.com/in/igem-bielefeld-cebitec">
+          <img className="socials" src="https://static.igem.wiki/teams/5247/design/icons/linkedin-hell.png"/>
+        </a>
+        <a href="https://www.instagram.com/igem.bielefeld/">
+          <img className="socials" src="https://static.igem.wiki/teams/5247/design/icons/instagram-1.png"/>
+        </a>
+        <a href="http://www.youtube.com/@iGemBielefeld2024">
+          <img className="socials" src="https://static.igem.wiki/teams/5247/design/icons/youtube-hell.png"/>
+        </a>
+        <a href="https://x.com/iGEM_Bielefeld">
+          <img className="socials" src="https://static.igem.wiki/teams/5247/design/icons/twitter-hell.png"/>
+        </a>
+      </span>
+      </div>
+      <hr/> 
+      <div className="row align-items-center">
+      <div className="col-sm-4">
+        <h6>Contact</h6>
+      </div>
+      <div className="col-sm-8">
+        <div className="row align-items-center">
+          <div className="col">
+            <a href="https://2024.igem.wiki/bielefeld-cebitec/partners">
+              <h6 className="alink">Spornsors and partners</h6>
+            </a>
+          </div>
+          <div className="col">
+            <h6>Former iGem Bielefeld teams</h6>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div className="row align-items-center">
+      <div className="col-sm-4">
+          <div className="col">
+            info@igem-bielefeld.de
+          </div>
+          <div className="col"> </div>
+          <div className="col">
+            iGEM2024
+            Universitätsstraße 25, 33613 Bielefeld
+            Centrum für Biotechnologie (CeBiTec)
+            Universität Bielefeld
+          </div> 
+        </div>
+      <div className="col-4">
+        <div className="slick-carousel align-items-center">
+            <a href="https://www.plasmidfactory.com/">
+              <img className="img-sponsor" src="https://static.igem.wiki/teams/5247/sponsors/plasmidfactory.png"/>
+            </a>
+            <a href="http://www.zeiss.de/naturwissenschaften">
+              <img className="img-sponsor" src="https://static.igem.wiki/teams/5247/sponsors/zeiss.png" />
+            </a>
+            <a href="https://www.jenabioscience.com/">
+              <img className="img-sponsor" src="https://static.igem.wiki/teams/5247/sponsors/jbs-dunkelgruen-text.png"/>
+            </a>
+            <a href="https://www.gip.com/home/">
+              <img className="img-sponsor" src="https://static.igem.wiki/teams/5247/sponsors/gip.png" />
+            </a>
+            <a href="https://www.integra-biosciences.com">
+              <img className="img-sponsor" src="https://static.igem.wiki/teams/5247/sponsors/integra-hinterlegt.jpeg" />
+            </a>
+            <a href="https://www.uni-bielefeld.de/">
+              <img className="img-sponsor" src="https://static.igem.wiki/teams/5247/logos-team/uni-bielefeld-dunkel.png"/>
+            </a>
+            <a href="www.snapgene.com">
+              <img className="img-sponsor" src="https://static.igem.wiki/teams/5247/sponsors/snapgene.png"/>
+            </a>
+            <a href="www.promega.com">
+              <img className="img-sponsor" src="https://static.igem.wiki/teams/5247/sponsors/promega-gelb.png"/>
+            </a>
+            <a href="https://www.carlroth.de/">
+              <img className="img-sponsor" src="https://static.igem.wiki/teams/5247/sponsors/roth.jpg"/>
+            </a>
+            <a href="https://bts-ev.de/">
+              <img className="img-sponsor" src="https://static.igem.wiki/teams/5247/sponsors/bts.png"/>
+            </a>
+            <a href="https://www.uni-bielefeld.de/fakultaeten/technische-fakultaet/arbeitsgruppen/multiscale-bioengineering/campusbrauerei/">
+              <img className="img-sponsor" src="https://static.igem.wiki/teams/5247/sponsors/campus-brauerei-hinterlegt.jpeg"/>
+            </a>
+        </div>
+      </div>
+      <div className="col-4"> 
+        <div className="row align-items-center">
+
+          <div className="col">
+            <div className="row align-items-center">
+              <div className="col">
+                <div className="col">
+                  <a href="https://2023.igem.wiki/bielefeld-cebitec/home"> Team 2023</a>
+                </div>
+                <div className="col">
+                  <a href="https://2021.igem.org/Team:Bielefeld-CeBiTec"> Team 2021</a>
+                </div>
+                <div className="col">
+                  <a href="https://2020.igem.org/Team:Bielefeld-CeBiTec"> Team 2020</a>
+                </div>
+                <div className="col">
+                  <a href="https://2019.igem.org/Team:Bielefeld-CeBiTec"> Team 2019</a>
+                </div>
+                <div className="col">
+                  <a href="https://2018.igem.org/Team:Bielefeld-CeBiTec"> Team 2018</a>
+                </div>
+                <div className="col">
+                  <a href="https://2017.igem.org/Team:Bielefeld-CeBiTec"> Team 2017</a>
+                </div>
+                <div className="col">
+                  <a href="https://2016.igem.org/Team:Bielefeld-CeBiTec"> Team 2016</a>
+                </div>
+              </div>
+              <div className="col">
+                <div className="col">
+                  <a href="https://2015.igem.org/Team:Bielefeld-CeBiTec" className="alink"> Team 2015</a>
+                </div>
+                <div className="col">
+                  <a href="https://2014.igem.org/Team:Bielefeld-CeBiTec"> Team 2014</a>
+                </div>
+                <div className="col">
+                  <a href="https://2013.igem.org/Team:Bielefeld-Germany"> Team 2013</a>
+                </div>
+                <div className="col">
+                  <a href="https://2012.igem.org/Team:Bielefeld-Germany"> Team 2012</a>
+                </div>
+                <div className="col">
+                  <a href="https://2011.igem.org/Team:Bielefeld-Germany"> Team 2011</a>
+                </div>
+                <div className="col">
+                  <a href="https://2010.igem.org/Team:Bielefeld-Germany"> Team 2010</a>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <hr/> 
+
+        <hr />
+        {/* The following MUST be on every page: license information and link to the repository on gitlab.igem.org */}
+        <div className="row mt-4">
+          <div className="col">
+            <p className="mb-0">
+              <small>
+                © 2024 - Content on this site is licensed under a{" "}
+                <a
+                  className="subfoot"
+                  href="https://creativecommons.org/licenses/by/4.0/"
+                  rel="license"
+                >
+                  Creative Commons Attribution 4.0 International license
+                </a>
+                .
+              </small>
+            </p>
+            <p>
+              <small>
+                The repository used to create this website is available at{" "}
+                <a href={`https://gitlab.igem.org/${teamYear}/${teamSlug}`}>
+                  gitlab.igem.org/{teamYear}/{teamSlug}
+                </a>
+                .
+              </small>
+            </p>
+          </div>
+        </div>
+      </div>
+    </footer>
+  );
+}
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
new file mode 100644
index 00000000..dbb8bb19
--- /dev/null
+++ b/src/components/Header.tsx
@@ -0,0 +1,20 @@
+import { H1 } from './headings.tsx';
+interface HeaderProps {
+  title: string;
+  lead: string;
+}
+
+export function Header({ title, lead }: HeaderProps) {
+  return (
+    <header className="py-5 mb-5">
+      <div className="container h-100">
+        <div className="row h-100 align-items-center">
+          <div className="col-lg-12">
+          <H1 text={title}></H1>
+            <p className="lead mb-5">{lead}</p>
+          </div>
+        </div>
+      </div>
+    </header>
+  );
+}
diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx
new file mode 100644
index 00000000..d554cb4e
--- /dev/null
+++ b/src/components/Navbar.tsx
@@ -0,0 +1,66 @@
+import Container from "react-bootstrap/Container";
+import Nav from "react-bootstrap/Nav";
+import BootstrapNavbar from "react-bootstrap/Navbar";
+import NavDropdown from "react-bootstrap/NavDropdown";
+import { Link } from "react-router-dom";
+import Pages from "../pages.ts";
+
+export function Navbar(/* {isLightMode, setIsLightMode}:any */) {
+
+  /* const handleToggle = () => {
+    setIsLightMode(!isLightMode);
+  }; */
+
+  const pages = Pages.map((item, pageIndex) => {
+    if ("folder" in item && item.folder) {
+      const folderItems = item.folder.map((subpage, subpageIndex) => {
+        if (subpage.path) {
+          return (
+            <NavDropdown.Item
+              key={`subpage-${pageIndex}-${subpageIndex}`}
+              as={Link}
+              to={subpage.path}
+            >
+              {subpage.name}
+            </NavDropdown.Item>
+          );
+        }
+      });
+      return (
+        <NavDropdown
+          key={`page-${pageIndex}`}
+          title={item.name}
+          renderMenuOnMount={true}
+          id="basic-nav-dropdown"
+        >
+          {folderItems}
+        </NavDropdown>
+      );
+    } else if ("path" in item && item.path) {
+      return (
+        <Nav.Link key={`page-${pageIndex}`} as={Link} to={item.path}>
+          {item.name}
+        </Nav.Link>
+      );
+    }
+  });
+
+  return (
+    <BootstrapNavbar className="navbar-custom" expand="lg" bg="bg-transparent" variant="light"/* bg={isLightMode ? "d" : "l"} variant={isLightMode ? "dark" : "light"}  */fixed="top">
+      <Container>
+        <BootstrapNavbar.Brand>
+          {import.meta.env.VITE_TEAM_NAME}
+        </BootstrapNavbar.Brand>
+        <BootstrapNavbar.Toggle aria-controls="basic-navbar-nav"/>
+        <BootstrapNavbar.Collapse id="basic-navbar-nav">
+            <Nav className="left-aligned">
+            {/* <button id="theme-toggle" className="btn btn-outline-secondary ml-auto" onClick={handleToggle}>        
+              {isLightMode ? '🌙' : '🔆' }
+            </button> */}
+            {pages}
+          </Nav> 
+        </BootstrapNavbar.Collapse>
+      </Container>
+    </BootstrapNavbar>
+  );
+}
diff --git a/src/components/NotFound.tsx b/src/components/NotFound.tsx
new file mode 100644
index 00000000..e98efdc1
--- /dev/null
+++ b/src/components/NotFound.tsx
@@ -0,0 +1,16 @@
+import { Link } from "react-router-dom";
+
+export function NotFound() {
+  return (
+    <div className="d-flex flex-column justify-content-center align-items-center">
+      <h1 className="not-found-title" style={{ fontSize: "100pt" }}>
+        404
+      </h1>
+      <div className="my-5">
+        <Link to="/" className="btn btn-secondary btn-lg">
+          Back to Home
+        </Link>
+      </div>
+    </div>
+  );
+}
diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx
new file mode 100644
index 00000000..b214463c
--- /dev/null
+++ b/src/components/Sidebar.tsx
@@ -0,0 +1,109 @@
+
+
+import { useEffect } from 'react';
+
+function SideItem({hesh, num}:{hesh: string; num: number}){
+    let link = "#" + hesh
+    let subdi = "subtitle" + num
+    return(
+        <div>   
+            <a href={link}>
+                <span id={subdi}>
+                    {hesh}
+                </span>
+            </a>
+        </div>   
+    )
+}
+
+
+
+/* LOading too slow...
+function Sidebar(){
+    const allWithClass = Array.from(
+        document.querySelectorAll('section')
+      );
+      console.log(allWithClass);
+    let content = [];
+    for(let idx in allWithClass){
+        const item = allWithClass[idx];
+        const id = item.id; 
+        console.log("idx: " + idx);
+        console.log("item: " + item); 
+        console.log("id: " + id);
+        content.push(<SideItem key={id} hesh={id}></SideItem>);
+    }
+    return (
+        <nav className="sidebar">
+            {content}
+        </nav>        
+    )
+    
+} */
+
+
+    function Sidebar({nums}:{nums: Array<string>}){
+
+      
+        useEffect(() => {
+          window.addEventListener('scroll', handleScroll);
+          return () => window.removeEventListener('scroll', handleScroll);
+        }, []);
+
+        const handleScroll = () => {
+            for(let idx in nums){
+                const item = nums[idx];
+                let ind = nums.findIndex((e) => e == item)
+                let subdi = "subtitle" + ind 
+                Highlight({el: document.getElementById(item)!}, {subtitle: document.getElementById(subdi)!});
+            }
+            
+            console.log("function HighlightCheck")
+        }
+      
+
+        console.log(nums)
+        let content = []; 
+        for(let idx in nums){
+            const item = nums[idx];
+            /* console.log("idx: " + idx);
+            console.log("item: " + item);  */
+            console.log("Type: " + typeof(document.getElementById(item)))
+            let ind = nums.findIndex((e) => e == item)
+            content.push(<SideItem key={item} hesh={item} num={ind}></SideItem>);
+        }
+        
+        return (
+            <nav className="sidebar">
+                    {content}
+            </nav>        
+        )
+        
+    }
+    
+
+
+      function Highlight({el}: {el: HTMLElement | null}, {subtitle}:{subtitle: HTMLElement | null}){
+        let TopDistance = 100; 
+        if (el != null && subtitle != null){
+            if (el.getBoundingClientRect().top < TopDistance + 1 && el.getBoundingClientRect().bottom > TopDistance){
+                subtitle.style.color = "#FFF6F2";
+                subtitle.style.backgroundColor = "#850F78";
+                subtitle.style.borderRadius = "15px";
+                subtitle.style.borderWidth = "15px"; 
+                subtitle.style.borderColor = "#850F78"; 
+/*                 console.log("subtitle: ",subtitle)
+                console.log("style: ", subtitle.style)
+                console.log("color: ",subtitle.style.color)
+                console.log("backcolor: ",subtitle.style.backgroundColor)    */     
+            }
+            else{
+                subtitle.style.color = "#850F78";
+                subtitle.style.backgroundColor = "";
+            }
+        }
+        
+      }
+    
+
+export default Sidebar;
\ No newline at end of file
diff --git a/src/components/Villagebuttons.tsx b/src/components/Villagebuttons.tsx
new file mode 100644
index 00000000..1133d06f
--- /dev/null
+++ b/src/components/Villagebuttons.tsx
@@ -0,0 +1,27 @@
+import { Link } from "react-router-dom";
+
+export function Villagebutton({ title, source, page }: { title: string; source: string; page:string}) {
+  return (
+    <Link className="btn village-style-button" role="button" to={page}>
+      <img src={source} className="d-block mx-auto mb-2" alt=""></img>
+      <h3>{title}</h3>
+    </Link>
+  )
+}
+
+export function Villbuttonrow(){
+  return(
+      <div className="row align-items-center bottom-buttons">
+        <Villagebutton page="/human-practices" source="https://static.igem.wiki/teams/5247/design/icons/humanpractices.png" title="Human Practice"></Villagebutton>
+        <Villagebutton page="/team" source="https://static.igem.wiki/teams/5247/design/icons/team.png" title="Team"></Villagebutton>
+        <Villagebutton page="/experiments" source="https://static.igem.wiki/teams/5247/design/icons/lab.png" title="Experiments"></Villagebutton>
+        <Villagebutton page="/description" source="https://static.igem.wiki/teams/5247/design/icons/dna.png" title="Description"></Villagebutton>
+        <Villagebutton page="/engineering" source="https://static.igem.wiki/teams/5247/design/icons/genetic-engineering.png" title="Engineering"></Villagebutton>
+        <Villagebutton page="/safety" source="https://static.igem.wiki/teams/5247/design/icons/safety.png" title="Safety"></Villagebutton>
+        <Villagebutton page="/results" source="https://static.igem.wiki/teams/5247/design/icons/results.png" title="Results"></Villagebutton>
+      
+      </div>  
+  )
+}
+
+export default Villbuttonrow; // Don’t forget to use export default!
\ No newline at end of file
diff --git a/src/main.tsx b/src/main.tsx
new file mode 100644
index 00000000..47cbbc68
--- /dev/null
+++ b/src/main.tsx
@@ -0,0 +1,12 @@
+import React from "react";
+import ReactDOM from "react-dom/client";
+import App from "./App/App";
+import { BrowserRouter } from "react-router-dom";
+
+ReactDOM.createRoot(document.getElementById("root")!).render(
+  <React.StrictMode>
+    <BrowserRouter basename={import.meta.env.BASE_URL}>
+      <App />
+    </BrowserRouter>
+  </React.StrictMode>,
+);
diff --git a/src/utils/getPathMapping.ts b/src/utils/getPathMapping.ts
new file mode 100644
index 00000000..0e0415a6
--- /dev/null
+++ b/src/utils/getPathMapping.ts
@@ -0,0 +1,36 @@
+import pages from "../pages.ts";
+
+export const getPathMapping = () => {
+  return pages.reduce<{
+    [key: string]: {
+      name: string | undefined;
+      title: string | undefined;
+      component: React.FC;
+      lead: string | undefined;
+      navlist: Array<string> | undefined;
+    };
+  }>((map, item) => {
+    if ("path" in item && item.path && item.component) {
+      map[item.path] = {
+        name: item.name,
+        title: item.title,
+        component: item.component,
+        lead: item.lead,
+        navlist: item.navlist, 
+      };
+    } else if ("folder" in item && item.folder) {
+      item.folder.forEach((page) => {
+        if (page.path && page.component) {
+          map[page.path] = {
+            name: page.name,
+            title: page.title,
+            component: page.component,
+            lead: page.lead,
+            navlist: page.navlist, 
+          };
+        }
+      });
+    }
+    return map;
+  }, {});
+};
diff --git a/src/utils/index.ts b/src/utils/index.ts
new file mode 100644
index 00000000..91290f52
--- /dev/null
+++ b/src/utils/index.ts
@@ -0,0 +1,2 @@
+export * from "./getPathMapping";
+export * from "./stringToSlug";
\ No newline at end of file
diff --git a/src/utils/stringToSlug.ts b/src/utils/stringToSlug.ts
new file mode 100644
index 00000000..3fb7b55e
--- /dev/null
+++ b/src/utils/stringToSlug.ts
@@ -0,0 +1,9 @@
+export function stringToSlug(string: string): string {
+  let slug = String(string).toLowerCase();
+  slug = slug.replace(/[^a-z0-9-]/g, "-");
+  slug = slug.replace(/-+/g, "-");
+  // remove dashes at start and end
+  const start = slug.search(/[^-]/); // find index of first non-dash
+  const end = slug.search(/-+$/); // find index of first end dash
+  return slug.substring(start, end === -1 ? undefined : end);
+}
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts
new file mode 100644
index 00000000..8b741f11
--- /dev/null
+++ b/src/vite-env.d.ts
@@ -0,0 +1,13 @@
+/// <reference types="vite/client" />
+
+interface ImportMetaEnv {
+    readonly VITE_TEAM_ID: string;
+    readonly VITE_TEAM_NAME: string;
+    readonly VITE_TEAM_YEAR: string;
+  }
+  
+  interface ImportMeta {
+    readonly env: ImportMetaEnv;
+  }
+  
+  
\ No newline at end of file
-- 
GitLab