- added drone files

- added docker files
- added ansible deployment files
This commit is contained in:
oonyeje 2023-10-09 07:45:57 -04:00
parent 01753b87b2
commit 86f4da9749
14 changed files with 509 additions and 325 deletions

74
.drone.yml Executable file
View File

@ -0,0 +1,74 @@
kind: pipeline
type: docker
name: build
steps:
- name: build
image: timbru31/node-alpine-git:18
commands:
- yarn
# - yarn build
- name: push-image
image: plugins/docker:latest
settings:
registry: gitea.bsidesolutions.net
repo: gitea.bsidesolutions.net/oonyeje/oonyeje-portfolio
username:
from_secret: DOCKER_USERNAME
password:
from_secret: DOCKER_PASSWORD
# email:
# from_secret: DOCKER_EMAIL
tags:
- latest
dockerfile: ./Dockerfile
context: ./
# - name: deploy-staging
# image: plugins/ansible:latest
# settings:
# playbook: ansible/playbook.staging.yml
# galaxy: ansible/requirements.yml
# inventory: ansible/inventory.yml
# become_user: bside
# user: bside
# verbose: 4
# become: true
# list_tasks: true
# list_hosts: true
# private_key:
# from_secret: STAGING_SERVER_PRIVATE_KEY
# trigger:
# branch:
# - master
# - prod
# - qa
# - feature/*
# event:
# - push
# - pull_request
---
kind: pipeline
type: exec
name: staging-deploy
platform:
os: linux
arch: amd64
steps:
- name: ansible-deploy
commands:
- ansible --version
- ansible-galaxy install --force --role-file ansible/requirements.yml -vvvv
- ansible-playbook --inventory ansible/inventory.yml --list-hosts ansible/playbook.staging.yml
# trigger:
# branch:
# - master
# - prod
# - qa
# - feature/*
# event:
# - push
# - pull_request

72
.gitignore vendored Normal file → Executable file
View File

@ -1,36 +1,36 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
.env
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
.env
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

25
Dockerfile Normal file
View File

@ -0,0 +1,25 @@
FROM node:18.8-alpine as base
FROM base as builder
WORKDIR /home/node/app
COPY package*.json ./
COPY . .
RUN yarn install
# RUN yarn build
FROM base as runtime
# ENV NODE_ENV=production
WORKDIR /home/node/app
COPY package*.json ./
# RUN yarn install --production
# COPY --from=builder /home/node/app/dist ./dist
# COPY --from=builder /home/node/app/build ./build
EXPOSE 3000
CMD ["yarn", "dev", '-p', '3000']

2
ansible/inventory.yml Executable file
View File

@ -0,0 +1,2 @@
deployment_servers:
hosts: localhost

60
ansible/playbook.staging.yml Executable file
View File

@ -0,0 +1,60 @@
- name: deploy docker stack
hosts: localhost
tasks:
- name: Tear down existing services
community.docker.docker_compose:
project_src: ../
state: absent
- name: Create and start services
community.docker.docker_compose:
project_src: ../
register: output
- name: Show results
ansible.builtin.debug:
var: output
- name: Run `docker-compose up` again
community.docker.docker_compose:
project_src: ../
build: false
register: output
# - name: Show results
# ansible.builtin.debug:
# var: output
# - ansible.builtin.assert:
# that: not output.changed
# - name: Stop all services
# community.docker.docker_compose:
# project_src: ../
# build: false
# stopped: true
# register: output
- name: Show results
ansible.builtin.debug:
var: output
- name: Verify that app and db services are running
ansible.builtin.assert:
that:
- "not output.services.app.oonyeje-portfolio_app_1.state.running"
# - name: Restart services
# community.docker.docker_compose:
# project_src: ../
# build: false
# restarted: true
# register: output
- name: Show results
ansible.builtin.debug:
var: output
# - name: Verify that app and db services are running
# ansible.builtin.assert:
# that:
# - "not output.services.app.oonyeje-portfolio_app_1.state.running"

5
ansible/requirements.yml Executable file
View File

@ -0,0 +1,5 @@
collections:
# Install a collection from Ansible Galaxy.
- name: community.docker
version: ">=3.4.8"
source: https://galaxy.ansible.com

102
components/content/carousel/index.tsx Normal file → Executable file
View File

@ -1,52 +1,52 @@
import React, { useState } from "react";
import Image from "next/image";
import { StaticImport } from "next/dist/shared/lib/get-img-props";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faChevronCircleLeft, faChevronCircleRight } from "@fortawesome/free-solid-svg-icons";
import IframeResizer from "iframe-resizer-react";
interface ContentCarouselProps {
data: Array<{
title: String,
heroImgSrc: string | StaticImport,
description?: string,
prototypeIframeURL?: string
}>
}
const ContentCarousel = ({
data = []
}: ContentCarouselProps) => {
const [pageLength, setPageLength] = useState(data.length)
const [currentPageIdx, setCurrentPageIdx] = useState(0);
const portfolioData = data[currentPageIdx];
return (
<div className="flex flex-row justify-between">
{(currentPageIdx > 0) && <span className="cursor-pointer" onClick={() => setCurrentPageIdx(currentPageIdx - 1)}><FontAwesomeIcon width={50} height={50} icon={faChevronCircleLeft} className="fas fa-chevron-circle-left" style={{ color: "white" }} /></span>}
<div style={{width: '-webkit-fill-available'}} className={`p-4 ${portfolioData.prototypeIframeURL ? '' : 'px-10'} flex flex-col`}>
<div className=" w-fit pb-1 mb-8 border-b-2 border-white">{portfolioData.title}</div>
{portfolioData.heroImgSrc && <div className="mb-8"><Image src={portfolioData.heroImgSrc} alt=""/></div>}
<div>{portfolioData.description}</div>
{portfolioData.prototypeIframeURL && <div style={{height: 1000, minHeight: '100%'}}>
{<IframeResizer
src={portfolioData.prototypeIframeURL}
log
style={{
width: "100%",
minWidth: "100%",
minHeight: '100%',
height: '1px'
}}
frameBorder= "0"
/>}
</div>}
</div>
{(currentPageIdx < pageLength - 1) && <span className="cursor-pointer" onClick={() => setCurrentPageIdx(currentPageIdx + 1)}><FontAwesomeIcon width={25} height={50} icon={faChevronCircleRight} className="fas fa-chevron-circle-right" style={{ color: "white" }} /></span>}
</div>
);
};
import React, { useState } from "react";
import Image from "next/image";
import { StaticImport } from "next/dist/shared/lib/get-img-props";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faChevronCircleLeft, faChevronCircleRight } from "@fortawesome/free-solid-svg-icons";
import IframeResizer from "iframe-resizer-react";
interface ContentCarouselProps {
data: Array<{
title: String,
heroImgSrc: string | StaticImport,
description?: string,
prototypeIframeURL?: string
}>
}
const ContentCarousel = ({
data = []
}: ContentCarouselProps) => {
const [pageLength, setPageLength] = useState(data.length)
const [currentPageIdx, setCurrentPageIdx] = useState(0);
const portfolioData = data[currentPageIdx];
return (
<div className="flex flex-row justify-between">
{(currentPageIdx > 0) && <span className="cursor-pointer" onClick={() => setCurrentPageIdx(currentPageIdx - 1)}><FontAwesomeIcon width={50} height={50} icon={faChevronCircleLeft} className="fas fa-chevron-circle-left" style={{ color: "white" }} /></span>}
<div style={{width: '-webkit-fill-available'}} className={`p-4 ${portfolioData.prototypeIframeURL ? '' : 'px-10'} flex flex-col`}>
<div className=" w-fit pb-1 mb-8 border-b-2 border-white">{portfolioData.title}</div>
{portfolioData.heroImgSrc && <div className="mb-8"><Image src={portfolioData.heroImgSrc} alt=""/></div>}
<div>{portfolioData.description}</div>
{portfolioData.prototypeIframeURL && <div style={{height: 1000, minHeight: '100%'}}>
{<IframeResizer
src={portfolioData.prototypeIframeURL}
log
style={{
width: "100%",
minWidth: "100%",
minHeight: '100%',
height: '1px'
}}
frameBorder= "0"
/>}
</div>}
</div>
{(currentPageIdx < pageLength - 1) && <span className="cursor-pointer" onClick={() => setCurrentPageIdx(currentPageIdx + 1)}><FontAwesomeIcon width={25} height={50} icon={faChevronCircleRight} className="fas fa-chevron-circle-right" style={{ color: "white" }} /></span>}
</div>
);
};
export default ContentCarousel;

52
components/content/index.tsx Normal file → Executable file
View File

@ -1,27 +1,27 @@
import React, { ReactNode } from "react";
import Image from "next/image";
import { StaticImport } from "next/dist/shared/lib/get-img-props";
interface ContentProps {
title: string,
heroImgSrc: string | StaticImport,
description?: string,
innerChildren?: ReactNode
}
const Content = ({
title = '',
heroImgSrc,
description = '',
innerChildren = <></>
}: ContentProps) => {
return (
<div className="p-4 px-10 flex flex-col">
<div className=" w-fit pb-1 mb-8 border-b-2 border-white">{title}</div>
{heroImgSrc && <div className="mb-8 h-1/2"><Image src={heroImgSrc} alt=""/></div>}
<div>{description}</div>
<div>{innerChildren}</div>
</div>
);
};
import React, { ReactNode } from "react";
import Image from "next/image";
import { StaticImport } from "next/dist/shared/lib/get-img-props";
interface ContentProps {
title: string,
heroImgSrc: string | StaticImport,
description?: string,
innerChildren?: ReactNode
}
const Content = ({
title = '',
heroImgSrc,
description = '',
innerChildren = <></>
}: ContentProps) => {
return (
<div className="p-4 px-10 flex flex-col">
<div className=" w-fit pb-1 mb-8 border-b-2 border-white">{title}</div>
{heroImgSrc && <div className="mb-8 h-1/2"><Image src={heroImgSrc} alt=""/></div>}
<div>{description}</div>
<div>{innerChildren}</div>
</div>
);
};
export default Content;

18
docker-compose.yaml Executable file
View File

@ -0,0 +1,18 @@
version: '3'
name: oonyeje-portfolio
services:
app:
image: node:18.8-alpine
build:
context: ./
dockerfile: Dockerfile
ports:
- "3000:3000"
volumes:
- .:/home/node/app
- ./node_modules:/home/node/app/node_modules
working_dir: /home/node/app/
command: sh -c "yarn install && yarn dev"
env_file:
- .env.local

92
lib/content.ts Normal file → Executable file
View File

