Commit d504a0fd authored by Gamage B.G.J's avatar Gamage B.G.J

Merge branch 'IT20005276' into 'master'

It20005276

See merge request !16
parents 68684f39 f8c53ceb
......@@ -19,6 +19,7 @@
"multer": "^1.4.5-lts.1",
"nodemailer": "^6.9.1",
"nodemon": "^2.0.22",
"react-mic": "^12.4.6",
"torch": "^0.2.7",
"uuid": "^9.0.0"
}
......@@ -696,6 +697,11 @@
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"node_modules/jsonwebtoken": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
......@@ -748,6 +754,17 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
},
"bin": {
"loose-envify": "cli.js"
}
},
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
......@@ -1117,6 +1134,16 @@
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.13.1"
}
},
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
......@@ -1178,6 +1205,47 @@
"node": ">= 0.8"
}
},
"node_modules/react": {
"version": "16.14.0",
"resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
"integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react-ga": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/react-ga/-/react-ga-2.7.0.tgz",
"integrity": "sha512-AjC7UOZMvygrWTc2hKxTDvlMXEtbmA0IgJjmkhgmQQ3RkXrWR11xEagLGFGaNyaPnmg24oaIiaNPnEoftUhfXA==",
"peerDependencies": {
"prop-types": "^15.6.0",
"react": "^15.6.2 || ^16.0"
}
},
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"node_modules/react-mic": {
"version": "12.4.6",
"resolved": "https://registry.npmjs.org/react-mic/-/react-mic-12.4.6.tgz",
"integrity": "sha512-2/DZoz7thR2nJyekF10zBvs/7a8HhUQ4L8MV6BpC+Q/T8G1MvpRHGSHjSlVtnbzaCMDJ3R1MdThoLu15WuVh/g==",
"dependencies": {
"prop-types": "^15.5.10",
"react-ga": "^2.2.0"
},
"peerDependencies": {
"prop-types": "^15.5.10",
"react": "16.x"
}
},
"node_modules/readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
......@@ -2092,6 +2160,11 @@
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"jsonwebtoken": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
......@@ -2139,6 +2212,14 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"requires": {
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
......@@ -2393,6 +2474,16 @@
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.13.1"
}
},
"proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
......@@ -2436,6 +2527,37 @@
"unpipe": "1.0.0"
}
},
"react": {
"version": "16.14.0",
"resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
"integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
"peer": true,
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2"
}
},
"react-ga": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/react-ga/-/react-ga-2.7.0.tgz",
"integrity": "sha512-AjC7UOZMvygrWTc2hKxTDvlMXEtbmA0IgJjmkhgmQQ3RkXrWR11xEagLGFGaNyaPnmg24oaIiaNPnEoftUhfXA==",
"requires": {}
},
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"react-mic": {
"version": "12.4.6",
"resolved": "https://registry.npmjs.org/react-mic/-/react-mic-12.4.6.tgz",
"integrity": "sha512-2/DZoz7thR2nJyekF10zBvs/7a8HhUQ4L8MV6BpC+Q/T8G1MvpRHGSHjSlVtnbzaCMDJ3R1MdThoLu15WuVh/g==",
"requires": {
"prop-types": "^15.5.10",
"react-ga": "^2.2.0"
}
},
"readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
......
......@@ -21,6 +21,7 @@
"multer": "^1.4.5-lts.1",
"nodemailer": "^6.9.1",
"nodemon": "^2.0.22",
"react-mic": "^12.4.6",
"torch": "^0.2.7",
"uuid": "^9.0.0"
}
......
......@@ -15,7 +15,8 @@ class ImageRequest(BaseModel):
image: UploadFile
# Load your Keras model
model = tf.keras.models.load_model('../ML_Models/sign_language_to_text/models/sign_language_model.h5')
# model = tf.keras.models.load_model('../ML_Models/sign_language_to_text/models/sign_language_model.h5')
model= None
CLASSES = mappings.classes
NUM_CLASSES = len(mappings.classes) # number of classes
IMG_SIZE = 224 # image size
......
......@@ -12,7 +12,10 @@ import {
ShoppingOutlined,
TeamOutlined,
TranslationOutlined,
UserOutlined
UserOutlined,
AudioOutlined,
VideoCameraOutlined,
RedditOutlined,
} from '@ant-design/icons';
// type
......@@ -29,7 +32,10 @@ const icons = {
LoginOutlined,
RocketOutlined,
BookOutlined,
TranslationOutlined
TranslationOutlined,
AudioOutlined,
VideoCameraOutlined,
RedditOutlined,
};
// ==============================|| MENU ITEMS - SUPPORT ||============================== //
......@@ -74,6 +80,32 @@ const application: NavItemType = {
icon: icons.TranslationOutlined,
url: '/ssl-translate/process',
},
{
id: 'emotion-detection',
title: <FormattedMessage id="emotion-detection" />,
type: 'collapse',
icon: icons.RedditOutlined,
children: [
{
id: 'audio-detection',
title: <FormattedMessage id="audio-detection" />,
type: 'item',
icon: icons.AudioOutlined,
url: '/emotion-detection/audio-detection',
},
{
id: 'video-detection',
title: <FormattedMessage id="video-detection" />,
type: 'item',
icon: icons.VideoCameraOutlined,
url: '/emotion-detection/video-detection',
},
]
},
{
id: 'learning-management',
title: <FormattedMessage id="learning-management" />,
......
import React, { useState } from 'react';
import MainCard from 'components/MainCard';
import ScrollX from 'components/ScrollX';
import Grid from '@mui/material/Grid';
import Button from '@mui/material/Button';
import UploadOutlined from '@ant-design/icons/lib/icons/UploadOutlined';
import AudioOutlined from '@ant-design/icons/lib/icons/AudioOutlined';
const List = () => {
const [audioBlob, setAudioBlob] = useState<Blob | undefined>(undefined);
const [mediaRecorder, setMediaRecorder] = useState<MediaRecorder | undefined>(undefined);
const [isRecording, setIsRecording] = useState<boolean>(false);
const [audioUrl, setAudioUrl] = useState<string | undefined>(undefined);
const handleRecordStart = async () => {
// Clear the uploaded audio state when recording starts
setAudioUrl(undefined);
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const recorder = new MediaRecorder(stream);
recorder.ondataavailable = (event) => {
if (event.data.size > 0) {
setAudioBlob(new Blob([event.data], { type: 'audio/wav' }));
}
};
recorder.onstop = () => {
stream.getTracks().forEach(track => track.stop());
};
setMediaRecorder(recorder);
recorder.start();
setIsRecording(true);
} catch (error) {
console.error('Error starting recording:', error);
}
};
const handleRecordStop = () => {
if (mediaRecorder && isRecording) {
mediaRecorder.stop();
setIsRecording(false);
}
};
const handleUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
const files = event.target.files;
if (files && files[0] && files[0].type.startsWith('audio/')) {
const audioObjectUrl = URL.createObjectURL(files[0]);
setAudioUrl(audioObjectUrl);
} else {
// Handle case where uploaded file is not an audio file
}
};
return (
<MainCard content={false}>
<ScrollX>
<Grid container spacing={2}>
<Grid item xs={12} md={6}>
<h2>Upload or Record</h2>
<MainCard>
<div style={{ textAlign: 'center' }}>
<input
type="file"
accept="audio/*"
onChange={handleUpload}
style={{ display: 'none' }}
id="audio-upload"
/>
<label htmlFor="audio-upload">
<Button
variant="contained"
color="primary"
component="span"
startIcon={<UploadOutlined />}
>
Upload
</Button>
</label>
<Button
variant="contained"
color="primary"
startIcon={<AudioOutlined />}
onClick={isRecording ? handleRecordStop : handleRecordStart}
>
{isRecording ? 'Stop Recording' : 'Record'}
</Button>
{audioBlob && (
<audio controls>
<source src={URL.createObjectURL(audioBlob)} type="audio/wav" />
Your browser does not support the audio element.
</audio>
)}
{audioUrl && (
<audio controls>
<source src={audioUrl} type="audio/mpeg" />
Your browser does not support the audio element.
</audio>
)}
</div>
</MainCard>
</Grid>
<Grid item xs={12} md={6}>
<h2>3D Avatar</h2>
<MainCard>
{/* Content of the second card */}
{/* You can put your 3D avatar components here */}
</MainCard>
</Grid>
</Grid>
</ScrollX>
</MainCard>
);
};
export default List;
import React, { useState, useRef } from 'react';
import MainCard from 'components/MainCard';
import ScrollX from 'components/ScrollX';
import Grid from '@mui/material/Grid';
import Button from '@mui/material/Button';
import VideoCameraOutlined from '@ant-design/icons/lib/icons/VideoCameraOutlined';
import UploadOutlined from '@ant-design/icons/lib/icons/UploadOutlined';
// import WebcamOutlinedIcon from '@mui/icons-material/WebcamOutlined';
const List = () => {
const [selectedFile, setSelectedFile] = useState<File | null>(null);
const [isLive, setIsLive] = useState(false);
const fileInputRef = useRef<HTMLInputElement | null>(null);
const videoRef = useRef<HTMLVideoElement | null>(null);
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
if (event.target.files && event.target.files[0]) {
setSelectedFile(event.target.files[0]);
}
};
const handleUploadButtonClick = () => {
if (fileInputRef.current) {
fileInputRef.current.click();
}
};
const handleLiveButtonClick = async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
if (videoRef.current) {
videoRef.current.srcObject = stream;
videoRef.current.play(); // Start playing the live camera feed
}
setIsLive(true);
} catch (error) {
console.error('Error accessing camera:', error);
}
};
return (
<MainCard content={false}>
<ScrollX>
<Grid container spacing={2}>
<Grid item xs={12} md={6}>
<h2>Upload or Live</h2>
<MainCard>
<div style={{ textAlign: 'center' }}>
<input
type="file"
accept="video/*"
ref={fileInputRef}
onChange={handleFileChange}
style={{ display: 'none' }}
/>
{isLive ? (
<video
ref={videoRef}
autoPlay
playsInline
width="100%"
/>
) : (
selectedFile && (
<video
controls
width="100%"
src={URL.createObjectURL(selectedFile)}
/>
)
)}
<Button
variant="contained"
color="primary"
startIcon={<UploadOutlined />}
onClick={handleUploadButtonClick}
>
Upload
</Button>
<Button
variant="contained"
color="primary"
startIcon={<VideoCameraOutlined />}
onClick={handleLiveButtonClick}
>
Live
</Button>
</div>
</MainCard>
</Grid>
<Grid item xs={12} md={6}>
<h2>3D Avatar</h2>
<MainCard>
{/* Content of the second card */}
{/* You can put your 3D avatar components here */}
</MainCard>
</Grid>
</Grid>
</ScrollX>
</MainCard>
);
};
export default List;
......@@ -46,6 +46,15 @@ const CurriculumManagementList = Loadable(lazy(() => import('pages/parameter/cur
const TutorialManagementList = Loadable(lazy(() => import('pages/parameter/tutorial-management/list/list')));
// render - audio-detection page
const AudioDetection = Loadable(lazy(() => import('pages/emotion-detection/emotion-audio-detection/list/list')));
// render - video-detection page
const VideoDetection = Loadable(lazy(() => import('pages/emotion-detection/emotion-video-detection/list/list')));
// ==============================|| MAIN ROUTING ||============================== //
const MainRoutes = {
......@@ -95,6 +104,21 @@ const MainRoutes = {
}
]
},
{
path: 'emotion-detection',
children: [
{
path: 'audio-detection',
element: <AudioDetection />
},
{
path: 'video-detection',
element: <VideoDetection />
}
]
},
{
path: 'learning-management',
children: [
......
......@@ -162,5 +162,8 @@
"learning-lead-board": "Lead Board",
"learning-feedback": "Feedback",
"ssl-translate": "SSL Translate",
"emotion-detection": "Emotion Detection",
"audio-detection": "Audio Detection",
"video-detection": "Video Detection",
"learning-dashboard": "Dashboard"
}
\ No newline at end of file
......@@ -20,6 +20,7 @@ const LINKS = [
{ name: 'About us', href: PATH_PAGE.about },
{ name: 'Contact us', href: PATH_PAGE.contact },
{ name: 'FAQs', href: PATH_PAGE.faqs },
{ name: 'Emotion Detection', href: PATH_PAGE.emotion },
],
},
{
......
......@@ -33,6 +33,7 @@ const navConfig = [
{ title: 'Payment', path: PATH_PAGE.payment },
{ title: 'Maintenance', path: PATH_PAGE.maintenance },
{ title: 'Coming Soon', path: PATH_PAGE.comingSoon },
{ title: 'Emotion Detection', path: PATH_PAGE.emotion },
],
},
{
......
// next
import Head from 'next/head';
// @mui
import { Container, Box } from '@mui/material';
// layouts
import MainLayout from '../layouts/main';
// _mock
// import { _mapEmotion } from '../_mock/arrays';
// sections
import { EmotionHero, EmotionForm, } from '../sections/emotion';
// ----------------------------------------------------------------------
EmotionDetection.getLayout = (page: React.ReactElement) => <MainLayout>{page}</MainLayout>;
// ----------------------------------------------------------------------
export default function EmotionDetection() {
return (
<>
<Head>
<title> Emotion Detection </title>
</Head>
<EmotionHero />
<Container sx={{ py: 10 }}>
<Box
gap={10}
display="grid"
gridTemplateColumns={{
xs: 'repeat(1, 1fr)',
md: 'repeat(2, 1fr)',
}}
>
<EmotionForm />
{/* <EmotionMap emotions={_mapEmotion} /> */}
</Box>
</Container>
</>
);
}
......@@ -27,6 +27,7 @@ export const PATH_PAGE = {
payment: '/payment',
about: '/about-us',
contact: '/contact-us',
emotion : '/emotion-detection',
faqs: '/faqs',
page403: '/403',
page404: '/404',
......
import { m } from 'framer-motion';
// @mui
import { Button, Typography, TextField, Stack } from '@mui/material';
// components
import { MotionViewport, varFade } from '../../components/animate';
// ----------------------------------------------------------------------
export default function EmotionForm() {
return (
<Stack component={MotionViewport} spacing={5}>
<m.div variants={varFade().inUp}>
<Typography variant="h3">
Feel free to contact us. <br />
We'll be glad to hear from you, buddy.
</Typography>
</m.div>
<Stack spacing={3}>
<m.div variants={varFade().inUp}>
<TextField fullWidth label="Name" />
</m.div>
<m.div variants={varFade().inUp}>
<TextField fullWidth label="Email" />
</m.div>
<m.div variants={varFade().inUp}>
<TextField fullWidth label="Subject" />
</m.div>
<m.div variants={varFade().inUp}>
<TextField fullWidth label="Enter your message here." multiline rows={4} />
</m.div>
</Stack>
<m.div variants={varFade().inUp}>
<Button size="large" variant="contained">
Submit Now
</Button>
</m.div>
</Stack>
);
}
import { m } from 'framer-motion';
// @mui
import { styled } from '@mui/material/styles';
import { Stack, Container, Typography, Grid } from '@mui/material';
//
import { TextAnimate, MotionContainer, varFade } from '../../components/animate';
// ----------------------------------------------------------------------
const EMOTIONS = [
{
country: 'Bali',
address: '508 Bridle Avenue Newnan, GA 30263',
phoneNumber: '(239) 555-0108',
},
{
country: 'London',
address: '508 Bridle Avenue Newnan, GA 30263',
phoneNumber: '(319) 555-0115',
},
{
country: 'Prague',
address: '508 Bridle Avenue Newnan, GA 30263',
phoneNumber: '(252) 555-0126',
},
{
country: 'Moscow',
address: '508 Bridle Avenue Newnan, GA 30263',
phoneNumber: '(307) 555-0133',
},
];
const StyledRoot = styled('div')(({ theme }) => ({
position: 'relative',
backgroundSize: 'cover',
backgroundPosition: 'center',
backgroundImage: 'url(/assets/background/overlay_1.svg), url(/assets/images/contact/hero.jpg)',
padding: theme.spacing(10, 0),
[theme.breakpoints.up('md')]: {
height: 560,
padding: 0,
},
}));
const StyledContent = styled('div')(({ theme }) => ({
textAlign: 'center',
[theme.breakpoints.up('md')]: {
bottom: 80,
textAlign: 'left',
position: 'absolute',
},
}));
// ----------------------------------------------------------------------
export default function EmotionHero() {
return (
<StyledRoot>
<Container component={MotionContainer}>
<StyledContent>
<TextAnimate text="Emotion" sx={{ color: 'primary.main' }} variants={varFade().inRight} />
<br />
<Stack spacing={2} display="inline-flex" direction="row" sx={{ color: 'common.white' }}>
<TextAnimate text="Detection" />
<TextAnimate text="find" />
<TextAnimate text="us?" />
</Stack>
<Grid container spacing={5} sx={{ mt: 5, color: 'common.white' }}>
{EMOTIONS.map((emotion) => (
<Grid
key={emotion.country}
item
xs={12}
sm={6}
md={3}
lg={2}
sx={{
pr: {
md: 5,
},
}}
>
<m.div variants={varFade().in}>
<Typography variant="h6" paragraph>
{emotion.country}
</Typography>
</m.div>
<m.div variants={varFade().inRight}>
<Typography variant="body2">
{emotion.address}
<br /> {emotion.phoneNumber}
</Typography>
</m.div>
</Grid>
))}
</Grid>
</StyledContent>
</Container>
</StyledRoot>
);
}
// export { default as EmotionMap } from './EmotionMap';
export { default as EmotionHero } from './EmotionHero';
export { default as EmotionForm } from './EmotionForm';
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment