added fetch card from server, style changes, i18

This commit is contained in:
DmitriyB
2023-03-20 16:45:16 +05:00
parent 85fa8dfe09
commit 21ac6e239c
59 changed files with 1452 additions and 501 deletions
+49 -41
View File
@@ -3,14 +3,21 @@ import "./App.css"
import { Route, Switch } from "react-router-dom";
import React, { useEffect, useState } from "react";
import { useAppDispatch, useAppSelector } from "./hooks/redux";
import cookies from "js-cookie";
import AOS from "aos";
import "aos/dist/aos.css";
import { Main } from "./components/main/main";
import { Header } from "./components/header/header";
import { Footer } from "./components/footer/footer";
import { Demostration } from "./components/demonstration/demonstartion";
import useQuery from "./hooks/useQuery";
import textRU from "./utils/textRU"
import textEN from "./utils/textEN";
import { languageSlice } from "./store/reducers/languageSlice";
import { fetchCards } from "./store/reducers/ActionCreator";
export type TObjct = {
calendar: boolean;
@@ -28,51 +35,52 @@ export const App: React.FC = () => {
const savedLanguage = localStorage.getItem('savedLang')
const dispatch = useAppDispatch();
const { handleChangeLanguage } = languageSlice.actions;
const { cards, currentCard, error } = useAppSelector((state) => state.cardReducer);
const { currentLang } = useAppSelector((state) => state.languageReducer);
const query = useQuery()
const langQuery = query.get('lang')
const langArray = ['en', 'ru']
const browserLanguage = window.navigator.language
const handleBrowserLanguage = () => {
return langArray.includes(browserLanguage)
}
const handleCookiesLanguage = () => {
const language = cookies.get("i18next")
return language
}
useEffect(() => {
if (savedLanguage !== null) {
setSavedLanguage()
} else {
setInitialLanguage()
if (langArray.includes(langQuery as string)) {
dispatch(handleChangeLanguage(langQuery as string));
return
}
}, []);
function setSavedLanguage() {
if (savedLanguage === 'RU') {
setLanguage('RU')
localStorage.setItem("lang", 'RU')
setText(textRU)
} else if (savedLanguage === 'EN') {
setLanguage('EN')
localStorage.setItem("lang", 'EN')
setText(textEN)
else if (handleCookiesLanguage()) {
const languageCookies = handleCookiesLanguage()
console.log(languageCookies)
dispatch(handleChangeLanguage(languageCookies as string))
return
}
}
let isSupported = handleBrowserLanguage()
dispatch(handleChangeLanguage(isSupported ? browserLanguage : 'en'));
}, [])
function setInitialLanguage() {
if (window.navigator.language === 'ru') {
setLanguage('RU')
localStorage.setItem("lang", 'RU')
setText(textRU)
} else {
setLanguage('EN')
setText(textEN)
useEffect(() => {
if (currentLang) {
dispatch(fetchCards(currentLang))
}
}
}, [currentLang])
function changeLanguage(language: string) {
if (language === 'RU') {
setLanguage(language);
setText(textRU)
localStorage.setItem('savedLang', 'RU');
localStorage.setItem("lang", 'RU')
} else {
setLanguage('EN')
localStorage.setItem("lang", 'EN')
localStorage.setItem("savedLang", 'EN')
setText(textEN)
}
}
AOS.init({
mirror: true,
@@ -81,8 +89,8 @@ export const App: React.FC = () => {
<Switch>
<Route path="/" exact>
<div className='App'>
<Header text={text.footer} language={language} changeLanguage={changeLanguage}></Header>
<Main locale={language} text={text}></Main>
<Header></Header>
<Main cards={cards} locale={language} text={text}></Main>
<Footer language={language} text={text.footer}></Footer>
</div>
</Route>
+5 -5
View File
@@ -37,7 +37,7 @@
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
background: #141414;
background: #1C1D21;
border-radius: 16px;
padding: 32px;
font-style: normal;
@@ -49,7 +49,7 @@
/* Landing/White */
color: #EBEBEB;
color: #F2F2F2;
}
@@ -85,7 +85,7 @@
align-items: flex-start;
gap: 20px;
padding: 24px;
background: #141414;
background: #1C1D21;
border-radius: 16px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
@@ -95,7 +95,7 @@
font-weight: 400;
font-size: 18px;
line-height: 140%;
color: #EBEBEB;
color: #F2F2F2;
background-color: transparent;
}
@@ -104,7 +104,7 @@
font-weight: 400;
font-size: 18px;
line-height: 140%;
color: #EBEBEB;
color: #F2F2F2;
}
.graph__row_item_l {
+25 -23
View File
@@ -4,21 +4,23 @@ import "../multiplayer/multiplayer.css";
import { PieChartComp } from "../piechart/piechart";
import { Button } from "../buttonDemo/buttonDemo"
import { Content } from "../content/content";
import { useTranslation } from "react-i18next";
export const Analytics: React.FC<any> = ({ text }) => {
const { cardLarge, cardLarge1, cardLarge2, cardSmall, cardSmall1, cardSmall2, cardSmall3 } = text;
const {t} = useTranslation()
return (
<div className="analytics__container">
<Content text={text}></Content>
<div data-aos="fade-up" data-aos-delay="100" className="graph__container">
<div className="graph__row_1">
<div className="graph__row_item">
<span className="graph__title title_1">{cardLarge.title}</span>
<span className="graph__title title_1">{t('cardLarge-title')}</span>
<div className="graph__bar_row">
<p className="graph__caption">{cardLarge.row}</p>
<p className="graph__caption">{t('cardLarge-row')}</p>
<div className="bar__container">
<div className="graph__bar_width_container">
<div className="graph__bar_1"></div>
@@ -27,7 +29,7 @@ export const Analytics: React.FC<any> = ({ text }) => {
<p className="graph__procentage">45%</p>
</div>
<div className="graph__bar_row">
<p className="graph__caption">{cardLarge.row1}</p>
<p className="graph__caption">{t('cardLarge-row1')}</p>
<div className="bar__container">
<div className="graph__bar_width_container">
<div className="graph__bar_2"></div>
@@ -37,7 +39,7 @@ export const Analytics: React.FC<any> = ({ text }) => {
</div>
<div className="graph__bar_row">
<p className="graph__caption">{cardLarge.row2}</p>
<p className="graph__caption">{t('cardLarge-row2')}</p>
<div className="bar__container">
<div className="graph__bar_width_container">
<div className="graph__bar_3"></div>
@@ -47,7 +49,7 @@ export const Analytics: React.FC<any> = ({ text }) => {
</div>
<div className="graph__bar_row">
<p className="graph__caption">{cardLarge.row3}</p>
<p className="graph__caption">{t('cardLarge-row3')}</p>
<div className="bar__container">
<div className="graph__bar_width_container">
<div className="graph__bar_4"></div>
@@ -58,57 +60,57 @@ export const Analytics: React.FC<any> = ({ text }) => {
</div>
</div>
<div className="graph__row_item">
<span className="graph__title title_2">{cardLarge1.title}</span>
<span className="graph__title title_2">{t('cardLarge1-title')}</span>
<div className="chart__container">
<PieChartComp />
<div className="legend__container">
<div className="legend__row">
<div className="legend__point color"></div>
<p className="legend__caption">{cardLarge1.row}</p>
<p className="legend__caption">{t('cardLarge1-row')}</p>
</div>
<div className="legend__row">
<div className="legend__point color1"></div>
<p className="legend__caption">{cardLarge1.row1}</p>
<p className="legend__caption">{t('cardLarge1-row1')}</p>
</div>
<div className="legend__row">
<div className="legend__point color2"></div>
<p className="legend__caption">{cardLarge1.row2}</p>
<p className="legend__caption">{t('cardLarge1-row2')}</p>
</div>
<div className="legend__row">
<div className="legend__point color3"></div>
<p className="legend__caption">{cardLarge1.row3}</p>
<p className="legend__caption">{t('cardLarge1-row3')}</p>
</div>
<div className="legend__row">
<div className="legend__point color4"></div>
<p className="legend__caption">{cardLarge1.row4}</p>
<p className="legend__caption">{t('cardLarge1-row4')}</p>
</div>
</div>
</div>
</div>
<div className="graph__row_item">
<span className="graph__title">{cardLarge2.title}</span>
<span className="graph__title">{t('cardLarge2-title')}</span>
<div className="sales__container">
<div className="sales__row">
<div className="background__row">
<div className="sales__bar">{cardLarge2.row}</div>
<div className="sales__bar">{t('cardLarge2-row')}</div>
</div>
<div className="sales__procentage"></div>
</div>
<div className="sales__row">
<div className="background__row">
<div className="sales__bar sales_bar_width">{cardLarge2.row1}</div>
<div className="sales__bar sales_bar_width">{t('cardLarge2-row1')}</div>
</div>
<div className="sales__procentage">93,47%</div>
</div>
<div className="sales__row">
<div className="background__row">
<div className="sales__bar sales_bar_width1">{cardLarge2.row2}</div>
<div className="sales__bar sales_bar_width1">{t('cardLarge2-row2')}</div>
</div>
<div className="sales__procentage">45,68%</div>
</div>
<div className="sales__row">
<div className="background__row">
<div className="sales__bar sales_bar_width3">{cardLarge2.row3}</div>
<div className="sales__bar sales_bar_width3">{t('cardLarge2-row3')}</div>
</div>
<div className="sales__procentage">29,13%</div>
</div>
@@ -118,38 +120,38 @@ export const Analytics: React.FC<any> = ({ text }) => {
</div>
<div className="graph__row_2">
<div className=" graph__row_item_s">
<span className="graph__title_s">{cardSmall.title}</span>
<span className="graph__title_s">{t('cardSmall-title')}</span>
<div className="graph__color_elem">
12:45
</div>
</div>
<div className="graph__row_item_s">
<span className="graph__title_s">{cardSmall1.title}</span>
<span className="graph__title_s">{t('cardSmall1-title')}</span>
<div className="graph__color_elem">
856
</div>
</div>
<div className=" graph__row_item_s">
<span className="graph__title_s">{cardSmall2.title}</span>
<span className="graph__title_s">{t('cardSmall2-title')}</span>
<div className="graph__color_elem">
12,44
</div>
</div>
<div className="graph__row_item_s">
<span className="graph__title_s">{cardSmall3.title}</span>
<span className="graph__title_s">{t('cardSmall3-title')}</span>
<div className="graph__color_elem">
134,5
</div>
</div>
<div className=" graph__row_mobile graph__row_item_l">
<div className="graph__text">{text.mainBlockSubblock}</div>
<div className="graph__text">{t(`${text}-mainBlockSubblock`)}</div>
</div>
</div>
</div>
<div className="main-block_subblock">
<div className="graph__text_mobile">{text.mainBlockSubblock}</div>
<Button text={text}></Button>
<div className="graph__text_mobile">{t(`${text}-mainBlockSubblock`)}</div>
<Button></Button>
</div>
</div>
@@ -3,8 +3,11 @@ import "./animationComponent.css"
import "../../styles/styles.css"
import "./mapblock.css"
import { Button } from "../buttonDemo/buttonDemo"
import { useTranslation } from 'react-i18next';
export const AnimationComponent: React.FC<any> = () => {
const { t } = useTranslation()
export const AnimationComponent: React.FC<any> = ({ text }) => {
return (
<div>
<div className="animation-container">
@@ -18,9 +21,9 @@ export const AnimationComponent: React.FC<any> = ({ text }) => {
</div>
<span className="title__caption">
{text.titleCaption}
{t('main-titleCaption')}
</span>
<Button text={text}></Button>
<Button></Button>
</div>
</div>
</div>
+22 -12
View File
@@ -1,16 +1,26 @@
import { Link } from "react-router-dom";
import iconButton from '../../styles/iconButton.svg'
import '../../styles/styles.css'
import { useTranslation } from 'react-i18next';
import { useAppSelector, useAppDispatch } from "../../hooks/redux";
export const Button: React.FC<any> = () => {
const { currentLang } = useAppSelector((state) => state.languageReducer);
const { t } = useTranslation()
return (
<a href={`https://stream.graff.tech/?lang=${currentLang}`} className="link">
<button className="main-block__button">
{t('main-button')}
<div className="main-block__icon_container">
<img alt="icon" src={iconButton} className="main-block__icon"></img>
</div>
</button>
</a>
)
}
export const Button: React.FC<any> = ({text}) => {
return (
<a href="https://stream.graff.tech/" className="link">
<button className="main-block__button">
{text.button}
<div className="main-block__icon_container">
<img alt="icon" src={iconButton} className="main-block__icon"></img>
</div>
</button>
</a>
)
}
+10 -7
View File
@@ -5,8 +5,9 @@ import point0 from "./Ellipse0.svg";
import point1 from "./Ellipse1.svg";
import { TProps } from "../calendarDesktop/calendarDesktop";
import { useSwiper } from 'swiper/react';
import { useTranslation } from "react-i18next";
export const Calendar: React.FC<TProps> = ({ open, setOpen, time, onUpdate, isMobile, locale, text }) => {
export const Calendar: React.FC<TProps> = ({ open, setOpen, time, onUpdate, isMobile, locale }) => {
const swiper = useSwiper();
const [calendar, setCalendar] = useState<any[]>([]);
const [value, setValue] = useState(time);
@@ -25,8 +26,8 @@ export const Calendar: React.FC<TProps> = ({ open, setOpen, time, onUpdate, isMo
useEffect(() => {
setValue(time.locale(locale as string))
}, [locale])
}, [locale])
useEffect(() => {
const day = startDay.clone().subtract("1", "day");
@@ -86,11 +87,13 @@ export const Calendar: React.FC<TProps> = ({ open, setOpen, time, onUpdate, isMo
}
return (<div data-aos="fade-up" className='calendar'>
const { t } = useTranslation()
return (<div data-aos="fade-up" className='calendar'>
<div className={open.calendar ? 'opacity_active' : 'opacity'}>
<div className="calendar__header">
<span className="calendar__caption calendar__caption_calendar">
{text.calendarCaption}
{t('calendarCaption')}
</span>
<div className="line"></div>
</div>
@@ -134,11 +137,11 @@ export const Calendar: React.FC<TProps> = ({ open, setOpen, time, onUpdate, isMo
<div className="appointment__block">
<div>
<img alt="point" className="point" src={point1}></img>
<span className="appointment__caption_active">{text.appointmentTrue}</span>
<span className="appointment__caption_active">{t('appointmentTrue')}</span>
</div>
<div>
<img alt="point" className="point" src={point0}></img>
<span className="appointment__caption" >{text.appointmentFalse}</span>
<span className="appointment__caption" >{t('appointmentFalse')}</span>
</div>
</div>
</div>)
@@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M23 12H1M1 12L8.2 5M1 12L8.2 19" stroke="#EBEBEB" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 211 B

+2 -30
View File
@@ -3,35 +3,7 @@
}
.button__arrow_l {
cursor: pointer;
background-image: url(./Arrow_Left.svg);
background-repeat: no-repeat;
background-position: center;
height: 14px;
width: 22px;
}
.button__arrow_r {
-webkit-transform: matrix(-1, 0, 0, 1, 0, 0);
-ms-transform: matrix(-1, 0, 0, 1, 0, 0);
transform: matrix(-1, 0, 0, 1, 0, 0);
cursor: pointer;
background-image: url(./Arrow_Left.svg);
background-repeat: no-repeat;
background-position: center;
height: 14px;
width: 22px;
}
.button__arrow_r:hover {
background-image: url(../calendar/arrow_active1.png);
}
.button__arrow_l:hover {
background-image: url(../calendar/arrow_active1.png);
}
.button__arrow_back {
cursor: pointer;
@@ -139,11 +111,11 @@
-ms-flex-direction: column;
flex-direction: column;
color: #ebebeb;
color: #F2F2F2;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 385px;
background: #141414;
background: #1C1D21;
border-radius: 16px;
padding: 24px 32px;
box-sizing: border-box;
@@ -9,6 +9,7 @@ import "../../styles/styles.css";
import { Confirm } from "../confirm/confirm";
import { Calendar } from "../calendar/calendar";
import { Content } from '../content/content'
import { useTranslation } from "react-i18next";
export type TProps = {
@@ -36,14 +37,13 @@ export const CalendarDesktop: React.FC<TProps> = ({
text,
locale
}) => {
console.log(text, 'here2')
const {t} = useTranslation()
return (
<div className="calendar__container">
<Content text={text}></Content>
<Content isColorCaption={true} text={text}></Content>
<div className="wrapper">
<Calendar
text={text}
setDisplayForm={setDisplayForm}
displayForm={displayForm}
open={open}
@@ -56,7 +56,6 @@ export const CalendarDesktop: React.FC<TProps> = ({
/>
<Timepicker
text={text}
setDisplayForm={setDisplayForm}
displayForm={displayForm}
open={open}
@@ -68,7 +67,6 @@ export const CalendarDesktop: React.FC<TProps> = ({
></Timepicker>
<Form
text={text}
setDisplayForm={setDisplayForm}
displayForm={displayForm}
open={open}
@@ -80,7 +78,6 @@ export const CalendarDesktop: React.FC<TProps> = ({
></Form>
<Confirm
text={text}
setDisplayForm={setDisplayForm}
displayForm={displayForm}
open={open}
@@ -93,7 +90,7 @@ export const CalendarDesktop: React.FC<TProps> = ({
</div>
<div className="main-block__subblock-container">
<div className="main-block_subblock">
{text.mainBlockSubblock}
{t('calendar-mainBlockSubblock')}
</div>
</div>
</div>
@@ -11,6 +11,7 @@ import "swiper/css/pagination";
import "swiper/css/navigation";
import "./calendarMobile.css"
import { Content } from "../content/content";
import { useTranslation } from "react-i18next";
@@ -18,11 +19,12 @@ import { Content } from "../content/content";
export const CalendarMobile: React.FC<TProps> = ({ setDisplayForm, displayForm, open, setOpen, onUpdate, time, onExit, isMobile, text, locale }) => {
const { t } = useTranslation()
return (
<div className="calendar__mobile">
<div className="calendar__container">
<div className="slider">
<Content text={text}></Content>
<Content isColorCaption={true} text={text}></Content>
</div>
<Swiper
rewind={true}
@@ -87,7 +89,7 @@ export const CalendarMobile: React.FC<TProps> = ({ setDisplayForm, displayForm,
</Swiper>
<div className="main-block__subblock-container calendar__padding">
<div className="main-block_subblock">
{text.mainBlockSubblock}
{t('calendar-mainBlockSubblock')}
</div>
</div>
</div>
@@ -5,8 +5,7 @@
.block__container {
overflow: hidden;
background: #141414;
border-radius: 32px;
background: #1C1D21; border-radius: 32px;
padding: 74px 80px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
@@ -1,9 +1,11 @@
import './cloudSolution.css'
import "../../styles/styles.css";
import serverFrame from './serverFrame.png'
import { useTranslation } from 'react-i18next';
export const CloudSolution: React.FC<any> = ({ text }) => {
const {t} = useTranslation()
return (
<div data-aos="zoom-in" data-aos-duration="500" className="cloud__container">
<div className='block__container'>
@@ -17,11 +19,11 @@ export const CloudSolution: React.FC<any> = ({ text }) => {
Graff.estate stream
</p>
<p className=" main-block__title_gardient_small width cloud__title">
{text.title}
{t('cloudSolution-title')}
</p>
</div>
<p className="main-block__caption cloud__caption">
{text.mainBlockCaption}
{t('cloudSolution=mainBlockCaption')}
</p>
</div>
</div>
+7 -4
View File
@@ -1,13 +1,16 @@
import '../form/form.css'
import { TProps } from "../calendarDesktop/calendarDesktop";
import { useSwiper } from 'swiper/react';
import { useTranslation } from 'react-i18next';
export const Confirm: React.FC<TProps> = ({ open, onExit, setOpen, isMobile, text }) => {
export const Confirm: React.FC<TProps> = ({ open, onExit, setOpen, isMobile }) => {
const swiper = useSwiper();
const {t} = useTranslation()
function exit() {
if (isMobile) {
swiper.slideNext()
@@ -20,14 +23,14 @@ export const Confirm: React.FC<TProps> = ({ open, onExit, setOpen, isMobile, tex
return (<div className={open.confirm ? "confirm" : "confirm__none"}>
<div className="confirm__container">
<h2 className="confirm__title">
{text.confirm.title}
{t("confirm-title")}
</h2>
<p className="confirm__caption">
{text.confirm.caption}
{t("confirm-caption")}
</p>
</div>
<button onClick={exit} className="button__submit">
{text.buttons.next}
{t("buttons-next")}
</button>
</div>
)
+8 -7
View File
@@ -1,20 +1,21 @@
import { useTranslation } from "react-i18next";
import "../../styles/styles.css";
export const Content: React.FC<any> = ({ text, captionSmall }) => {
export const Content: React.FC<any> = ({ text, captionSmall, isColorCaption }) => {
const { t } = useTranslation()
return (
<div data-aos="fade-up"
data-aos-delay="400"
className="main-block__container">
<p className="main-block__title_small">
Graff.estate stream{" "}
<p className="main-block__title_gardient_small">{text.title}</p>
<p className="main-block__title_gardient_small">{t(`${text}-title`)}</p>
</p>
{text.mainBlockCaptionColor ? <p className=" main-block__caption_color">
{text.mainBlockCaptionColor}
</p>
: <></>}
{isColorCaption ? <p className=" main-block__caption_color">
{t(`${text}-mainBlockCaptionColor`)}
</p> : <></>}
<p className={captionSmall ? "main-block__caption main-block__caption_small" : "main-block__caption"}>
{text.mainBlockCaption}
{t(`${text}-mainBlockCaption`)}
</p>
</div>
)
+6 -7
View File
@@ -35,7 +35,7 @@
}
.demos_container {
background: #141414;
background: #1C1D21;
border-radius: 16px;
}
@@ -52,6 +52,7 @@
}
.demo_image {
object-fit: cover;
background: -webkit-gradient(linear, left bottom, left top, from(rgba(0, 0, 0, 0.3)), to(rgba(0, 0, 0, 0.3)));
background: -o-linear-gradient(bottom, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.3));
background: linear-gradient(0deg, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.3));
@@ -88,7 +89,7 @@
/* Landing/White */
color: #EBEBEB;
color: #F2F2F2;
}
.caption {
@@ -102,7 +103,7 @@
/* Landing/White */
color: #EBEBEB;
color: #F2F2F2;
opacity: 0.5;
@@ -120,7 +121,7 @@
/* Landing/White */
color: #EBEBEB;
color: #F2F2F2;
}
.caption2 {
@@ -135,7 +136,7 @@
/* Landing/White */
color: #EBEBEB;
color: #F2F2F2;
opacity: 0.5;
}
@@ -232,8 +233,6 @@
.demo_image {
height: auto;
-o-object-fit: cover;
object-fit: cover;
width: 240px;
}
}
+25 -40
View File
@@ -3,56 +3,41 @@ import "../../styles/styles.css";
import building1 from './building1.png'
import building2 from './building2.png'
import { useAppDispatch, useAppSelector } from "../../hooks/redux";
import iconButton from "./iconButton.svg"
import { useTranslation } from 'react-i18next';
export const Demos: React.FC<any> = ({ text }) => {
const { card, card1 } = text;
console.log(text)
export const Demos: React.FC<any> = ({ cards }) => {
const { currentLang } = useAppSelector((state) => state.languageReducer);
const {t} = useTranslation()
return (<div className=" demo__container_mobile main-block__container width demo__container">
<h3 className='demos__tittle'>
{text.title}
{t('demo-title')}
</h3>
<a href='https://stream.graff.tech/' target='_blank' rel="noreferrer" data-aos="fade-up"
data-aos-delay="100" className='demos_container'>
<div className="main-block__icon_container demo__icon">
<img alt='icon' src={iconButton} className="main-block__icon"></img>
</div>
<div className='demo'>
<img alt='buildingImg' src={building1} className='demo_image'></img>
<div className='demo_info'>
<div className='title__block'>
<h4 className='title__demo'>{card.title}</h4>
<p className='caption'>{card.subTitle}</p>
</div>
<div className='body__block'>
<p className='caption1'>{card.caption}</p>
<p className='caption2'>{card.caption1}</p>
{cards.map((i: any) => (
<a href={`https://stream.graff.tech/?lang=${currentLang}`} target='_blank' rel="noreferrer" data-aos="fade-up"
data-aos-delay="100" className='demos_container'>
<div className="main-block__icon_container demo__icon">
<img alt='icon' src={iconButton} className="main-block__icon"></img>
</div>
<div className='demo'>
<img alt='buildingImg' src={i.preview} className='demo_image'></img>
<div className='demo_info'>
<div className='title__block'>
<h4 className='title__demo'>{i.title}</h4>
<p className='caption'>{i.location}</p>
</div>
<div className='body__block'>
<p className='caption1'>{i.description}</p>
{i.feature_description ? <p className='caption2'>{i.feature_description}</p> : <p></p>}
</div>
</div>
</div>
</div>
</a>
<a href='https://stream.graff.tech/' target='_blank' rel="noreferrer" data-aos="fade-up"
data-aos-delay="150" className='demos_container'>
<div className="main-block__icon_container demo__icon">
<img alt='icon' src={iconButton} className="main-block__icon"></img>
</div>
<div className='demo'>
<img alt='buildingImg' src={building2} className='demo_image'></img>
<div className='demo_info'>
<div className='title__block'>
<h4 className='title__demo'>{card1.title}</h4>
<p className='caption'>{card1.subTitle}</p>
</div>
<div className='body__block'>
<p className='caption1'>{card1.caption}</p>
<p className='caption2'>{card1.caption1}</p>
</div>
</div>
</div>
</a>
</a>
))}
</div>
)
Binary file not shown.

After

Width:  |  Height:  |  Size: 382 KiB

+2 -3
View File
@@ -34,8 +34,7 @@
flex-direction: column;
height: 380px;
padding: 32px;
background: #141414;
border-radius: 16px;
background: #1C1D21; border-radius: 16px;
gap: 20px;
}
@@ -67,7 +66,7 @@
/* Landing/White */
color: #ebebeb;
color: #C5C7CE;
opacity: 0.8;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 639 KiB

After

Width:  |  Height:  |  Size: 669 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 433 KiB

After

Width:  |  Height:  |  Size: 437 KiB

+6 -5
View File
@@ -9,7 +9,7 @@
-webkit-box-sizing: border-box;
box-sizing: border-box;
background-color: transparent;
background: #141414;
background: #1C1D21;
border-radius: 32px 32px 0px 0px;
color: #EBEBEB;
display: -webkit-box;
@@ -30,7 +30,7 @@
display: -webkit-box;
display: -ms-flexbox;
display: flex;
padding: 120px 120px;
padding: 0 120px;
gap: 186px;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
@@ -173,7 +173,7 @@
}
.footer__card_l {
background: #1E1E1E;
background: #2E3038;
border-radius: 16px;
padding: 32px;
margin-bottom: 30px;
@@ -190,6 +190,7 @@
}
.footer__card_2 {
-webkit-box-sizing: border-box;
box-sizing: border-box;
cursor: pointer;
@@ -205,8 +206,8 @@
/* Gray */
color: #E3DDE5;
border: 1px solid #454545;
color: #FFFFFF;
border: 1px solid #73788C;
border-radius: 16px;
}
-1
View File
@@ -22,7 +22,6 @@ export const Footer: React.FC<any> = ({ text, language }) => {
<p className='contacts__title'>{text.social}</p>
<div className='footer__container_social'>
<a href='https://www.facebook.com/GRAFFinteractive' target='_blank' rel="noreferrer" className='footer__social'>Facebook</a>
<a href='https://www.instagram.com/graffinteractive/' target='_blank' rel="noreferrer" className='footer__social'>Instagram</a>
<a href='https://www.youtube.com/channel/UCveYBNLVeGxgsDsfhrVxNoA' target='_blank' rel="noreferrer" className='footer__social'>YouTube</a>
<a href='https://vk.com/graffinteractive' target='_blank' rel="noreferrer" className='footer__social'>VK</a>
</div>
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 17 KiB

+2 -2
View File
@@ -1,6 +1,5 @@
.form__container {
width: 385px;
color: #ebebeb;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
@@ -11,7 +10,8 @@
padding: 24px 32px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
background: #141414;
background: #1C1D21;
color: #F2F2F2;
border-radius: 16px;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
+10 -8
View File
@@ -3,9 +3,10 @@ import "../timepicker/timepicker.css"
import "../../index.css"
import { TProps } from "../calendarDesktop/calendarDesktop";
import { useSwiper } from 'swiper/react';
import { useTranslation } from "react-i18next";
export const Form: React.FC<TProps> = ({ time, open, setOpen, displayForm, setDisplayForm, isMobile, text }) => {
export const Form: React.FC<TProps> = ({ time, open, setOpen, displayForm, setDisplayForm, isMobile }) => {
const swiper = useSwiper();
@@ -37,7 +38,7 @@ export const Form: React.FC<TProps> = ({ time, open, setOpen, displayForm, setDi
form: false,
confirm: true
})
swiper.slideNext()
swiper.slideNext()
} else {
setDisplayForm(false)
setOpen({
@@ -45,11 +46,12 @@ export const Form: React.FC<TProps> = ({ time, open, setOpen, displayForm, setDi
timePicker: false,
form: false,
confirm: true
})
})
}
}
const { t } = useTranslation()
return (
@@ -58,7 +60,7 @@ export const Form: React.FC<TProps> = ({ time, open, setOpen, displayForm, setDi
<div className="timepicker__header">
<div className="caption__container">
<div onClick={goBack} className="button__arrow_back"></div>
<span className="calendar__caption">{text.formCaption}</span>
<span className="calendar__caption">{t('formCaption')}</span>
</div>
<div className="line line_time"></div>
<div className="date date_time">{!open.form ? '' : time.format("DD MMM, HH:mm")}</div>
@@ -70,26 +72,26 @@ export const Form: React.FC<TProps> = ({ time, open, setOpen, displayForm, setDi
name="tel"
className="form__input"
type="text"
placeholder={text.placeholders.name}
placeholder={t('placeholders-phoneNumber') as string}
></input>
<input
name="email"
className="form__input"
type="number"
placeholder={text.placeholders.phoneNumber}
placeholder={t('placeholders-email') as string}
></input>
<input
name="name"
className="form__input"
type="email"
placeholder={text.placeholders.email}
placeholder={t('placeholders-name') as string}
></input>
</form>
</div>
</div>
</div>
<button onClick={handleConfirm} disabled={!open.form} type="submit" className={open.form ? 'button__submit' : 'button__submit button__submit_disabled'}>
{text.buttons.plan}
{t('buttons-plan')}
</button>
</div>
);
+4
View File
@@ -0,0 +1,4 @@
<svg width="20" height="13" viewBox="0 0 20 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 13C0.447716 13 0 12.5523 0 12V1C0 0.447715 0.447715 0 1 0H6.82201C7.28827 0 7.66624 0.377978 7.66624 0.844238V0.844238C7.66624 1.3105 7.28827 1.68848 6.82201 1.68848H2.34491C2.06877 1.68848 1.84491 1.91233 1.84491 2.18848V5.14941C1.84491 5.42556 2.06877 5.64941 2.34491 5.64941H6.42515C6.88966 5.64941 7.26621 6.02597 7.26621 6.49048V6.49048C7.26621 6.95499 6.88966 7.33154 6.42515 7.33154H2.34491C2.06877 7.33154 1.84491 7.5554 1.84491 7.83154V10.8115C1.84491 11.0877 2.06877 11.3115 2.34491 11.3115H6.89365C7.35991 11.3115 7.73789 11.6895 7.73789 12.1558V12.1558C7.73789 12.622 7.35991 13 6.89365 13H1Z" fill="#F2F2F2"/>
<path d="M19.0865 0C19.591 0 20 0.408988 20 0.913501V12C20 12.5523 19.5523 13 19 13H18.8462C18.5082 13 18.193 12.8293 18.0085 12.5461L12.1107 3.49922C12.0972 3.47838 12.074 3.46582 12.0491 3.46582V3.46582C12.0085 3.46582 11.9755 3.49876 11.9755 3.5394V12.0775C11.9755 12.587 11.5625 13 11.0531 13V13C10.5436 13 10.1306 12.587 10.1306 12.0775V1C10.1306 0.447715 10.5783 0 11.1306 0H11.2963C11.6343 0 11.9495 0.170802 12.1341 0.454032L18.0378 9.51347C18.0514 9.53431 18.0746 9.54687 18.0994 9.54687V9.54687C18.1401 9.54687 18.173 9.51394 18.173 9.4733V0.913501C18.173 0.408988 18.582 0 19.0865 0V0Z" fill="#F2F2F2"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+4
View File
@@ -0,0 +1,4 @@
<svg width="20" height="13" viewBox="0 0 20 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.897734 12.7877C0.401929 12.7877 0 12.3858 0 11.89V0.999999C0 0.447714 0.447715 0 1 0H4.24172C5.16366 0 5.92872 0.170669 6.5369 0.512008C7.14894 0.853346 7.60604 1.32581 7.90819 1.92939C8.21034 2.52882 8.36142 3.2219 8.36142 4.00865C8.36142 4.79123 8.20841 5.48015 7.90238 6.07541C7.60023 6.66651 7.14313 7.12648 6.53109 7.45533C5.92291 7.78418 5.15785 7.94861 4.23591 7.94861H1.85311C1.39447 7.94861 1.02266 7.5768 1.02266 7.11816C1.02266 6.65951 1.39447 6.2877 1.85311 6.2877H4.07321C4.65427 6.2877 5.12686 6.19821 5.49099 6.01921C5.859 5.84022 6.12822 5.58005 6.29866 5.23871C6.46911 4.89737 6.55433 4.48735 6.55433 4.00865C6.55433 3.52578 6.46717 3.10743 6.29285 2.7536C6.12241 2.39978 5.85319 2.1292 5.48518 1.94188C5.12105 1.7504 4.64265 1.65466 4.04997 1.65466H2.29547C2.01933 1.65466 1.79547 1.87852 1.79547 2.15466V11.89C1.79547 12.3858 1.39354 12.7877 0.897734 12.7877ZM5.32848 7.01825C5.66354 7.01825 5.97028 7.20621 6.12241 7.50474L8.14113 11.4661C8.44931 12.0708 8.01003 12.7877 7.3313 12.7877C6.9869 12.7877 6.67209 12.5931 6.51818 12.285L4.53132 8.30754C4.23536 7.71508 4.66621 7.01825 5.32848 7.01825Z" fill="#F2F2F2"/>
<path d="M18.1987 0.900639C18.1987 0.403229 18.602 0 19.0994 0C19.5968 0 20 0.40323 20 0.900639V8.41066C20 9.30564 19.8044 10.0986 19.4131 10.7896C19.0219 11.4765 18.4718 12.0176 17.7629 12.4131C17.054 12.8044 16.2231 13 15.2702 13C14.3211 13 13.4922 12.8044 12.7833 12.4131C12.0744 12.0176 11.5243 11.4765 11.1331 10.7896C10.7418 10.0986 10.5462 9.30564 10.5462 8.41066V0.897733C10.5462 0.401929 10.9481 0 11.4439 0C11.9397 0 12.3417 0.401929 12.3417 0.897734V8.25456C12.3417 8.83317 12.4598 9.34726 12.6961 9.79683C12.9363 10.2464 13.2752 10.6002 13.713 10.8583C14.1507 11.1122 14.6698 11.2392 15.2702 11.2392C15.8745 11.2392 16.3955 11.1122 16.8332 10.8583C17.2748 10.6002 17.6119 10.2464 17.8443 9.79683C18.0806 9.34726 18.1987 8.83317 18.1987 8.25456V0.900639Z" fill="#F2F2F2"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

+93 -111
View File
@@ -1,32 +1,53 @@
/*
* Prefixed by https://autoprefixer.github.io
* PostCSS: v8.4.14,
* Autoprefixer: v10.4.7
* Browsers: last 4 version
*/
.header-container {
display: -webkit-box;
display: -ms-flexbox;
.header {
box-sizing: border-box;
width: 100%;
display: flex;
padding: 30px 40px;
color: #ffffff;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
position: relative;
}
.header-popup {
position: absolute;
}
.header-button-container {
display: flex;
gap: 8px;
}
.button-lang {
background: transparent;
border: none;
outline: none;
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
box-sizing: border-box;
border-radius: 4px;
padding: 10px 14px;
}
.button-lang:hover {
background: #23242A;
}
.button-lang-active {
cursor: pointer;
pointer-events: none;
background: #2E3038;
}
.header__buttons_wrapper {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
gap: 40px;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
@@ -35,73 +56,48 @@
}
.header-logo {
width: 31px;
height: 50px;
width: 104px;
height: 40px;
}
.header-buttons {
margin-right: 96px;
}
.header-button {
font-family: "GilroyWebRegular";
font-style: normal;
font-weight: 400;
font-size: 16px;
line-height: 125%;
background-color: transparent;
border: none;
color: #ffffff;
cursor: pointer;
padding: 0px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
text-decoration: none;
}
.header-lang-button-text:hover {
background: rgba(235, 235, 235, 0.2);
}
.wrapper__button {
margin: 0;
height: 15px;
}
.header-lang-button {
position: absolute;
right: 40px;
top: 40px;
overflow: hidden;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
gap: 10px;
width: 58px;
padding: 5px 12px;
-webkit-box-sizing: border-box;
width: 55px;
padding: 6px 8px 5px 12px;
box-sizing: border-box;
height: 31px;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
height: 29px;
justify-content: space-between;
box-sizing: border-box;
line-height: 13px;
background-color: transparent;
border: 1.2px solid #ebebeb;
border: 2px solid #ebebeb;
border-radius: 12px;
-webkit-transition: height ease-in 0.3s;
-o-transition: height ease-in 0.3s;
transition: height ease-in 0.3s;
font-style: normal;
font-weight: 500;
font-size: 15px;
line-height: 130%;
transition: height ease-in 0.5s;
}
.header-lang-button_disabled {
@@ -109,7 +105,7 @@
}
.header-lang-button_active {
height: 53px;
height: 51px;
}
.header-lang-button_active {
@@ -117,8 +113,8 @@
}
.header-lang-button-text {
width: 100%;
-moz-appearance: none;
appearance: none;
background-color: transparent;
color: #ebebeb;
@@ -126,54 +122,29 @@
text-align: left;
margin: 0;
border: none;
height: 15px;
height: 13px;
-webkit-appearance: none;
font-style: normal;
font-weight: 500;
font-size: 15px;
line-height: 130%;
cursor: pointer;
}
.header-lang-button-picked {
width: 100%;
-moz-appearance: none;
appearance: none;
background-color: transparent;
color: #ebebeb;
padding: 0;
text-align: left;
margin: 0;
border: none;
height: 100%;
-webkit-appearance: none;
font-style: normal;
font-weight: 500;
font-size: 15px;
line-height: 130%;
cursor: pointer;
}
.header-select__icon {
top: 6px;
height: 16px;
height: 13px;
right: 5px;
position: absolute;
}
.select {
background-color: transparent;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-ms-flex-item-align: center;
-ms-grid-row-align: center;
align-self: center;
gap: 11px;
position: relative;
@@ -187,9 +158,10 @@
.option {
/* or 16px */
/* Landing/White */
color: #ebebeb;
color: #EBEBEB;
}
.burger__button {
@@ -197,34 +169,31 @@
cursor: pointer;
background-color: transparent;
display: none;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
gap: 5px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.line__burger {
background-color: #ffffff;
background-color: #FFFFFF;
width: 14px;
height: 1px;
}
@media screen and (min-width: 1600px) {
.header-container {
.header {
padding: 35px 48px;
}
.header-logo {
width: 46px;
height: 74px;
cursor: pointer;
}
.header-button {
font-size: 20px;
}
.header-lang-button_active {
height: auto;
}
.header-buttons {
@@ -232,45 +201,58 @@
}
.header-lang-button {
width: 70px;
padding: 7px 15px;
top: 57px;
width: 60px;
}
}
@media screen and (max-width: 1279px) {
.header-container {
.header {
padding: 30px 12px;
}
.header-lang-button {
top: 40px;
right: 12px;
}
}
@media screen and (max-width: 1024px) {
.header-container {
.header {
padding: 15px 12px;
}
.header-lang-button {
right: 12px;
top: 26px;
top: 25%;
}
}
@media screen and (max-width: 639px) {
.header-container {
.header-logo {
width: 94px;
height: 36px;
}
.header-popup {
position: static;
}
.header {
padding: 8px 10px;
}
.header-buttons {
display: none;
}
.burger__button {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
}
+27 -94
View File
@@ -1,106 +1,39 @@
import React, { CSSProperties, useState } from "react";
import "./Header.css";
import logo from "./logoIcon.svg";
import chevron from "./chevronIcon.svg";
import "./header.css";
import "../../styles/styles.css";
import iconClose from './closeIcon1.svg'
import { Nav } from "../Navigaton/navigation";
import { useLocation, useHistory } from "react-router-dom";
import ru from './RU.svg'
import en from './EN.svg'
import { useAppSelector, useAppDispatch } from "../../hooks/redux";
import { languageSlice } from "../../store/reducers/languageSlice";
import { useLocation } from "react-router-dom";
export type THeader = {
language: string;
changeLanguage: (language: string) => void;
text?: any;
};
export const Header: React.FC<THeader> =
({ changeLanguage, language, text }) => {
const [open, setOpen] = useState<boolean>(false)
const [menuOpen, setMenuOpen] = useState(false)
const [opacity, setOpacity] = useState(false)
const userLanguage = language === 'RU';
export const Header: React.FC = ({ }) => {
const buttons = [{
icon: ru, value: "ru"
}, { icon: en, value: "en" }]
const location = useLocation();
const location = useLocation()
const history = useHistory()
console.log(location, 'loc')
function handleUpdateLanguage(value: string) {
changeLanguage(value)
setOpen(prev => !prev)
}
function handleOpen() {
setOpen(prev => !prev)
}
function handleOpacity() {
setOpacity(true)
}
const style = {
background: 'rgba(235, 235, 235, 0.2'
};
const iconTransform = {
transform: 'rotate(-90deg)'
} as CSSProperties
const setBackground = opacity && !open as boolean;
function setOpacityAndMenu() {
setMenuOpen(true)
const targetElement = document.querySelector('body') as HTMLElement
targetElement.style.overflow = 'hidden'
}
const { handleChangeLanguage } = languageSlice.actions;
const { currentLang } = useAppSelector((state) => state.languageReducer);
const dispatch = useAppDispatch();
function openMenu() {
setMenuOpen(false)
const targetElement = document.querySelector('body') as HTMLElement
targetElement.style.overflow = 'visible'
}
function goBack() {
if (location.pathname === '/demos') {
history.goBack()
} else {
window.location.reload();
}
}
return (
<div className="header">
<div className="header-container">
<img onClick={goBack} className="header-logo" alt="company-logo" src={logo} />
<div className="header-buttons">
<div className="header__buttons_wrapper">
<a target='_blank' rel="noreferrer" href={userLanguage ? 'https://graff.tech/contacts/' : 'http://en.graff.tech/contactseng' } className="header-button">{text.captionContact}</a>
<a target='_blank' rel="noreferrer" href={userLanguage ? 'https://graff.tech/' : 'http://en.graff.tech/' } className="header-button">{text.captionCompain}</a>
</div>
<div className={open ? "header-lang-button header-lang-button_active" : 'header-lang-button header-lang-button_disabled'} style={setBackground ? style : { background: 'transparent' }}>
<img alt="img" src={chevron} className="header-select__icon" style={open ? iconTransform : {
transform: 'rotate(0deg)'
}}></img>
<div className="wrapper__button">
<button onMouseEnter={handleOpacity} onMouseLeave={() => setOpacity(false)} onClick={handleOpen} className=" header-lang-button-picked">{language}</button>
</div>
{language === 'RU' ? (<button value={'EN'} onClick={(e: any) => handleUpdateLanguage(e.target.value)} className="header-lang-button-text">EN</button>
) : (<button onClick={(e: any) => handleUpdateLanguage(e.target.value)} value={'RU'} className="header-lang-button-text">RU</button>)}
</div>
</div>
{menuOpen ? <img alt="iconClose" src={iconClose} onClick={openMenu} className='nav__close'></img>
:
<button onClick={setOpacityAndMenu} className="burger__button">
<span className="line__burger"></span>
<span className="line__burger"></span>
<span className="line__burger"></span>
</button>}
</div>
<Nav text={text} setOpacity={setOpacity} language={language} menuOpen={menuOpen} setOpen={setMenuOpen} changeLanguage={changeLanguage}></Nav>
return (
<header className={location.pathname === '/' ? 'header' : 'header header-popup'}>
<a className="header-logo" target='_blank' href="https://estate.graff.tech/" style={{ cursor: "pointer" }}><img alt="company-logo" src={logo} />
</a>
<div className="header-button-container">
{buttons.map((item, index) => (<button key={index} onClick={() => dispatch(handleChangeLanguage(item.value))} value={item.value} className={currentLang === item.value ? 'button-lang button-lang-active' : "button-lang"}><img src={item.icon}></img></button>
))}
</div>
);
}
</header>
);
};
+14 -12
View File
@@ -12,6 +12,7 @@ import { Demos } from "../demos/demos";
import { PhotoComponent } from "../photoComponent/photoComponent";
import { CalendarMobile } from "../calendarMobile/calendarMobile";
import moment, { Moment } from "moment";
import useScreenSize from 'use-screen-size'
@@ -28,7 +29,7 @@ export type TText = {
text: object,
}
export const Main: React.FC<any> = ({ text, locale }) => {
export const Main: React.FC<any> = ({ locale, cards }) => {
const { width } = useScreenSize()
const [displayForm, setDisplayForm] = useState(true);
@@ -78,14 +79,15 @@ export const Main: React.FC<any> = ({ text, locale }) => {
})
setDisplayForm(true)
}
return (
<main className="main">
<AnimationComponent text={text.title} />
<SliderComponent text={text.slider} />
<AnimationComponent />
<SliderComponent />
<div className="calendar__mobile">
<CalendarMobile
locale={locale}
text={text.calendar}
text={'calendar'}
setDisplayForm={setDisplayForm}
displayForm={displayForm}
setOpen={navigationHandler}
@@ -99,7 +101,7 @@ export const Main: React.FC<any> = ({ text, locale }) => {
<div className="calendar__desktop">
<CalendarDesktop
locale={locale}
text={text.calendar}
text={'calendar'}
setDisplayForm={setDisplayForm}
displayForm={displayForm}
setOpen={navigationHandler}
@@ -110,13 +112,13 @@ export const Main: React.FC<any> = ({ text, locale }) => {
isMobile={isMobile}
></CalendarDesktop>
</div>
<Multiplayer text={text.multiplayer} />
<Devices text={text.devices} />
<PhotoComponent text={text.photoComponent} />
<Player text={text.player} />
<Analytics text={text.analytics} />
<CloudSolution text={text.cloudSolution} />
<Demos text={text.demos} />
<Multiplayer text={'multiplayer'} />
<Devices text={'devices'} />
<PhotoComponent text={'photoComponent'} />
<Player text={'player'} />
<Analytics text={'analytics'} />
<CloudSolution text={'analytics'} />
<Demos cards={cards} />
</main>
);
};
+1 -1
View File
@@ -6,7 +6,7 @@
*/
.multiplayer__container {
background: #141414;
background: #1C1D21;
border-radius: 32px;
padding: 120px 32px 80px;
margin-bottom: 160px;
+4 -2
View File
@@ -7,16 +7,18 @@ import photo3 from "./Photo3.png";
import { Button } from "../buttonDemo/buttonDemo"
import { Content } from "../content/content";
import { useState } from "react";
import { useTranslation } from "react-i18next";
export const Multiplayer: React.FC<any> = ({text}) => {
const [captionSmall, setCaptionSmall] = useState(true);
const {t} = useTranslation()
return (
<div
data-aos="zoom-in"
data-aos-duration="400"
className="multiplayer__container"
>
<Content captionSmall={captionSmall} text={text}></Content>
<Content isColor={false} captionSmall={captionSmall} text={text}></Content>
<div className="multiplayer__photo-container">
<img alt="device" src={photo1} className="multiplayer__image" />
<img alt="device" src={photo} className="multiplayer__image" />
@@ -25,7 +27,7 @@ export const Multiplayer: React.FC<any> = ({text}) => {
</div>
<div className="main-block__subblock-container">
<div className={captionSmall ? " main-block__caption_small main-block_subblock " : 'main-block_subblock'}>
{text.mainBlockSubblock}
{t(`${text}-mainBlockSubblock`)}
<Button text={text}></Button>
</div>
</div>
+1 -2
View File
@@ -6,8 +6,7 @@
*/
.player__container {
background: #141414;
border-radius: 32px;
background: #1C1D21; border-radius: 32px;
padding: 120px 32px 80px;
margin-bottom: 80px;
}
@@ -9,7 +9,7 @@
width: 100%;
margin: 0 auto;
background: #141414;
background: #1C1D21;
border-radius: 32px;
padding-top: 120px;
padding-bottom: 85px;
@@ -1,9 +1,11 @@
import React from "react";
import "./sliderComponent.css";
import "../../styles/styles.css"
import Swiper from "../swiper/swiper";
import Swiper from "../swiper/swiper"
import { useTranslation } from 'react-i18next';
export const SliderComponent: React.FC<any> = React.memo(({ text }) => {
export const SliderComponent: React.FC<any> = () => {
const { t } = useTranslation()
return (
<div data-aos="zoom-in" data-aos-duration="500" className="slider-container">
<div className="slider">
@@ -15,14 +17,13 @@ export const SliderComponent: React.FC<any> = React.memo(({ text }) => {
<p className="main-block__title_gardient title__gardient_pos">stream</p>
</div>
<p className=" main-block__caption_color main-block__caption_color_slider">
{text.mainBlockCaptionColor}
{t('slider-mainBlockCaptionColor')}
</p>
<p className="main-block__caption_l">{text.mainBlockCaption}</p>
<p className="main-block__caption_l">{t('slider-mainBlockCaption')}</p>
</div>
</div>
</div>
<Swiper
text={text}
slidesPerView={'2'}
centeredSlides={false}
spaceBetween={0}
@@ -34,4 +35,4 @@ export const SliderComponent: React.FC<any> = React.memo(({ text }) => {
></Swiper>
</div>
);
});
}
+3
View File
@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M23 12H1M1 12L8.2 5M1 12L8.2 19" stroke="#F2F2F2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 228 B

Before

Width:  |  Height:  |  Size: 215 B

After

Width:  |  Height:  |  Size: 215 B

+24 -1
View File
@@ -10,6 +10,29 @@
width: 536px;
}
.button__arrow_l {
cursor: pointer;
background-image: url(./Arrow_Left.svg);
background-repeat: no-repeat;
background-position: center;
height: 14px;
width: 22px;
}
.button__arrow_r {
-webkit-transform: matrix(-1, 0, 0, 1, 0, 0);
-ms-transform: matrix(-1, 0, 0, 1, 0, 0);
transform: matrix(-1, 0, 0, 1, 0, 0);
cursor: pointer;
background-image: url(./Arrow_Left.svg);
background-repeat: no-repeat;
background-position: center;
height: 14px;
width: 22px;
}
@@ -81,7 +104,7 @@
color: #ebebeb;
display: flex;
color: #ebebeb !important;
color: #F2F2F2 !important;
}
.swiper__caption {
+12 -10
View File
@@ -15,6 +15,7 @@ import "swiper/css";
import "swiper/css/pagination";
import "swiper/css/navigation";
import "../calendar/calendar";
import { useTranslation } from "react-i18next";
type propsTypes = {
slidesPerView: string;
@@ -24,17 +25,18 @@ type propsTypes = {
className: string;
children: React.ReactNode;
rewind: boolean;
text: any;
slideToClickedSlide: boolean,
};
export default function SwiperCentred(props: propsTypes) {
const { t } = useTranslation()
const size = useScreenSize();
const [caption, setCaption] = useState<any>();
useEffect(() => {
setCaption(props.text.subtitle1);
}, [props.text]);
setCaption(t('slider-subtitle1'));
}, [t]);
function updateCaption() {
const slide = document
@@ -82,8 +84,8 @@ export default function SwiperCentred(props: propsTypes) {
<SwiperSlide style={swiperWidth()}>
{({ isActive }) => (
<img
data-caption={props.text.subtitle}
className={isActive ? "image__slider_active" : "image__slider"}
data-caption={t('slider-subtitle')}
className={isActive ? "image__slider_active" : "image__slider"}
src={img1}
alt="slide"
/>
@@ -92,7 +94,7 @@ export default function SwiperCentred(props: propsTypes) {
<SwiperSlide style={swiperWidth()}>
{({ isActive }) => (
<img
data-caption={props.text.subtitle1}
data-caption={t('slider-subtitle1')}
className={isActive ? "image__slider_active" : "image__slider"}
src={img}
alt="slide"
@@ -102,8 +104,8 @@ export default function SwiperCentred(props: propsTypes) {
<SwiperSlide style={swiperWidth()}>
{({ isActive }) => (
<img
data-caption={props.text.subtitle2}
className={isActive ? "image__slider_active" : "image__slider"}
data-caption={t('slider-subtitle2')}
className={isActive ? "image__slider_active" : "image__slider"}
src={img2}
alt="slide"
/>
@@ -112,8 +114,8 @@ export default function SwiperCentred(props: propsTypes) {
<SwiperSlide style={swiperWidth()}>
{({ isActive }) => (
<img
data-caption={props.text.subtitle3}
className={isActive ? "image__slider_active" : "image__slider"}
data-caption={t('slider-subtitle3')}
className={isActive ? "image__slider_active" : "image__slider"}
src={img3}
alt="slide"
/>
+7 -5
View File
@@ -7,6 +7,7 @@ import point0 from "../calendar/Ellipse0.svg";
import point1 from "../calendar/Ellipse1.svg";
import { TProps } from "../calendarDesktop/calendarDesktop";
import { useSwiper } from 'swiper/react';
import { useTranslation } from "react-i18next";
@@ -16,7 +17,6 @@ export const Timepicker: React.FC<TProps> = ({
open,
setOpen,
isMobile,
text
}) => {
@@ -84,16 +84,18 @@ export const Timepicker: React.FC<TProps> = ({
}
}
const { t } = useTranslation()
return (
<div data-aos="fade-up" className={open.timePicker ? " calendar aos-init aos-animate" : "calendar aos-init aos-animate"}>
<div className={open.timePicker ? 'opacity_active' : 'opacity'}>
<div className="timepicker__header">
<div className="caption__container">
<div onClick={() => goBack()} className="button__arrow_back" ></div>
<span className="calendar__caption">{text.timepickerCaption}</span>
<span className="calendar__caption">{t('timepickerCaption')}</span>
</div>
<div className="line line_time"></div>
<div className="date date_time">{!open.calendar ? time.format("DD MMMM") : '' }</div>
<div className="date date_time">{!open.calendar ? time.format("DD MMMM") : ''}</div>
</div>
<div className="form__block">
{timePicker.map((date, i) => (
@@ -114,11 +116,11 @@ export const Timepicker: React.FC<TProps> = ({
<div className="appointment__block appointment__block_time">
<div>
<img alt="point" className="point" src={point1}></img>
<span className="appointment__caption_active">{text.appointmentTrue}</span>
<span className="appointment__caption_active">{t('appointmentTrue')}</span>
</div>
<div>
<img alt="point" className="point" src={point0}></img>
<span>{text.appointmentFalse}</span>
<span>{t('appointmentFalse')}</span>
</div>
</div>
+6
View File
@@ -0,0 +1,6 @@
import { useDispatch, useSelector, TypedUseSelectorHook } from "react-redux";
import { AppDispatch, RootState } from "../store/store";
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
+5
View File
@@ -0,0 +1,5 @@
import { useLocation } from "react-router";
const useQuery = () => new URLSearchParams(useLocation().search);
export default useQuery
+2 -2
View File
@@ -5,7 +5,7 @@
@import url(./components/cloudSolution/cloudSolution.css);
@import url(./components/devices/devices.css);
@import url(./components/form/form.css);
@import url(./components/header/header.css);
@import url(./components/header/Header.css);
@import url(./components/multiplayer/multiplayer.css);
@import url(./components/player/player.css);
@import url(./components/sliderComponent/sliderComponent.css);
@@ -28,7 +28,7 @@ body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-overflow-scrolling: touch;
background: #0e0e0e;
background: #151619;
width: 100%;
}
+32 -2
View File
@@ -3,6 +3,34 @@ import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from "react-router-dom";
import { Provider } from "react-redux";
import { setupStore } from "./store/store";
import i18next from "i18next";
import { initReactI18next } from "react-i18next";
import HttpApi from "i18next-http-backend";
import LanguageDetector from "i18next-browser-languagedetector";
const store = setupStore();
i18next
.use(HttpApi)
.use(LanguageDetector)
.use(initReactI18next)
.init({
supportedLngs: ["en", "ru"],
fallbackLng: "en",
debug: false,
// Options for language detector
detection: {
order: ["cookie", "navigator"],
caches: ["cookie"],
},
// react: { useSuspense: false },
backend: {
loadPath: "/assets/locales/{{lng}}/translation.json",
},
});
const root = ReactDOM.createRoot(
@@ -10,8 +38,10 @@ const root = ReactDOM.createRoot(
);
root.render(
<BrowserRouter basename='/streaming-landing'>
<App />
<BrowserRouter>
<Provider store={store}>
<App />
</Provider>
</BrowserRouter>
);
+11
View File
@@ -0,0 +1,11 @@
export interface ICards {
app_title: string;
title: string;
language: string;
location: string;
feature_description: string;
icon: string;
logo: string;
preview: string;
_id: string;
}
+5
View File
@@ -0,0 +1,5 @@
export interface IData {
link: string;
connection_code: string;
msg: string,
}
BIN
View File
Binary file not shown.
+69
View File
@@ -0,0 +1,69 @@
import { createAsyncThunk } from "@reduxjs/toolkit";
import axios from 'axios';
const instance = axios.create({
baseURL: 'https://a1.coord.graff.tech',
});
instance.defaults.headers.post['Content-Type'] = 'application/json';
export const fetchCards = createAsyncThunk(
"cards/FetchAll",
async (language: string, thunkApi) => {
try {
const { data } = await instance.get('/title/get_for_language/', { params: { start: 0, count: 100, language: language } });
return data;
} catch (e: any) {
const { response } = e
if (!response) {
return thunkApi.rejectWithValue('Произошла ошибка, попробуйте позже');
} else {
return thunkApi.rejectWithValue(response.data.message);
}
}
}
);
export const createSession = createAsyncThunk(
"session/Create",
async (title: string, thunkApi) => {
try {
const { data } = await instance.post('/session/create', { title });
return data;
} catch (e: any) {
const { response } = e
if (!response) {
return thunkApi.rejectWithValue('Произошла ошибка, попробуйте позже');
} else {
return thunkApi.rejectWithValue(response.data.message);
}
}
}
);
export const connectSession = createAsyncThunk(
"session/Connect",
async (code: string, thunkApi) => {
try {
const { data } = await instance.get('/session/connect', { params: { session_id: code } });
return data;
} catch (e: any) {
const { response } = e
if (!response) {
return thunkApi.rejectWithValue('Произошла ошибка, попробуйте позже');
} else {
return thunkApi.rejectWithValue(response.data.message);
}
}
}
);
+45
View File
@@ -0,0 +1,45 @@
import { ICards } from "../../models/ICards";
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { fetchCards } from "./ActionCreator";
interface CardState {
cards: ICards[];
isLoading: boolean;
error: any;
currentCard: ICards | null;
}
const initialState: CardState = {
cards: [],
isLoading: false,
error: "",
currentCard: null,
};
export const cardSlice = createSlice({
name: "cards",
initialState,
reducers: {
handleCurrentCard(state, action: PayloadAction<ICards>) {
state.currentCard = action.payload;
},
},
extraReducers: {
[fetchCards.fulfilled.type]: (state, action: PayloadAction<ICards[]>) => {
state.isLoading = false;
state.error = "";
state.cards = action.payload;
},
[fetchCards.pending.type]: (state) => {
state.isLoading = true;
},
[fetchCards.rejected.type]: (state, action: PayloadAction<any>) => {
console.log(action.payload)
state.isLoading = false;
state.error = action.payload;
},
},
});
export default cardSlice.reducer;
+50
View File
@@ -0,0 +1,50 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import i18next from "i18next";
import { initReactI18next } from "react-i18next";
import HttpApi from "i18next-http-backend";
import cookies from "js-cookie";
import LanguageDetector from "i18next-browser-languagedetector";
i18next
.use(HttpApi)
.use(LanguageDetector)
.use(initReactI18next)
.init({
supportedLngs: ["en", "ru"],
fallbackLng: "en",
debug: false,
// Options for language detector
detection: {
order: ["cookie", "navigator"],
caches: ["cookie"],
},
// react: { useSuspense: false },
backend: {
loadPath: "/assets/locales/{{lng}}/translation.json",
},
});
interface LanguageState {
currentLang: string;
}
const initialState: LanguageState = {
currentLang: '',
};
export const languageSlice = createSlice({
name: "language",
initialState,
reducers: {
handleChangeLanguage(state, action: PayloadAction<string>) {
i18next.changeLanguage(action.payload)
state.currentLang = action.payload
},
},
});
export default languageSlice.reducer;
+76
View File
@@ -0,0 +1,76 @@
import { IData } from "../../models/IData";
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { createSession, connectSession } from "./ActionCreator";
export interface sessionState {
isLoading: boolean;
error: any;
url: string;
id: string;
playerCount: any
}
interface ConnectSessionResponseInterface {
websocket_url: string;
}
interface CreateSessionResponseInterface {
session_id: string;
}
const initialState: sessionState = {
isLoading: false,
error: null,
url: "",
id: "",
playerCount: [],
};
export const sessionSlice = createSlice({
name: "data",
initialState,
reducers: {
cleanErrors(state) {
state = initialState
},
setUserCount(state, action) {
console.log(action.payload)
const newArr = new Array(action.payload).fill('user')
state.playerCount = newArr
}
},
extraReducers: {
[createSession.fulfilled.type]: (
state,
action: PayloadAction<CreateSessionResponseInterface>
) => {
state.isLoading = false;
state.id = action.payload.session_id;
},
[createSession.rejected.type]: (state, action: PayloadAction<any>) => {
state.isLoading = false;
state.error = action.payload;
},
[createSession.pending.type]: (state) => {
state.isLoading = true;
},
[connectSession.fulfilled.type]: (
state,
action: PayloadAction<ConnectSessionResponseInterface>
) => {
state.isLoading = false;
const url = action.payload.websocket_url;
state.url = url;
},
[connectSession.rejected.type]: (state, action: PayloadAction<any>) => {
state.isLoading = false;
state.error = action.payload;
},
[connectSession.pending.type]: (state, action) => {
state.isLoading = true;
},
},
});
export default sessionSlice.reducer;
+25
View File
@@ -0,0 +1,25 @@
import { combineReducers, configureStore } from "@reduxjs/toolkit";
import cardReducer from "./reducers/cardSlice";
import sessionReducer from "./reducers/sessionSlice";
import languageReducer from "./reducers/languageSlice";
const rootReducer = combineReducers({
cardReducer,
sessionReducer,
languageReducer,
});
export const setupStore = () => {
return configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({ serializableCheck: false }),
});
};
export type RootState = ReturnType<typeof rootReducer>;
export type AppStore = ReturnType<typeof setupStore>;
export type AppDispatch = AppStore["dispatch"];
+6 -6
View File
@@ -38,7 +38,7 @@
font-size: 18px;
line-height: 140%;
margin: 0;
color: #ebebeb;
color: #F2F2F2;
}
.main-block__subblock-container {
@@ -76,7 +76,7 @@
/* Landing/White */
color: #ebebeb;
color: #F2F2F2;
}
.main-block__title {
@@ -84,7 +84,7 @@
font-weight: 400;
font-size: 64px;
line-height: 100%;
color: #ebebeb;
color: #F2F2F2;
margin: 0;
}
@@ -92,7 +92,7 @@
font-style: normal;
font-weight: 400;
line-height: 100%;
color: #ebebeb;
color: #F2F2F2;
margin: 0;
font-size: 40px;
}
@@ -133,7 +133,7 @@
font-size: 18px;
line-height: 140%;
margin: 20px 0 0 0;
color: #ebebeb;
color: #F2F2F2;
}
.main-block__caption_color {
@@ -191,7 +191,7 @@
border: 1px solid #454545;
border-radius: 32px;
background-color: transparent;
color: #ebebeb;
color: #F2F2F2;
cursor: pointer;
}
.main-block__icon {