@ -1,47 +1,47 @@
const contentValues = {
intro: {
name: 'INTRO',
description: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Rhoncus urna neque viverra justo nec ultrices dui. Quis risus sed vulputate odio ut. Praesent semper feugiat nibh sed pulvinar proin gravida hendrerit. Mi ipsum faucibus vitae aliquet nec. Adipiscing elit ut aliquam purus sit amet luctus. Morbi tempus iaculis urna id. Vitae congue mauris rhoncus aenean vel elit scelerisque. Cursus turpis massa tincidunt dui. Vulputate sapien nec sagittis aliquam malesuada. Lectus proin nibh nisl condimentum id venenatis a condimentum. Est lorem ipsum dolor sit amet consectetur. Blandit aliquam etiam erat velit.
Vel turpis nunc eget lorem dolor. Volutpat commodo sed egestas egestas fringilla phasellus faucibus. Auctor eu augue ut lectus arcu bibendum. Suscipit tellus mauris a diam maecenas sed enim ut sem. Vivamus at augue eget arcu dictum varius. Vitae et leo duis ut diam quam nulla porttitor. Enim eu turpis egestas pretium. A diam sollicitudin tempor id eu nisl nunc mi. Venenatis cras sed felis eget. Sagittis eu volutpat odio facilisis mauris sit amet massa vitae. Tempor orci eu lobortis elementum nibh tellus molestie. Semper auctor neque vitae tempus quam pellentesque nec nam. Tempor commodo ullamcorper a lacus vestibulum sed arcu non odio. Tristique nulla aliquet enim tortor. Volutpat commodo sed egestas egestas fringilla phasellus. Enim ut sem viverra aliquet eget sit amet tellus cras. Cras semper auctor neque vitae tempus quam.
In nibh mauris cursus mattis molestie. Vivamus arcu felis bibendum ut tristique et egestas quis ipsum. Dolor purus non enim praesent elementum facilisis leo. Enim ut tellus elementum sagittis. Sed libero enim sed faucibus turpis in. Ac turpis egestas maecenas pharetra convallis posuere morbi leo. Nibh sit amet commodo nulla facilisi nullam vehicula ipsum. Arcu dictum varius duis at consectetur lorem donec massa. Tellus cras adipiscing enim eu turpis egestas pretium. Phasellus faucibus scelerisque eleifend donec pretium vulputate. Sollicitudin nibh sit amet commodo nulla facilisi nullam. Bibendum enim facilisis gravida neque convallis. Quis viverra nibh cras pulvinar mattis nunc. Quam nulla porttitor massa id neque aliquam vestibulum. Pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies. Faucibus turpis in eu mi bibendum neque. Curabitur gravida arcu ac tortor. Purus sit amet luctus venenatis lectus magna fringilla. Tincidunt vitae semper quis lectus nulla at volutpat. Vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis.
Mi quis hendrerit dolor magna eget est lorem. Ut lectus arcu bibendum at. Elit at imperdiet dui accumsan sit amet nulla. Tristique et egestas quis ipsum suspendisse ultrices. A arcu cursus vitae congue. Dolor sed viverra ipsum nunc aliquet bibendum enim facilisis. Nec dui nunc mattis enim ut tellus elementum sagittis. Posuere ac ut consequat semper. Eu non diam phasellus vestibulum lorem sed risus. Arcu ac tortor dignissim convallis aenean et tortor at. Velit scelerisque in dictum non consectetur a erat. Condimentum mattis pellentesque id nibh. Quam quisque id diam vel quam. At lectus urna duis convallis convallis tellus id interdum velit. Aliquam vestibulum morbi blandit cursus risus at ultrices. Ullamcorper velit sed ullamcorper morbi tincidunt ornare massa. Mattis molestie a iaculis at erat pellentesque adipiscing. In nulla posuere sollicitudin aliquam ultrices sagittis. Vel elit scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique.
Amet consectetur adipiscing elit ut aliquam purus sit amet luctus. Et ultrices neque ornare aenean euismod elementum. Orci sagittis eu volutpat odio. Vitae aliquet nec ullamcorper sit amet risus nullam. A scelerisque purus semper eget duis at. Risus viverra adipiscing at in tellus integer feugiat scelerisque varius. Quis auctor elit sed vulputate. Enim ut sem viverra aliquet eget sit. Nulla aliquet porttitor lacus luctus. Mi sit amet mauris commodo quis imperdiet. Ac felis donec et odio pellentesque diam volutpat commodo sed. Lacus viverra vitae congue eu consequat ac felis donec et. Facilisis magna etiam tempor orci eu lobortis elementum nibh tellus. Velit egestas dui id ornare arcu.`
},
work: {
name: 'WORK',
description: ``
},
about: {
name: 'ABOUT',
description: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Rhoncus urna neque viverra justo nec ultrices dui. Quis risus sed vulputate odio ut. Praesent semper feugiat nibh sed pulvinar proin gravida hendrerit. Mi ipsum faucibus vitae aliquet nec. Adipiscing elit ut aliquam purus sit amet luctus. Morbi tempus iaculis urna id. Vitae congue mauris rhoncus aenean vel elit scelerisque. Cursus turpis massa tincidunt dui. Vulputate sapien nec sagittis aliquam malesuada. Lectus proin nibh nisl condimentum id venenatis a condimentum. Est lorem ipsum dolor sit amet consectetur. Blandit aliquam etiam erat velit.
Vel turpis nunc eget lorem dolor. Volutpat commodo sed egestas egestas fringilla phasellus faucibus. Auctor eu augue ut lectus arcu bibendum. Suscipit tellus mauris a diam maecenas sed enim ut sem. Vivamus at augue eget arcu dictum varius. Vitae et leo duis ut diam quam nulla porttitor. Enim eu turpis egestas pretium. A diam sollicitudin tempor id eu nisl nunc mi. Venenatis cras sed felis eget. Sagittis eu volutpat odio facilisis mauris sit amet massa vitae. Tempor orci eu lobortis elementum nibh tellus molestie. Semper auctor neque vitae tempus quam pellentesque nec nam. Tempor commodo ullamcorper a lacus vestibulum sed arcu non odio. Tristique nulla aliquet enim tortor. Volutpat commodo sed egestas egestas fringilla phasellus. Enim ut sem viverra aliquet eget sit amet tellus cras. Cras semper auctor neque vitae tempus quam.
In nibh mauris cursus mattis molestie. Vivamus arcu felis bibendum ut tristique et egestas quis ipsum. Dolor purus non enim praesent elementum facilisis leo. Enim ut tellus elementum sagittis. Sed libero enim sed faucibus turpis in. Ac turpis egestas maecenas pharetra convallis posuere morbi leo. Nibh sit amet commodo nulla facilisi nullam vehicula ipsum. Arcu dictum varius duis at consectetur lorem donec massa. Tellus cras adipiscing enim eu turpis egestas pretium. Phasellus faucibus scelerisque eleifend donec pretium vulputate. Sollicitudin nibh sit amet commodo nulla facilisi nullam. Bibendum enim facilisis gravida neque convallis. Quis viverra nibh cras pulvinar mattis nunc. Quam nulla porttitor massa id neque aliquam vestibulum. Pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies. Faucibus turpis in eu mi bibendum neque. Curabitur gravida arcu ac tortor. Purus sit amet luctus venenatis lectus magna fringilla. Tincidunt vitae semper quis lectus nulla at volutpat. Vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis.
Mi quis hendrerit dolor magna eget est lorem. Ut lectus arcu bibendum at. Elit at imperdiet dui accumsan sit amet nulla. Tristique et egestas quis ipsum suspendisse ultrices. A arcu cursus vitae congue. Dolor sed viverra ipsum nunc aliquet bibendum enim facilisis. Nec dui nunc mattis enim ut tellus elementum sagittis. Posuere ac ut consequat semper. Eu non diam phasellus vestibulum lorem sed risus. Arcu ac tortor dignissim convallis aenean et tortor at. Velit scelerisque in dictum non consectetur a erat. Condimentum mattis pellentesque id nibh. Quam quisque id diam vel quam. At lectus urna duis convallis convallis tellus id interdum velit. Aliquam vestibulum morbi blandit cursus risus at ultrices. Ullamcorper velit sed ullamcorper morbi tincidunt ornare massa. Mattis molestie a iaculis at erat pellentesque adipiscing. In nulla posuere sollicitudin aliquam ultrices sagittis. Vel elit scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique.
Amet consectetur adipiscing elit ut aliquam purus sit amet luctus. Et ultrices neque ornare aenean euismod elementum. Orci sagittis eu volutpat odio. Vitae aliquet nec ullamcorper sit amet risus nullam. A scelerisque purus semper eget duis at. Risus viverra adipiscing at in tellus integer feugiat scelerisque varius. Quis auctor elit sed vulputate. Enim ut sem viverra aliquet eget sit. Nulla aliquet porttitor lacus luctus. Mi sit amet mauris commodo quis imperdiet. Ac felis donec et odio pellentesque diam volutpat commodo sed. Lacus viverra vitae congue eu consequat ac felis donec et. Facilisis magna etiam tempor orci eu lobortis elementum nibh tellus. Velit egestas dui id ornare arcu.`
},
contact: {
name: 'CONTACT',
description: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Rhoncus urna neque viverra justo nec ultrices dui. Quis risus sed vulputate odio ut. Praesent semper feugiat nibh sed pulvinar proin gravida hendrerit. Mi ipsum faucibus vitae aliquet nec. Adipiscing elit ut aliquam purus sit amet luctus. Morbi tempus iaculis urna id. Vitae congue mauris rhoncus aenean vel elit scelerisque. Cursus turpis massa tincidunt dui. Vulputate sapien nec sagittis aliquam malesuada. Lectus proin nibh nisl condimentum id venenatis a condimentum. Est lorem ipsum dolor sit amet consectetur. Blandit aliquam etiam erat velit.
Vel turpis nunc eget lorem dolor. Volutpat commodo sed egestas egestas fringilla phasellus faucibus. Auctor eu augue ut lectus arcu bibendum. Suscipit tellus mauris a diam maecenas sed enim ut sem. Vivamus at augue eget arcu dictum varius. Vitae et leo duis ut diam quam nulla porttitor. Enim eu turpis egestas pretium. A diam sollicitudin tempor id eu nisl nunc mi. Venenatis cras sed felis eget. Sagittis eu volutpat odio facilisis mauris sit amet massa vitae. Tempor orci eu lobortis elementum nibh tellus molestie. Semper auctor neque vitae tempus quam pellentesque nec nam. Tempor commodo ullamcorper a lacus vestibulum sed arcu non odio. Tristique nulla aliquet enim tortor. Volutpat commodo sed egestas egestas fringilla phasellus. Enim ut sem viverra aliquet eget sit amet tellus cras. Cras semper auctor neque vitae tempus quam.
In nibh mauris cursus mattis molestie. Vivamus arcu felis bibendum ut tristique et egestas quis ipsum. Dolor purus non enim praesent elementum facilisis leo. Enim ut tellus elementum sagittis. Sed libero enim sed faucibus turpis in. Ac turpis egestas maecenas pharetra convallis posuere morbi leo. Nibh sit amet commodo nulla facilisi nullam vehicula ipsum. Arcu dictum varius duis at consectetur lorem donec massa. Tellus cras adipiscing enim eu turpis egestas pretium. Phasellus faucibus scelerisque eleifend donec pretium vulputate. Sollicitudin nibh sit amet commodo nulla facilisi nullam. Bibendum enim facilisis gravida neque convallis. Quis viverra nibh cras pulvinar mattis nunc. Quam nulla porttitor massa id neque aliquam vestibulum. Pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies. Faucibus turpis in eu mi bibendum neque. Curabitur gravida arcu ac tortor. Purus sit amet luctus venenatis lectus magna fringilla. Tincidunt vitae semper quis lectus nulla at volutpat. Vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis.
Mi quis hendrerit dolor magna eget est lorem. Ut lectus arcu bibendum at. Elit at imperdiet dui accumsan sit amet nulla. Tristique et egestas quis ipsum suspendisse ultrices. A arcu cursus vitae congue. Dolor sed viverra ipsum nunc aliquet bibendum enim facilisis. Nec dui nunc mattis enim ut tellus elementum sagittis. Posuere ac ut consequat semper. Eu non diam phasellus vestibulum lorem sed risus. Arcu ac tortor dignissim convallis aenean et tortor at. Velit scelerisque in dictum non consectetur a erat. Condimentum mattis pellentesque id nibh. Quam quisque id diam vel quam. At lectus urna duis convallis convallis tellus id interdum velit. Aliquam vestibulum morbi blandit cursus risus at ultrices. Ullamcorper velit sed ullamcorper morbi tincidunt ornare massa. Mattis molestie a iaculis at erat pellentesque adipiscing. In nulla posuere sollicitudin aliquam ultrices sagittis. Vel elit scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique.
Amet consectetur adipiscing elit ut aliquam purus sit amet luctus. Et ultrices neque ornare aenean euismod elementum. Orci sagittis eu volutpat odio. Vitae aliquet nec ullamcorper sit amet risus nullam. A scelerisque purus semper eget duis at. Risus viverra adipiscing at in tellus integer feugiat scelerisque varius. Quis auctor elit sed vulputate. Enim ut sem viverra aliquet eget sit. Nulla aliquet porttitor lacus luctus. Mi sit amet mauris commodo quis imperdiet. Ac felis donec et odio pellentesque diam volutpat commodo sed. Lacus viverra vitae congue eu consequat ac felis donec et. Facilisis magna etiam tempor orci eu lobortis elementum nibh tellus. Velit egestas dui id ornare arcu.`
}
}
const contentValues = {
intro: {
name: 'INTRO',
description: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Rhoncus urna neque viverra justo nec ultrices dui. Quis risus sed vulputate odio ut. Praesent semper feugiat nibh sed pulvinar proin gravida hendrerit. Mi ipsum faucibus vitae aliquet nec. Adipiscing elit ut aliquam purus sit amet luctus. Morbi tempus iaculis urna id. Vitae congue mauris rhoncus aenean vel elit scelerisque. Cursus turpis massa tincidunt dui. Vulputate sapien nec sagittis aliquam malesuada. Lectus proin nibh nisl condimentum id venenatis a condimentum. Est lorem ipsum dolor sit amet consectetur. Blandit aliquam etiam erat velit.
Vel turpis nunc eget lorem dolor. Volutpat commodo sed egestas egestas fringilla phasellus faucibus. Auctor eu augue ut lectus arcu bibendum. Suscipit tellus mauris a diam maecenas sed enim ut sem. Vivamus at augue eget arcu dictum varius. Vitae et leo duis ut diam quam nulla porttitor. Enim eu turpis egestas pretium. A diam sollicitudin tempor id eu nisl nunc mi. Venenatis cras sed felis eget. Sagittis eu volutpat odio facilisis mauris sit amet massa vitae. Tempor orci eu lobortis elementum nibh tellus molestie. Semper auctor neque vitae tempus quam pellentesque nec nam. Tempor commodo ullamcorper a lacus vestibulum sed arcu non odio. Tristique nulla aliquet enim tortor. Volutpat commodo sed egestas egestas fringilla phasellus. Enim ut sem viverra aliquet eget sit amet tellus cras. Cras semper auctor neque vitae tempus quam.
In nibh mauris cursus mattis molestie. Vivamus arcu felis bibendum ut tristique et egestas quis ipsum. Dolor purus non enim praesent elementum facilisis leo. Enim ut tellus elementum sagittis. Sed libero enim sed faucibus turpis in. Ac turpis egestas maecenas pharetra convallis posuere morbi leo. Nibh sit amet commodo nulla facilisi nullam vehicula ipsum. Arcu dictum varius duis at consectetur lorem donec massa. Tellus cras adipiscing enim eu turpis egestas pretium. Phasellus faucibus scelerisque eleifend donec pretium vulputate. Sollicitudin nibh sit amet commodo nulla facilisi nullam. Bibendum enim facilisis gravida neque convallis. Quis viverra nibh cras pulvinar mattis nunc. Quam nulla porttitor massa id neque aliquam vestibulum. Pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies. Faucibus turpis in eu mi bibendum neque. Curabitur gravida arcu ac tortor. Purus sit amet luctus venenatis lectus magna fringilla. Tincidunt vitae semper quis lectus nulla at volutpat. Vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis.
Mi quis hendrerit dolor magna eget est lorem. Ut lectus arcu bibendum at. Elit at imperdiet dui accumsan sit amet nulla. Tristique et egestas quis ipsum suspendisse ultrices. A arcu cursus vitae congue. Dolor sed viverra ipsum nunc aliquet bibendum enim facilisis. Nec dui nunc mattis enim ut tellus elementum sagittis. Posuere ac ut consequat semper. Eu non diam phasellus vestibulum lorem sed risus. Arcu ac tortor dignissim convallis aenean et tortor at. Velit scelerisque in dictum non consectetur a erat. Condimentum mattis pellentesque id nibh. Quam quisque id diam vel quam. At lectus urna duis convallis convallis tellus id interdum velit. Aliquam vestibulum morbi blandit cursus risus at ultrices. Ullamcorper velit sed ullamcorper morbi tincidunt ornare massa. Mattis molestie a iaculis at erat pellentesque adipiscing. In nulla posuere sollicitudin aliquam ultrices sagittis. Vel elit scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique.
Amet consectetur adipiscing elit ut aliquam purus sit amet luctus. Et ultrices neque ornare aenean euismod elementum. Orci sagittis eu volutpat odio. Vitae aliquet nec ullamcorper sit amet risus nullam. A scelerisque purus semper eget duis at. Risus viverra adipiscing at in tellus integer feugiat scelerisque varius. Quis auctor elit sed vulputate. Enim ut sem viverra aliquet eget sit. Nulla aliquet porttitor lacus luctus. Mi sit amet mauris commodo quis imperdiet. Ac felis donec et odio pellentesque diam volutpat commodo sed. Lacus viverra vitae congue eu consequat ac felis donec et. Facilisis magna etiam tempor orci eu lobortis elementum nibh tellus. Velit egestas dui id ornare arcu.`
},
work: {
name: 'WORK',
description: ``
},
about: {
name: 'ABOUT',
description: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Rhoncus urna neque viverra justo nec ultrices dui. Quis risus sed vulputate odio ut. Praesent semper feugiat nibh sed pulvinar proin gravida hendrerit. Mi ipsum faucibus vitae aliquet nec. Adipiscing elit ut aliquam purus sit amet luctus. Morbi tempus iaculis urna id. Vitae congue mauris rhoncus aenean vel elit scelerisque. Cursus turpis massa tincidunt dui. Vulputate sapien nec sagittis aliquam malesuada. Lectus proin nibh nisl condimentum id venenatis a condimentum. Est lorem ipsum dolor sit amet consectetur. Blandit aliquam etiam erat velit.
Vel turpis nunc eget lorem dolor. Volutpat commodo sed egestas egestas fringilla phasellus faucibus. Auctor eu augue ut lectus arcu bibendum. Suscipit tellus mauris a diam maecenas sed enim ut sem. Vivamus at augue eget arcu dictum varius. Vitae et leo duis ut diam quam nulla porttitor. Enim eu turpis egestas pretium. A diam sollicitudin tempor id eu nisl nunc mi. Venenatis cras sed felis eget. Sagittis eu volutpat odio facilisis mauris sit amet massa vitae. Tempor orci eu lobortis elementum nibh tellus molestie. Semper auctor neque vitae tempus quam pellentesque nec nam. Tempor commodo ullamcorper a lacus vestibulum sed arcu non odio. Tristique nulla aliquet enim tortor. Volutpat commodo sed egestas egestas fringilla phasellus. Enim ut sem viverra aliquet eget sit amet tellus cras. Cras semper auctor neque vitae tempus quam.
In nibh mauris cursus mattis molestie. Vivamus arcu felis bibendum ut tristique et egestas quis ipsum. Dolor purus non enim praesent elementum facilisis leo. Enim ut tellus elementum sagittis. Sed libero enim sed faucibus turpis in. Ac turpis egestas maecenas pharetra convallis posuere morbi leo. Nibh sit amet commodo nulla facilisi nullam vehicula ipsum. Arcu dictum varius duis at consectetur lorem donec massa. Tellus cras adipiscing enim eu turpis egestas pretium. Phasellus faucibus scelerisque eleifend donec pretium vulputate. Sollicitudin nibh sit amet commodo nulla facilisi nullam. Bibendum enim facilisis gravida neque convallis. Quis viverra nibh cras pulvinar mattis nunc. Quam nulla porttitor massa id neque aliquam vestibulum. Pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies. Faucibus turpis in eu mi bibendum neque. Curabitur gravida arcu ac tortor. Purus sit amet luctus venenatis lectus magna fringilla. Tincidunt vitae semper quis lectus nulla at volutpat. Vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis.
Mi quis hendrerit dolor magna eget est lorem. Ut lectus arcu bibendum at. Elit at imperdiet dui accumsan sit amet nulla. Tristique et egestas quis ipsum suspendisse ultrices. A arcu cursus vitae congue. Dolor sed viverra ipsum nunc aliquet bibendum enim facilisis. Nec dui nunc mattis enim ut tellus elementum sagittis. Posuere ac ut consequat semper. Eu non diam phasellus vestibulum lorem sed risus. Arcu ac tortor dignissim convallis aenean et tortor at. Velit scelerisque in dictum non consectetur a erat. Condimentum mattis pellentesque id nibh. Quam quisque id diam vel quam. At lectus urna duis convallis convallis tellus id interdum velit. Aliquam vestibulum morbi blandit cursus risus at ultrices. Ullamcorper velit sed ullamcorper morbi tincidunt ornare massa. Mattis molestie a iaculis at erat pellentesque adipiscing. In nulla posuere sollicitudin aliquam ultrices sagittis. Vel elit scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique.
Amet consectetur adipiscing elit ut aliquam purus sit amet luctus. Et ultrices neque ornare aenean euismod elementum. Orci sagittis eu volutpat odio. Vitae aliquet nec ullamcorper sit amet risus nullam. A scelerisque purus semper eget duis at. Risus viverra adipiscing at in tellus integer feugiat scelerisque varius. Quis auctor elit sed vulputate. Enim ut sem viverra aliquet eget sit. Nulla aliquet porttitor lacus luctus. Mi sit amet mauris commodo quis imperdiet. Ac felis donec et odio pellentesque diam volutpat commodo sed. Lacus viverra vitae congue eu consequat ac felis donec et. Facilisis magna etiam tempor orci eu lobortis elementum nibh tellus. Velit egestas dui id ornare arcu.`
},
contact: {
name: 'CONTACT',
description: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Rhoncus urna neque viverra justo nec ultrices dui. Quis risus sed vulputate odio ut. Praesent semper feugiat nibh sed pulvinar proin gravida hendrerit. Mi ipsum faucibus vitae aliquet nec. Adipiscing elit ut aliquam purus sit amet luctus. Morbi tempus iaculis urna id. Vitae congue mauris rhoncus aenean vel elit scelerisque. Cursus turpis massa tincidunt dui. Vulputate sapien nec sagittis aliquam malesuada. Lectus proin nibh nisl condimentum id venenatis a condimentum. Est lorem ipsum dolor sit amet consectetur. Blandit aliquam etiam erat velit.
Vel turpis nunc eget lorem dolor. Volutpat commodo sed egestas egestas fringilla phasellus faucibus. Auctor eu augue ut lectus arcu bibendum. Suscipit tellus mauris a diam maecenas sed enim ut sem. Vivamus at augue eget arcu dictum varius. Vitae et leo duis ut diam quam nulla porttitor. Enim eu turpis egestas pretium. A diam sollicitudin tempor id eu nisl nunc mi. Venenatis cras sed felis eget. Sagittis eu volutpat odio facilisis mauris sit amet massa vitae. Tempor orci eu lobortis elementum nibh tellus molestie. Semper auctor neque vitae tempus quam pellentesque nec nam. Tempor commodo ullamcorper a lacus vestibulum sed arcu non odio. Tristique nulla aliquet enim tortor. Volutpat commodo sed egestas egestas fringilla phasellus. Enim ut sem viverra aliquet eget sit amet tellus cras. Cras semper auctor neque vitae tempus quam.
In nibh mauris cursus mattis molestie. Vivamus arcu felis bibendum ut tristique et egestas quis ipsum. Dolor purus non enim praesent elementum facilisis leo. Enim ut tellus elementum sagittis. Sed libero enim sed faucibus turpis in. Ac turpis egestas maecenas pharetra convallis posuere morbi leo. Nibh sit amet commodo nulla facilisi nullam vehicula ipsum. Arcu dictum varius duis at consectetur lorem donec massa. Tellus cras adipiscing enim eu turpis egestas pretium. Phasellus faucibus scelerisque eleifend donec pretium vulputate. Sollicitudin nibh sit amet commodo nulla facilisi nullam. Bibendum enim facilisis gravida neque convallis. Quis viverra nibh cras pulvinar mattis nunc. Quam nulla porttitor massa id neque aliquam vestibulum. Pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies. Faucibus turpis in eu mi bibendum neque. Curabitur gravida arcu ac tortor. Purus sit amet luctus venenatis lectus magna fringilla. Tincidunt vitae semper quis lectus nulla at volutpat. Vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis.
Mi quis hendrerit dolor magna eget est lorem. Ut lectus arcu bibendum at. Elit at imperdiet dui accumsan sit amet nulla. Tristique et egestas quis ipsum suspendisse ultrices. A arcu cursus vitae congue. Dolor sed viverra ipsum nunc aliquet bibendum enim facilisis. Nec dui nunc mattis enim ut tellus elementum sagittis. Posuere ac ut consequat semper. Eu non diam phasellus vestibulum lorem sed risus. Arcu ac tortor dignissim convallis aenean et tortor at. Velit scelerisque in dictum non consectetur a erat. Condimentum mattis pellentesque id nibh. Quam quisque id diam vel quam. At lectus urna duis convallis convallis tellus id interdum velit. Aliquam vestibulum morbi blandit cursus risus at ultrices. Ullamcorper velit sed ullamcorper morbi tincidunt ornare massa. Mattis molestie a iaculis at erat pellentesque adipiscing. In nulla posuere sollicitudin aliquam ultrices sagittis. Vel elit scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique.
Amet consectetur adipiscing elit ut aliquam purus sit amet luctus. Et ultrices neque ornare aenean euismod elementum. Orci sagittis eu volutpat odio. Vitae aliquet nec ullamcorper sit amet risus nullam. A scelerisque purus semper eget duis at. Risus viverra adipiscing at in tellus integer feugiat scelerisque varius. Quis auctor elit sed vulputate. Enim ut sem viverra aliquet eget sit. Nulla aliquet porttitor lacus luctus. Mi sit amet mauris commodo quis imperdiet. Ac felis donec et odio pellentesque diam volutpat commodo sed. Lacus viverra vitae congue eu consequat ac felis donec et. Facilisis magna etiam tempor orci eu lobortis elementum nibh tellus. Velit egestas dui id ornare arcu.`
}
}
export default contentValues;

