Skip to content
Snippets Groups Projects
Commit 3d6b1fd1 authored by Kamile Liucija Vainiute's avatar Kamile Liucija Vainiute
Browse files

Merge branch 'feat/MISC-5-initial-page' into 'develop'

[#MISC-5] Initial page

See merge request websites/igem!3
parents 1ddb6005 4c523c64
No related branches found
No related tags found
No related merge requests found
Pipeline #2414 passed
Showing
with 998 additions and 0 deletions
/node_modules
/build
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
.idea/
.env
npm-debug.log*
yarn-debug.log*
yarn-error.log*
index.css
# node image
image: node:16.13.1-alpine
# cache dependencies
cache:
- key:
files:
- yarn.lock
paths:
- .yarn-cache/
- when: 'on_success'
.build:
stage: build
script:
- echo 'yarn-offline-mirror ".yarn-cache/"' >> .yarnrc
- echo 'yarn-offline-mirror-pruning true' >> .yarnrc
- yarn install --production --frozen-lockfile --no-progress
- chmod +x support/change-homepage.sh
- ./support/change-homepage.sh
- yarn build
- rm ./public -rf
- mv ./build ./public
- cp ./public/index.html ./public/404.html
artifacts:
paths:
- public
build-prod:
environment:
name: production
extends: .build
rules:
- if: '$CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH'
when: never
- if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH'
build-dev:
environment:
name: development
extends: .build
variables:
AWS_DEPLOY_PREFIX: $CI_PROJECT_NAME
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
when: never
- if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH'
lint:
stage: test
script:
- yarn
- yarn lint
pages:
stage: deploy
environment:
name: production
script:
- echo "Deploy to GitLab pages";
artifacts:
paths:
- public
rules:
- if: '$CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH'
when: never
- if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH'
pages-dev:
stage: deploy
environment:
name: development
image: 'registry.gitlab.com/gitlab-org/cloud-deploy/aws-base:latest'
script:
- aws s3 sync ./public s3://$AWS_FRONTENDS_BUCKET_DEV/$CI_PROJECT_NAME --delete
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
when: never
- if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH'
# iGEM Main Website # iGEM Main Website
## Usage
```bash
yarn start
```
{
"name": "my-app",
"version": "0.1.0",
"private": false,
"license": "UNLICENSED",
"homepage": "/",
"dependencies": {
"@igem/mdx-utils": "^0.2.1",
"@igem/ui-components": "^0.3.2",
"@mdx-js/loader": "^2.0.0-rc.2",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^12.1.2",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.4.0",
"@types/node": "^17.0.10",
"@types/react": "^17.0.38",
"@types/react-dom": "^17.0.11",
"autoprefixer": "^10.4.2",
"clsx": "^1.1.1",
"cross-env": "^7.0.3",
"delay-cli": "^1.1.0",
"lint-staged": "^12.3.1",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.5",
"postcss-cli": "^8.3.1",
"postcss-preset-env": "^6.7.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^6.2.1",
"react-scripts": "^4.0.3",
"tailwindcss": "^3.0.16",
"ts-standard": "^11.0.0",
"typescript": "^4.5.5"
},
"resolutions": {
"react-error-overlay": "6.0.9"
},
"scripts": {
"pre-compile": "node ./src/utils/FixMdxLoader.js",
"update": "yarn upgrade igem-components",
"start": "yarn pre-compile && run-p watch:css react-scripts:start",
"build": "yarn pre-compile && yarn build:css && yarn react-scripts:build",
"test": "react-scripts test --watchAll=false --passWithNoTests",
"eject": "react-scripts eject",
"build:css": "cross-env TAILWIND_MODE=build NODE_ENV=production postcss src/styles/tailwind.css -o src/styles/index.css",
"watch:css": "cross-env TAILWIND_MODE=watch NODE_ENV=development postcss src/styles/tailwind.css -o src/styles/index.css --watch",
"react-scripts:start": "react-scripts start",
"react-scripts:build": "react-scripts build",
"lint": "ts-standard",
"lint:fix": "ts-standard --fix",
"format": "prettier-standard",
"lint-staged": "lint-staged --allow-empty",
"prepare": "husky install"
},
"lint-staged": {
"*.{ts,tsx}": "ts-standard --fix",
"*": "prettier-standard --staged"
},
"eslintConfig": {
"extends": "react-app"
},
"ts-standard": {
"ignore": [
"public"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"husky": "^7.0.4",
"prettier-standard": "^16.4.1"
}
}
module.exports = {
plugins: [require('tailwindcss'), require('postcss-preset-env')]
}
public/favicon.ico

1.12 KiB

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<script
defer
src="https://unpkg.com/smoothscroll-polyfill@0.4.4/dist/smoothscroll.min.js"
></script>
<title>iGEM</title>
<meta name="title" content="iGEM" />
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website" />
<meta property="og:url" content="https://igem.org" />
<meta property="og:title" content="iGEM" />
<!-- Twitter -->
<meta property="twitter:url" content="https://igem.org" />
<meta property="twitter:title" content="iGEM" />
<!-- Matomo -->
<script type="text/javascript">
var _paq = (window._paq = window._paq || [])
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(['trackPageView'])
_paq.push(['enableLinkTracking'])
;(function () {
var u = 'https://matomo.igem.org/'
_paq.push(['setTrackerUrl', u + 'matomo.php'])
_paq.push(['setSiteId', '4'])
var d = document,
g = d.createElement('script'),
s = d.getElementsByTagName('script')[0]
g.type = 'text/javascript'
g.async = true
g.src = u + 'matomo.js'
s.parentNode.insertBefore(g, s)
})()
</script>
<!-- End Matomo Code -->
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
{
"short_name": "iGEM",
"name": "iGEM",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
# https://www.robotstxt.org/robotstxt.html
User-agent: *
export enum TimelineEvents {
JAMBOREE = 'jamboree',
REGIONAL = '5 regional jamborees',
WORLD = '1 world championship',
GIANT = 'giant jamboree',
VIRTUAL = 'virtual giant jamboree',
MEETUPS = '10 jamboree meetups',
GRAND = 'grand jamboree'
}
export enum TimelineLocations {
BOSTON = 'Boston, USA',
PARIS = 'Paris, France',
ONLINE = 'Online'
}
export interface TimelineItemInfo {
teams?: number
participants?: number
events: TimelineEvents[]
location: TimelineLocations
}
export const timeline: Record<string, TimelineItemInfo> = {
2022: {
events: [TimelineEvents.GRAND],
location: TimelineLocations.PARIS
},
2021: {
teams: 350,
participants: 7314,
events: [TimelineEvents.MEETUPS, TimelineEvents.VIRTUAL],
location: TimelineLocations.ONLINE
},
2020: {
teams: 249,
participants: 4800,
events: [TimelineEvents.VIRTUAL],
location: TimelineLocations.ONLINE
},
2019: {
teams: 353,
participants: 6375,
events: [TimelineEvents.GIANT],
location: TimelineLocations.BOSTON
},
2018: {
teams: 340,
participants: 5790,
events: [TimelineEvents.GIANT],
location: TimelineLocations.BOSTON
},
2017: {
teams: 310,
participants: 5386,
events: [TimelineEvents.GIANT],
location: TimelineLocations.BOSTON
},
2016: {
teams: 300,
participants: 4432,
events: [TimelineEvents.GIANT],
location: TimelineLocations.BOSTON
},
2015: {
teams: 280,
participants: 5018,
events: [TimelineEvents.GIANT],
location: TimelineLocations.BOSTON
},
2014: {
teams: 245,
participants: 4515,
events: [TimelineEvents.GIANT],
location: TimelineLocations.BOSTON
},
2013: {
teams: 215,
participants: 4027,
events: [TimelineEvents.REGIONAL, TimelineEvents.WORLD],
location: TimelineLocations.BOSTON
},
2012: {
teams: 190,
participants: 3696,
events: [TimelineEvents.REGIONAL, TimelineEvents.WORLD],
location: TimelineLocations.BOSTON
},
2011: {
teams: 165,
participants: 2586,
events: [TimelineEvents.REGIONAL, TimelineEvents.WORLD],
location: TimelineLocations.BOSTON
},
2010: {
teams: 128,
participants: 2327,
events: [TimelineEvents.JAMBOREE],
location: TimelineLocations.BOSTON
},
2009: {
teams: 113,
participants: 1840,
events: [TimelineEvents.JAMBOREE],
location: TimelineLocations.BOSTON
},
2008: {
teams: 88,
participants: 1248,
events: [TimelineEvents.JAMBOREE],
location: TimelineLocations.BOSTON
},
2007: {
teams: 54,
participants: 777,
events: [TimelineEvents.JAMBOREE],
location: TimelineLocations.BOSTON
},
2006: {
teams: 32,
participants: 723,
events: [TimelineEvents.JAMBOREE],
location: TimelineLocations.BOSTON
},
2005: {
teams: 13,
participants: 125,
events: [TimelineEvents.JAMBOREE],
location: TimelineLocations.BOSTON
},
2004: {
teams: 5,
participants: 31,
events: [TimelineEvents.JAMBOREE],
location: TimelineLocations.BOSTON
}
}
import { Button, Chevron } from '@igem/ui-components'
import React from 'react'
interface ButtonWithLinkProps {
link: string
title: string
className?: string
}
const ButtonWithLink = ({
title,
link,
className
}: ButtonWithLinkProps): JSX.Element => {
return (
<a href={link} target='_blank' rel='noreferrer'>
<Button
className={{
button: className,
title: 'text-xs font-semibold'
}}
>
<div className='flex items-center text-xxs font-bold'>
<Chevron className='transform -rotate-90 w-4 flex-shrink-0' />
{title}
</div>
</Button>
</a>
)
}
export default ButtonWithLink
import React, {
RefObject,
useCallback,
useEffect,
useRef,
useState
} from 'react'
import clsx from 'clsx'
import { Chevron } from '@igem/ui-components'
enum ScrollMode {
BOTH,
LEFT,
RIGHT,
NONE
}
interface HorizontalScrollProps {
className?: string
children: JSX.Element
scrollRef: RefObject<HTMLDivElement>
showLast?: boolean
}
const HorizontalScroll = (props: HorizontalScrollProps): JSX.Element => {
const { children, className, scrollRef, showLast } = props
const innerRef = useRef<HTMLDivElement>(null)
const coverRef = useRef<HTMLDivElement>(null)
const ref = scrollRef
const [scrollMode, setScrollMode] = useState<ScrollMode>(ScrollMode.NONE)
const recalculateOverlay = useCallback((): void => {
const innerWidth = innerRef.current?.clientWidth
const coverWidth = coverRef.current?.clientWidth
const scrollLeft = ref.current?.scrollLeft
const offsetWidth = ref.current?.offsetWidth
const scrollWidth = ref.current?.scrollWidth
if (
innerWidth !== undefined &&
coverWidth !== undefined &&
innerWidth <= coverWidth
) {
setScrollMode(ScrollMode.NONE)
} else {
if (scrollLeft !== undefined && offsetWidth !== undefined) {
if (scrollLeft + offsetWidth === scrollWidth) {
setScrollMode(ScrollMode.RIGHT)
} else if (scrollLeft === 0) {
setScrollMode(ScrollMode.LEFT)
} else {
setScrollMode(ScrollMode.BOTH)
}
} else {
setScrollMode(ScrollMode.NONE)
}
}
}, [innerRef, coverRef, ref])
useEffect(() => {
recalculateOverlay()
}, [
innerRef.current?.clientWidth,
coverRef.current?.clientWidth,
recalculateOverlay
])
window.addEventListener('resize', () => recalculateOverlay())
const handleScrollClick = (toTheRight: boolean): void => {
if (ref.current?.scrollLeft !== undefined) {
ref.current?.scrollBy({
left: toTheRight ? 300 : -300,
behavior: 'smooth'
})
}
}
useEffect(() => {
if (showLast !== undefined && showLast) {
ref.current?.scrollTo({
left: ref.current?.scrollWidth - ref.current?.clientWidth,
behavior: 'auto'
})
}
}, [ref.current?.scrollWidth, children, showLast, ref])
const getGradientClass = (): string => {
switch (scrollMode) {
case ScrollMode.BOTH:
return 'cover-gradient'
case ScrollMode.LEFT:
return 'cover-gradient-left'
case ScrollMode.RIGHT:
return 'cover-gradient-right'
case ScrollMode.NONE:
return ''
}
}
return (
<div className='relative'>
<div
className='overflow-y-scroll no-scrollbar'
ref={ref}
onScroll={recalculateOverlay}
>
<div className={className} ref={innerRef}>
{children}
</div>
</div>
<div
className={clsx(
'w-full absolute inset-0 pointer-events-none flex items-center justify-between z-30 h-full',
getGradientClass()
)}
ref={coverRef}
>
{scrollMode !== ScrollMode.NONE && (
<div className='flex relative w-full h-full items-center'>
{(scrollMode === ScrollMode.BOTH ||
scrollMode === ScrollMode.RIGHT) && (
<button
onClick={() => handleScrollClick(false)}
className='border absolute border-white w-10 h-10 rounded-full flex items-center justify-center mr-2 z-50 pointer-events-auto cursor-pointer'
>
<Chevron className='transform rotate-90' />
</button>
)}
{(scrollMode === ScrollMode.BOTH ||
scrollMode === ScrollMode.LEFT) && (
<button
onClick={() => handleScrollClick(true)}
className='border absolute -right-0 border-white w-10 h-10 rounded-full flex items-center justify-center mr-2 z-50 pointer-events-auto cursor-pointer'
>
<Chevron className='transform -rotate-90' />
</button>
)}
</div>
)}
</div>
</div>
)
}
export default HorizontalScroll
import { Chevron, ContentBox } from '@igem/ui-components'
import React from 'react'
import clsx from 'clsx'
interface InfoBoxProps {
className?: string
subTitle: string
title: string
shouldScrollToSection?: boolean
children?: JSX.Element
}
const InfoBox = ({
className,
subTitle,
title,
shouldScrollToSection = false,
children
}: InfoBoxProps): JSX.Element => {
const onMoreInfoClick = (): void => {
const element = document.getElementById(`link-group-${title.toLowerCase()}`)
if (element !== undefined && element !== null) {
const top =
element.getBoundingClientRect().top +
(window.top?.pageYOffset ?? 0) -
200
window.scrollTo({ top, behavior: 'smooth' })
}
}
return (
<div
className={clsx(
className,
'w-full',
shouldScrollToSection && 'cursor-pointer'
)}
onClick={() => shouldScrollToSection && onMoreInfoClick()}
>
<ContentBox className={clsx('px-6 py-4 h-full w-full')}>
<div className='flex flex-col h-full'>
<p className='text-xs text-gray-700 font-medium text-opacity-70'>
{subTitle}
</p>
<p className='font-bold text-lg'>{title}</p>
<div className='text-xs py-1'>{children}</div>
{shouldScrollToSection && (
<div className='mx-auto mt-auto flex h-full items-end'>
<button
className='flex items-center text-green-500 uppercase font-medium text-xxs tracking-widest '
onClick={onMoreInfoClick}
>
<p>More info</p>
<Chevron />
</button>
</div>
)}
</div>
</ContentBox>
</div>
)
}
export default InfoBox
import {
Divider,
LinkCard,
ThreeColumns,
FourColumns,
PageContent,
Button,
Chevron,
ImageSize
} from '@igem/ui-components'
import React from 'react'
import clsx from 'clsx'
interface LinksGroupProps {
isGray?: boolean
title: string
subTitle: string
description: string
titleLink?: {
link: string
title: string
}
links: Array<{
image: string
linkTitle: string
url: string
}>
}
const LinksGroup = ({
isGray = false,
title,
titleLink,
subTitle,
description,
links
}: LinksGroupProps): JSX.Element => {
const getLinkCards = (): JSX.Element => (
<>
{links.map(({ image, linkTitle, url }) => (
<LinkCard
key={linkTitle}
image={image}
// @ts-expect-error
size={ImageSize.SMALL}
title={linkTitle}
url={url}
/>
))}
</>
)
return (
<div
className={clsx(isGray && 'bg-gray-500', 'sm:py-5 sm:px-16 p-3')}
id={`link-group-${title.toLowerCase()}`}
>
<PageContent>
<>
<div className='flex items-center uppercase tracking-widest text-sm font-semibold text-gray-700'>
{title}
<Divider className='ml-2' />
</div>
<span className='text-lg font-bold block pb-2 py-5 flex items-center sm:flex-row flex-col'>
{subTitle}
{titleLink !== undefined && (
<a
href={titleLink.link}
className='sm:ml-8'
target='_blank'
rel='noreferrer'
>
<Button
className={{
button: 'py-1 sm:my-0 my-2',
title: 'text-xs font-semibold'
}}
>
<div className='flex items-center text-xxs font-bold'>
<Chevron className='transform -rotate-90 w-4' />{' '}
<p>{titleLink.title}</p>
</div>
</Button>
</a>
)}
</span>
<span className='text-sm'>{description}</span>
{links.length === 3 && (
<ThreeColumns className='mt-5 gap-3'>{getLinkCards()}</ThreeColumns>
)}
{links.length === 4 && (
<FourColumns className='mt-5 gap-3'>{getLinkCards()}</FourColumns>
)}
</>
</PageContent>
</div>
)
}
export default LinksGroup
import React from 'react'
import clsx from 'clsx'
interface NumberWithDescriptionProps {
number: number
description: string
className?: string
}
const NumberWithDescription = ({
number,
description,
className
}: NumberWithDescriptionProps): JSX.Element => {
const spaceEveryThreeDigitsRegex = /\B(?=(\d{3})+(?!\d))/g
return (
<div className={clsx('flex flex-col items-center py-3', className)}>
<p className='text-2xl font-bold'>
{number.toString().replace(spaceEveryThreeDigitsRegex, ' ')}
</p>
<p className='uppercase text-xxs font-medium tracking-wider'>
{description}
</p>
</div>
)
}
export default NumberWithDescription
import { Divider } from '@igem/ui-components'
import React, { useRef } from 'react'
import HorizontalScroll from './HorizontalScroll'
export interface TimelineProps {
items: TimelineItem[]
scrollToLeftOnLoad?: boolean
}
export interface TimelineItem {
header?: string
children: JSX.Element
}
const Timeline = ({
items,
scrollToLeftOnLoad = false
}: TimelineProps): JSX.Element => {
const scrollRef = useRef<HTMLDivElement>(null)
return (
<HorizontalScroll
scrollRef={scrollRef}
className='w-max'
showLast={scrollToLeftOnLoad}
>
<div
className='flex w-max py-16 sm:px-24 px-12 relative items-stretch'
ref={scrollRef}
>
<Divider className='absolute' />
{items.map((item, index) => (
<div className='w-full' key={`${item.header ?? ''}-${index}`}>
<div className='flex justify-center relative items-center'>
<div className='rounded-full border border-gray-600 px-3 py-0.5 text-xs font-bold w-max absolute bg-gray-500'>
{item.header}
</div>
</div>
<div className='pt-10'>{item.children}</div>
</div>
))}
</div>
</HorizontalScroll>
)
}
export default Timeline
import React, { useMemo } from 'react'
import { Chevron, Divider, Pin } from '@igem/ui-components'
import ButtonWithLink from './ButtonWithLink'
import Timeline, { TimelineItem } from './Timeline'
import { timeline, TimelineItemInfo } from '../assets/data/timeline'
const TimelineWrapper = (): JSX.Element => {
const renderElement = (info: TimelineItemInfo): JSX.Element => (
<div>
<div className='grid grid-cols-2 text-xs gap-x-3 items-center gap-y-1'>
<p className='text-right font-bold'>{info.teams ?? '?'}</p>
<p>teams</p>
<p className='text-right font-bold'>{info.participants ?? '?'}</p>
<p>participants</p>
{info.events.map(event => (
<React.Fragment key={`${event}-${info.participants ?? ''}`}>
<div className='flex justify-end'>
<Chevron className='w-4 transform -rotate-90' />
</div>
<p className='uppercase tracking-wider'>{event}</p>
</React.Fragment>
))}
<div className='flex justify-end'>
<Pin className='w-4' />
</div>
<p>{info.location}</p>
</div>
</div>
)
const items: TimelineItem[] = useMemo(
() =>
Object.entries(timeline).map(([year, info]) => {
return { header: year, children: renderElement(info) }
}),
[]
)
return (
<div className='w-full top-10' id='link-group-competition'>
<div className=' max-w-screen-lg mx-auto px-16'>
<div className='flex items-center uppercase tracking-widest text-sm font-semibold text-gray-700'>
Competition
<Divider className='ml-2' />
</div>
<div className='flex items-center gap-x-10 sm:flex-row flex-col gap-y-2 sm:gap-y-0'>
<p className='font-bold text-lg'>19 Years of the iGEM Competition!</p>
<ButtonWithLink
link='https://igem.org/timeline'
title='TIMELINE'
className='py-1 px-5'
/>
<ButtonWithLink
link='https://competition.igem.org'
title='competition.igem.org'
className='py-1 px-5'
/>
</div>
</div>
<Timeline items={items} scrollToLeftOnLoad />
</div>
)
}
export default TimelineWrapper
import {
Footer,
LINK_VALUE,
NavBar,
PageContent,
components
} from '@igem/ui-components'
import { MdxRouter } from '@igem/mdx-utils'
/* eslint-disable import/no-webpack-loader-syntax */
import Banner from '!@mdx-js/loader!content/banner.mdx'
import WhatIsIgem from '!@mdx-js/loader!content/what-is-igem.mdx'
import PreviousPages from '!@mdx-js/loader!content/previousPages.mdx'
import News from '!@mdx-js/loader!content/news.mdx'
import Pages from '!@mdx-js/loader!content/pages.mdx'
import { Route } from 'react-router-dom'
import TimelineWrapper from '../../components/TimelineWrapper'
const RedirectToOldIgem = (): JSX.Element => {
const pathname = window.location.pathname
window.location.href = `https://old.igem.org${pathname}`
return <></>
}
function App (): JSX.Element {
return (
<div className='app'>
<NavBar page={LINK_VALUE.IGEM} showTemporaryBanner />
<div className='w-screen bg-gray-500 flex items-center py-16'>
<div className='max-w-screen-lg mx-auto w-full flex items-center px-12 sm:flex-row flex-col'>
<Banner />
</div>
</div>
<MdxRouter
contentStructure={[]}
otherRoutes={<Route path='*' element={<RedirectToOldIgem />} />}
components={components}
pageClassName='w-full p-0'
homepage={
<>
<PageContent>
<>
<PreviousPages />
<WhatIsIgem />
</>
</PageContent>
<TimelineWrapper />
<PageContent>
<News />
</PageContent>
<Pages />
</>
}
/>
<Footer />
</div>
)
}
export default App
import { IgemLogo, Bricks } from '@igem/ui-components'
<IgemLogo className='h-36 w-36 mr-12 flex-shrink-0' />
<div>
<span className='flex items-end pb-2'>
<Bricks className='w-12 h-9 mr-5' />
<h2 className='font-bold text-lg'>New igem.org is coming soon!</h2>
</span>
<div className='banner-text'>
The iGEM Foundation is an independent, non-profit organization dedicated to
the advancement of synthetic biology, education and competition, and the
development of an open community and collaboration. This is done by
fostering an open, cooperative community and friendly competition. While we
build up our new website, you can explore our old website: >
[old.igem.org](https://old.igem.org)
</div>
</div>
import { NewsBox, ThreeColumns, TwoColumns, Image } from '@igem/ui-components'
[<Image
image='https://static.igem.io/common/images/banner-dark.png'
alt='2022 Grand Jamboree Banner'
imageSize='no_size'
className='my-5'
/>](https://jamboree.igem.org)
<TwoColumns className='py-5'>
<Image
image='https://static.igem.io/common/images/igem_from_above.jpg'
alt='iGEM from Above'
imageSize='no_size'
/>
<Image
image='https://static.igem.io/common/images/audience.jpg'
alt='iGEM Audience'
imageSize='no_size'
/>
</TwoColumns>
<ThreeColumns>
<div>
<NewsBox
alt='Insights from iGEM’s History'
date='2019-09-18'
image='https://static.igem.io/common/images/blog-igem-history.jpg'
readMoreLink='https://blog.igem.org/blog/2019/9/18/what-is-igem-part-3'
title='Insights from iGEM’s History'
readMoreLinkText='read more on the igem blog'
/>
</div>
<div>
<NewsBox
alt='A community, a field, an approach: iGEM’s new purpose'
date='2021-07-02'
image='https://static.igem.io/common/images/blog-igem-purpose.png'
readMoreLink='https://blog.igem.org/blog/2021/6/2/a-community-a-field-an-approach-igems-new-purpose'
title='A community, a field, an approach: iGEM’s new purpose'
readMoreLinkText='read more on the igem blog'
/>
</div>
<div>
<NewsBox
alt='Local People Solving Local Problems: Highlights from iGEM 2020'
date='2019-08-21'
image='https://static.igem.io/common/images/blog-local-problems.jpg'
readMoreLink='https://blog.igem.org/blog/2019/8/21/what-is-igem-part-2'
title='Local People Solving Local Problems: Highlights from iGEM 2020'
readMoreLinkText='read more on the igem blog'
className={{ title: 'font-bold' }}
/>
</div>
</ThreeColumns>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment