upd
This commit is contained in:
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 26 KiB |
@@ -4,7 +4,7 @@ import { PhoneIcon } from './icons/PhoneIcon';
|
||||
import { SendIcon } from './icons/SendIcon';
|
||||
import { TelegramIcon } from './icons/TelegramIcon';
|
||||
import { VKIcon } from './icons/VKIcon';
|
||||
import { YoutubeIcon } from './icons/YoutubeIcon';
|
||||
import { RutubeIcon } from './icons/RutubeIcon';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useModalStore } from '../stores/modalStore';
|
||||
import { ModalWithForm } from './Layout/ModalWithForm';
|
||||
@@ -38,9 +38,7 @@ export function Contacts() {
|
||||
className="py-4"
|
||||
width="full"
|
||||
icon={<MailIcon />}
|
||||
onClick={() => {
|
||||
window.location.href = 'mailto:info@graff.tech';
|
||||
}}
|
||||
href="mailto:info@graff.tech"
|
||||
>
|
||||
<span className="btn-text opacity-80">Написать</span>
|
||||
</Button>
|
||||
@@ -49,9 +47,7 @@ export function Contacts() {
|
||||
className="py-4"
|
||||
width="full"
|
||||
icon={<PhoneIcon />}
|
||||
onClick={() => {
|
||||
window.location.href = 'tel:88007700067';
|
||||
}}
|
||||
href="tel:88007700067"
|
||||
>
|
||||
<span className="btn-text opacity-80">Позвонить</span>
|
||||
</Button>
|
||||
@@ -60,10 +56,10 @@ export function Contacts() {
|
||||
<h4 className="h4 font-medium">Социальные сети</h4>
|
||||
<div className="gap-x-2 flex">
|
||||
<Link
|
||||
to={'https://www.youtube.com/@GRAFFtech'}
|
||||
className="p-4 rounded-full opacity-80 border-[#3D425C] border hover:border-[#52587A] transition-all"
|
||||
to={'https://rutube.ru/channel/25505040/'}
|
||||
className="p-4 flex items-center justify-center rounded-full opacity-80 border-[#3D425C] border hover:border-[#52587A] transition-all"
|
||||
>
|
||||
<YoutubeIcon />
|
||||
<RutubeIcon />
|
||||
</Link>
|
||||
<Link
|
||||
to={'https://vk.com/graffinteractive?from=groups'}
|
||||
|
||||
@@ -149,7 +149,7 @@ export function FeedbackForm({
|
||||
mask={placeholder?.replace(/\d/g, '9') ?? ''}
|
||||
maskChar={null}
|
||||
value={phone}
|
||||
placeholder={placeholder}
|
||||
placeholder={'XXX XXX XX XX'}
|
||||
onChange={e => setPhone(e.target.value.replace(/ /g, ''))}
|
||||
className="transition-all bg-transparent rounded-none outline-none h4 placeholder:h4 placeholder:font-medium placeholder:select-none peer"
|
||||
/>
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import { LogoIcon } from '../icons/LogoIcon';
|
||||
import { Link, NavLink } from 'react-router-dom';
|
||||
import { LogoWithoutText } from '../icons/LogoWithoutTextIcon';
|
||||
|
||||
export function Footer() {
|
||||
return (
|
||||
<footer className="sm:grid xl:grid-cols-[2fr_1fr_1fr] sm:grid-cols-2 sm:max-xl:grid-rows-2 bg-[#14161F]">
|
||||
<div className="flex sm:items-center max-sm:flex-col sm:px-6 px-4 sm:py-9 py-4 border-t border-[#3D425C] gap-6 sm:max-xl:row-start-1 sm:max-xl:col-span-2">
|
||||
<Link to={'/'}>
|
||||
<LogoIcon />
|
||||
<img
|
||||
src="images/GRAFFinteractive.svg"
|
||||
alt="GRAFFinteractive"
|
||||
className="w-[118px] max-md:hidden"
|
||||
/>
|
||||
<div className="md:hidden">
|
||||
<LogoWithoutText />
|
||||
</div>
|
||||
</Link>
|
||||
<div className="flex flex-col gap-y-1">
|
||||
<div className="flex gap-x-4 m-text">
|
||||
@@ -20,7 +27,7 @@ export function Footer() {
|
||||
<Link to="https://graff.tech">graff.tech</Link>
|
||||
</div>
|
||||
<p className="opacity-40 sm:font-medium m-text">
|
||||
© 2024 GRAFF interactive. Все права защищены
|
||||
© 2026 GRAFF interactive. Все права защищены
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
import { LogoIcon } from '../icons/LogoIcon';
|
||||
import { Button } from '../ui/Button';
|
||||
import { ClassNameWrapper } from '../../hocs/ClassNameWrapper';
|
||||
import { useModalStore } from '../../stores/modalStore';
|
||||
@@ -26,9 +25,10 @@ export function Header() {
|
||||
return (
|
||||
<header className="sticky top-0 lg:px-6 px-4 flex max-lg:justify-between items-center lg:h-16 h-12 border-b border-[#3D425C] bg-[#14161F] z-50">
|
||||
<Link to={'/'} className="max-sm:hidden">
|
||||
<ClassNameWrapper
|
||||
element={<LogoIcon />}
|
||||
className="h-8 lg:h-10 lg:w-[113px] w-[93px]"
|
||||
<img
|
||||
src="images/GRAFFinteractive.svg"
|
||||
alt="GRAFFinteractive"
|
||||
className="lg:w-[118px] sm:w-[80px] max-sm:hidden"
|
||||
/>
|
||||
</Link>
|
||||
<Link to={'/'} className="sm:hidden">
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { ClassNameWrapper } from '../../hocs/ClassNameWrapper';
|
||||
import { useModalStore } from '../../stores/modalStore';
|
||||
import { Button } from '../ui/Button';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { ArrowRightIcon } from '../icons/ArrowRightIcon';
|
||||
import { CloseIcon } from '../icons/CloseIcon';
|
||||
import { FeedbackForm } from './FeedbackForm';
|
||||
import { useOnClickOutside } from 'usehooks-ts';
|
||||
|
||||
export function ModalWithForm() {
|
||||
const { setModal } = useModalStore();
|
||||
|
||||
const [sent, setSent] = useState(false);
|
||||
const modalRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const listener = (e: KeyboardEvent) => {
|
||||
@@ -22,8 +23,13 @@ export function ModalWithForm() {
|
||||
return () => document.removeEventListener('keydown', listener);
|
||||
}, [setModal]);
|
||||
|
||||
useOnClickOutside(modalRef, () => setModal(false));
|
||||
|
||||
return (
|
||||
<div className="fixed flex flex-col gap-4 top-0 right-0 h-full sm:w-[408px] w-full bg-[#14161F] overflow-y-auto sm:p-8 p-6">
|
||||
<div
|
||||
ref={modalRef}
|
||||
className="fixed flex flex-col gap-4 top-0 right-0 h-full sm:w-[408px] w-full bg-[#14161F] overflow-y-auto sm:p-8 p-6"
|
||||
>
|
||||
{!sent ? (
|
||||
<div className="space-y-8">
|
||||
<div className="flex justify-between items-center">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export function LogoIcon() {
|
||||
return (
|
||||
<svg
|
||||
width={128}
|
||||
width={138}
|
||||
height={50}
|
||||
viewBox="0 0 128 50"
|
||||
fill="none"
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
export function RutubeIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g opacity="0.8" transform="translate(2, 3)">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M8.793 4.543H2.62V2.205h6.174c.36 0 .612.06.738.165.125.106.203.3.203.585v.84c0 .3-.078.494-.203.6-.126.104-.377.15-.738.15zM9.217.001H0V10h2.619V6.747h4.825L9.734 10h2.933l-2.525-3.268c.93-.132 1.349-.405 1.693-.855s.518-1.17.518-2.13v-.749c0-.57-.063-1.019-.173-1.364a2.26 2.26 0 0 0-.564-.914 2.6 2.6 0 0 0-.973-.555C10.268.06 9.797 0 9.218 0"
|
||||
fill="#fff"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -8,6 +8,8 @@ interface ButtonProps {
|
||||
disabled?: boolean;
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
/** Native link (mailto:, tel:, https://). More reliable than JS navigation on some mobile WebViews. */
|
||||
href?: string;
|
||||
}
|
||||
|
||||
export function Button({
|
||||
@@ -18,25 +20,47 @@ export function Button({
|
||||
disabled = false,
|
||||
className,
|
||||
onClick,
|
||||
href,
|
||||
}: ButtonProps) {
|
||||
return (
|
||||
<button
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
className={`group relative px-6 py-2 rounded-full min-w-fit ${
|
||||
const sharedClassName = `group relative px-6 py-2 rounded-full min-w-fit ${
|
||||
(color === 'primary'
|
||||
? 'bg-gradient-to-r from-[#798FFF] to-[#D375FF]'
|
||||
: '') ||
|
||||
(color === 'secondary' ? 'outline outline-1 outline-[#3D425C]' : '')
|
||||
} ${
|
||||
icon ? 'pr-4' : ''
|
||||
} flex gap-1 items-center overflow-hidden w-${width} ${className} justify-between`}
|
||||
>
|
||||
} flex gap-1 items-center overflow-hidden w-${width} ${className} justify-between`;
|
||||
|
||||
const inner = (
|
||||
<>
|
||||
<span className="group-hover:opacity-10 opacity-0 bg-black transition-opacity absolute top-0 left-0 w-full h-full"></span>
|
||||
<span className={'relative font-medium' + (icon ? '' : ' m-auto')}>
|
||||
{children}
|
||||
</span>
|
||||
<span className="relative">{icon}</span>
|
||||
</>
|
||||
);
|
||||
|
||||
if (href) {
|
||||
return (
|
||||
<a
|
||||
href={disabled ? undefined : href}
|
||||
className={sharedClassName + (disabled ? ' pointer-events-none opacity-50' : '')}
|
||||
aria-disabled={disabled || undefined}
|
||||
onClick={disabled ? (e) => e.preventDefault() : onClick}
|
||||
>
|
||||
{inner}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
className={sharedClassName}
|
||||
>
|
||||
{inner}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -27,13 +27,13 @@ export const stands: IStand[] = [
|
||||
},
|
||||
{
|
||||
img: 'images/stands/interactive_floor.jpg',
|
||||
title: 'Interactive floor',
|
||||
title: 'Интерактивный этаж',
|
||||
annotation: 'Выставка «Россия ВДНХ»',
|
||||
year: '2022',
|
||||
},
|
||||
{
|
||||
img: 'images/stands/graff_estate_stream.jpg',
|
||||
title: 'Graff.estate stream',
|
||||
title: 'Модуль удаленной демонстрации недвижимости GRAFF.estate',
|
||||
annotation: 'WOW FEST',
|
||||
year: '2023',
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user