114
lib/navigationContent.tsx Normal file → Executable file
View File

@ -1,58 +1,58 @@
import React from 'react';
import Content from '../components/content'
import backgroundPic from '../public/unspash_image.jpg'
import ContentCarousel from '../components/content/carousel'
import contentValues from './content';
import portfolioValues from './portfolio';
import { pdfjs, Document, Page } from 'react-pdf';
const resumePdf = '../public/assets/Okechi_Onyeje_Resume_Professional_2023.pdf'
export default [
{
name: contentValues.intro.name,
url: '#intro',
content: <Content
title='Intro'
heroImgSrc={backgroundPic}
description={contentValues.intro.description}
/>
},
{
name: contentValues.work.name,
url: '#work',
content: <Content
title='Work'
heroImgSrc={backgroundPic}
description={contentValues.work.description}
innerChildren={
<div>
<Document
file={resumePdf}
/>
<ContentCarousel
data={portfolioValues}
/>
</div>
}
/>
},
{
name: contentValues.about.name,
url: '#about',
content: <Content
title='About'
heroImgSrc={backgroundPic}
description={contentValues.about.description}
/>
},
{
name: contentValues.contact.name,
url: '#contact',
content: <Content
title='Contact'
heroImgSrc={backgroundPic}
description={contentValues.contact.description}
/>
}
import React from 'react';
import Content from '../components/content'
import backgroundPic from '../public/unspash_image.jpg'
import ContentCarousel from '../components/content/carousel'
import contentValues from './content';
import portfolioValues from './portfolio';
import { pdfjs, Document, Page } from 'react-pdf';
const resumePdf = '../public/assets/Okechi_Onyeje_Resume_Professional_2023.pdf'
export default [
{
name: contentValues.intro.name,
url: '#intro',
content: <Content
title='Intro'
heroImgSrc={backgroundPic}
description={contentValues.intro.description}
/>
},
{
name: contentValues.work.name,
url: '#work',
content: <Content
title='Work'
heroImgSrc={backgroundPic}
description={contentValues.work.description}
innerChildren={
<div>
<Document
file={resumePdf}
/>
<ContentCarousel
data={portfolioValues}
/>
</div>
}
/>
},
{
name: contentValues.about.name,
url: '#about',
content: <Content
title='About'
heroImgSrc={backgroundPic}
description={contentValues.about.description}
/>
},
{
name: contentValues.contact.name,
url: '#contact',
content: <Content
title='Contact'
heroImgSrc={backgroundPic}
description={contentValues.contact.description}
/>
}
];

54
lib/portfolio.ts Normal file → Executable file
View File

@ -1,28 +1,28 @@
const portfolioValues = [
{
title: 'Vendoo',
heroImgSrc: '',
description: '',
prototypeIframeURL: 'https://www.kroleo.com/invision/Vendoo/#/screens'
},
{
title: 'Garage2Garage',
heroImgSrc: '',
description: '',
prototypeIframeURL: ''
},
{
title: 'Aqua',
heroImgSrc: '',
description: '',
prototypeIframeURL: 'https://projects.invisionapp.com/share/QV9OA25MA#/screens'
},
{
title: 'GetHip',
heroImgSrc: '',
description: '',
prototypeIframeURL: 'https://www.kroleo.com/invision/GetHip/#/screens'
},
]
const portfolioValues = [
{
title: 'Vendoo',
heroImgSrc: '',
description: '',
prototypeIframeURL: 'https://www.kroleo.com/invision/Vendoo/#/screens'
},
{
title: 'Garage2Garage',
heroImgSrc: '',
description: '',
prototypeIframeURL: ''
},
{
title: 'Aqua',
heroImgSrc: '',
description: '',
prototypeIframeURL: 'https://projects.invisionapp.com/share/QV9OA25MA#/screens'
},
{
title: 'GetHip',
heroImgSrc: '',
description: '',
prototypeIframeURL: 'https://www.kroleo.com/invision/GetHip/#/screens'
},
]
export default portfolioValues;

164
pages/index.tsx Normal file → Executable file
View File

@ -1,82 +1,82 @@
import React, {useState} from 'react'
import Image from 'next/image'
import backgroundPic from '../public/unspash_image.jpg'
import { Inter } from 'next/font/google'
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faGem } from "@fortawesome/free-solid-svg-icons";
import navigationContent from '../lib/navigationContent'
import Modal from 'react-modal';
const inter = Inter({ subsets: ['latin'] })
export default function Home() {
const customStyles = {
overlay: {
backgroundColor: 'rgba(0, 0, 0, 0.6)'
},
content: {
top: '50%',
left: '50%',
right: 'auto',
bottom: 'auto',
marginRight: '-50%',
transform: 'translate(-50%, -50%)',
backgroundColor: 'gray',
width: '75vw'
}
}
const [showModal, setShowModal] = useState(false);
const [modalData, setModalData] = useState<{name: string, url: string, content?: any}>({
name: '',
url: '',
content: ''
});
const renderNav = (navData: Array<{name: string, url: string, content: (string | React.ElementType | null)}>) => {
return navData.map((data, idx) => (
<span
onClick={() => {
setShowModal(true)
setModalData(data);
}}
key={idx}
className='p-4 border-white text-white border-2 hover:cursor-pointer hover:bg-white hover:bg-opacity-10'
>
<a href={data.url}>{data.name}</a>
</span>
));
};
Modal.setAppElement('#info-anchor');
return (
<div id="info-anchor" className='relative w-full flex-row justify-center'>
{!showModal && <div className='tablet:w-full h-full bg-cover'>
{/* <Image src={backgroundPic} alt="record background"/> */}
<div className='flex flex-col justify-center text-center'>
{/* <FontAwesomeIcon width={25} height={50} icon={faGem} className="fas fa-gem" style={{ color: "red" }} /> */}
<div className='w-full grid grid-row-4 justify-center h-1/2'>
<div className='col-span-2 w-1/2 border-t-2 border-white border-r-2'></div>
<div className='col-span-2 h-1/2 w-1/2 border-t-2 border-white border-l-2'></div>
</div>
<div className='flex flex-row justify-center'>
{renderNav(navigationContent)}
</div>
</div>
</div>}
{showModal && (
<div style={{height: '100vh', width: '100vw'}} className='justify-center flex flex-row bg-black bg-opacity-40'>
<div style={{height: '100vh'}} className="laptop:px-24 absolute z-10 p-10 overflow-y-auto flex flex-row justify-center">
<div className='flex flex-row justify-center'>
<div className=" laptop:w-1/2 h-min z-20 bg-black bg-opacity-90 text-white rounded">
<div className="w-full flex flex-row justify-end p-4">
<span className="cursor-pointer" onClick={() => setShowModal(false)}>X</span>
</div>
{modalData.content}
</div>
</div>
</div>
</div>
)}
</div>
)
}
import React, {useState} from 'react'
import Image from 'next/image'
import backgroundPic from '../public/unspash_image.jpg'
import { Inter } from 'next/font/google'
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faGem } from "@fortawesome/free-solid-svg-icons";
import navigationContent from '../lib/navigationContent'
import Modal from 'react-modal';
const inter = Inter({ subsets: ['latin'] })
export default function Home() {
const customStyles = {
overlay: {
backgroundColor: 'rgba(0, 0, 0, 0.6)'
},
content: {
top: '50%',
left: '50%',
right: 'auto',
bottom: 'auto',
marginRight: '-50%',
transform: 'translate(-50%, -50%)',
backgroundColor: 'gray',
width: '75vw'
}
}
const [showModal, setShowModal] = useState(false);
const [modalData, setModalData] = useState<{name: string, url: string, content?: any}>({
name: '',
url: '',
content: ''
});
const renderNav = (navData: Array<{name: string, url: string, content: (string | React.ElementType | null)}>) => {
return navData.map((data, idx) => (
<span
onClick={() => {
setShowModal(true)
setModalData(data);
}}
key={idx}
className='p-4 border-white text-white border-2 hover:cursor-pointer hover:bg-white hover:bg-opacity-10'
>
<a href={data.url}>{data.name}</a>
</span>
));
};
Modal.setAppElement('#info-anchor');
return (
<div id="info-anchor" className='relative w-full flex-row justify-center'>
{!showModal && <div className='tablet:w-full h-full bg-cover'>
{/* <Image src={backgroundPic} alt="record background"/> */}
<div className='flex flex-col justify-center text-center'>
{/* <FontAwesomeIcon width={25} height={50} icon={faGem} className="fas fa-gem" style={{ color: "red" }} /> */}
<div className='w-full grid grid-row-4 justify-center h-1/2'>
<div className='col-span-2 w-1/2 border-t-2 border-white border-r-2'></div>
<div className='col-span-2 h-1/2 w-1/2 border-t-2 border-white border-l-2'></div>
</div>
<div className='flex flex-row justify-center'>
{renderNav(navigationContent)}
</div>
</div>
</div>}
{showModal && (
<div style={{height: '100vh', width: '100vw'}} className='justify-center flex flex-row bg-black bg-opacity-40'>
<div style={{height: '100vh'}} className="laptop:px-24 absolute z-10 p-10 overflow-y-auto flex flex-row justify-center">
<div className='flex flex-row justify-center'>
<div className=" laptop:w-1/2 h-min z-20 bg-black bg-opacity-90 text-white rounded">
<div className="w-full flex flex-row justify-end p-4">
<span className="cursor-pointer" onClick={() => setShowModal(false)}>X</span>
</div>
{modalData.content}
</div>
</div>
</div>
</div>
)}
</div>
)
}

View File