feat: add start section

This commit is contained in:
2025-05-28 15:07:29 +03:00
parent 498aa4e4c1
commit 855fc3f740
32 changed files with 594 additions and 408 deletions

View File

@@ -1,32 +1,38 @@
import type { Metadata } from 'next';
import { Geist, Geist_Mono } from 'next/font/google';
import './globals.css';
import { Open_Sans } from 'next/font/google';
import '@core/styles/reset.scss';
import '@core/styles/globals.scss';
const geistSans = Geist({
variable: '--font-geist-sans',
subsets: ['latin'],
});
const geistMono = Geist_Mono({
variable: '--font-geist-mono',
subsets: ['latin'],
const openSans = Open_Sans({
subsets: ['latin', 'cyrillic'],
weight: ['300', '400', '500', '600', '700'],
variable: '--open-sans',
});
export const metadata: Metadata = {
title: 'Пожарная экспертиза',
description: 'Пожарная экспертиза',
title: 'Обследование на соответствие пожарной безопасности',
description:
'Полное обследование объекта на соответствие требованиям пожарной безопасности',
openGraph: {
title: 'Обследование на соответствие пожарной безопасности',
description:
'Полное обследование объекта на соответствие требованиям пожарной безопасности',
siteName: 'Обследование на соответствие пожарной безопасности',
// images: [
// {
// url: `MetaSR.png`,
// alt: 'icon',
// },
// ],
},
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
}: Readonly<{ children: React.ReactNode }>) {
return (
<html lang='en'>
<body className={`${geistSans.variable} ${geistMono.variable}`}>
{children}
</body>
<body className={`${openSans.variable}`}>{children}</body>
</html>
);
}

View File

@@ -1,4 +1,4 @@
import HomePage from '@pages/home';
import { HomePage } from '@pages/home';
export default function Home() {
return (

View File

@@ -0,0 +1,6 @@
@use 'sass:math';
@function rem($size) {
$remSize: math.div($size, $base-font-size);
@return $remSize * 1rem;
}

View File

@@ -1,13 +1,6 @@
:root {
--background: #ffffff;
--foreground: #171717;
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
--foreground: #333333;
}
html,
@@ -34,9 +27,3 @@ a {
color: inherit;
text-decoration: none;
}
@media (prefers-color-scheme: dark) {
html {
color-scheme: dark;
}
}

View File

@@ -0,0 +1,2 @@
@import './variables.scss';
@import './mixins.scss';

View File

@@ -0,0 +1,23 @@
@mixin onlymobile {
@media (min-width: 0px) and (max-width: calc($tablet - 1px)) {
@content;
}
}
@mixin iftablet {
@media (min-width: $tablet) {
@content;
}
}
@mixin iflaptop {
@media (min-width: $laptop) {
@content;
}
}
@mixin ifdesktop {
@media (min-width: $desktop) {
@content;
}
}

106
src/core/styles/reset.scss Normal file
View File

@@ -0,0 +1,106 @@
/* Reset and base styles */
* {
padding: 0;
margin: 0;
border: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); // stop highlights element blue when tapping
}
*,
*::before,
*::after {
box-sizing: border-box;
}
/* Links */
a,
a:link,
a:visited {
text-decoration: none;
color: unset;
}
a:hover {
text-decoration: none;
}
/* Components */
aside,
nav,
footer,
header,
section,
main {
display: block;
}
h1,
h2,
h3,
h4,
h5,
h6,
p {
font-size: inherit;
font-weight: inherit;
margin: 0;
padding: 0;
//margin-block-start: 0;
//margin-block-end: 0;
}
ul[role='list'], ol[role='list'] {
list-style: none;
}
ul,
ul li {
list-style: none;
}
/* Form */
input,
textarea,
button,
select {
font-family: inherit;
font-size: inherit;
color: inherit;
background-color: transparent;
}
input::-ms-clear {
display: none;
}
button,
input[type='submit'] {
display: inline-block;
box-shadow: none;
background-color: transparent;
background: none;
}
input:focus,
input:active,
button:focus,
button:active {
outline: none;
}
button::-moz-focus-inner {
padding: 0;
border: 0;
}
legend {
display: block;
}
img, picture, svg, video, canvas {
background-repeat: no-repeat;
background-size: cover;
}

View File

@@ -0,0 +1,21 @@
//frontend breakpoint
$mobile: 360px;
$tablet: 768px;
$laptop: 1024px;
$desktop: 1440px;
//fonts
$font-open-sans: var(--open-sans), sans-serif;
$font-regular: 500;
$font-semi-bold: 600;
// colors
$color-white: #FFFFFF;
$color-black: #000000;
$color-orange: #E96526;
$color-lightgray: #E4E1E1;
$color-text: #333333;
$color-text-light: #222222;
$color-mark: #E96526;

View File

@@ -0,0 +1,106 @@
.Start {
padding: 0px 160px 0px;
&_BgWrapper {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 900px;
z-index: -1;
& img {
object-fit: cover;
filter: brightness(0.5);
}
}
}
.Header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid $color-white;
height: 80px;
.Logo {
color: $color-white;
}
.Buttons {
color: $color-white;
display: flex;
flex-direction: row;
align-items: center;
gap: 30px;
.Icon {
width: 60px;
height: 60px;
cursor: pointer;
}
.Button {
display: flex;
flex-direction: row;
gap: 16px;
height: 48px;
padding: 24px;
}
}
}
.Info {
display: flex;
flex-direction: row;
padding: 160px 0 200px;
.Content {
display: flex;
flex-direction: column;
justify-content: flex-start;
gap: 60px;
.Title {
font-family: $font-open-sans;
font-weight: $font-regular;
font-size: 60px;
line-height: 1;
color: $color-white;
max-width: 960px;
}
.List {
display: flex;
flex-direction: column;
justify-content: flex-start;
gap: 16px;
}
.ListItem {
font-family: $font-open-sans;
font-weight: $font-semi-bold;
font-size: 26px;
line-height: 1;
color: $color-white;
}
}
.Phone {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
flex-basis: 40%;
gap: 40px;
.Title {
font-family: $font-open-sans;
font-weight: $font-semi-bold;
font-size: 60px;
line-height: 1;
color: $color-white;
}
}
}

57
src/pages/home/home.tsx Normal file
View File

@@ -0,0 +1,57 @@
import s from './home.module.scss';
import { Button } from '@shared/ui';
import waIcon from '@public/svg/whatsapp.svg';
import tgIcon from '@public/svg/telegram.svg';
import callBtn from '@public/svg/phone-calling.svg';
import bgStart from '@public/images/bg-start-desktop.jpg';
import Image from 'next/image';
export default function Home() {
return (
<section className={s.Start}>
<div className={s.Start_BgWrapper}>
<Image
src={bgStart}
placeholder='blur'
alt={''}
sizes='100vw'
quality={100}
fill
priority
/>
</div>
<div className={s.Header}>
<div className={s.Logo}>Пожарная экспертиза</div>
<div className={s.Buttons}>
<Image className={s.Icon} src={waIcon} alt='whatsapp' />
<Image className={s.Icon} src={tgIcon} alt='telegram' />
<Button className={s.Button}>
<Image src={callBtn} alt='Call' />
Обратный звонок
</Button>
</div>
</div>
<div className={s.Info}>
<div className={s.Content}>
<h1 className={s.Title}>
Полное обследование объекта на соответствие требованиям пожарной
безопасности
</h1>
<ul className={s.List}>
<li className={s.ListItem}>
Пожарно-техническое обследование (пожарный аудит)
</li>
<li className={s.ListItem}>Расчёт пожарного риска</li>
<li className={s.ListItem}>
Сокращение затрат на модернизацию пожарных систем
</li>
</ul>
</div>
<div className={s.Phone}>
<p className={s.Title}>+7 999 123 45 67</p>
<Button variant='orange'>Получить консультацию</Button>
</div>
</div>
</section>
);
}

View File

@@ -1 +1 @@
export { default } from './ui/Home';
export { default as HomePage } from './home';

View File

@@ -1,5 +0,0 @@
function Home() {
return <main>Home</main>;
}
export default Home;

View File

@@ -0,0 +1,46 @@
.Button {
display: flex;
align-items: center;
justify-content: center;
padding: 13px 33px;
border-radius: 28px;
font-family: $font-open-sans;
font-weight: $font-regular;
font-size: 24px;
line-height: 1;
transition: all 0.15s linear;
white-space: nowrap;
svg {
width: 18px;
height: 18px;
//fill: var(--text-primary);
margin-right: 18px;
}
&:hover {
cursor: pointer;
}
&:hover svg {
fill: var(--white);
}
&_default {
background: $color-lightgray;
color: $color-text;
}
&_orange {
background: $color-orange;
color: $color-white;
}
&_disabled {
cursor: not-allowed;
}
}

View File

@@ -0,0 +1,39 @@
import s from './button.module.scss';
import { FunctionComponent, HTMLAttributes, ReactNode, SVGProps } from 'react';
import { clsx } from 'clsx';
type ButtonProps = {
className?: string;
children?: ReactNode;
disabled?: boolean;
Icon?: FunctionComponent<SVGProps<SVGSVGElement>>;
onClick?: () => void;
variant?: 'default' | 'orange' | 'ghost';
} & HTMLAttributes<HTMLButtonElement>;
export default function Button({
className,
children,
onClick,
Icon,
disabled,
variant = 'default',
...props
}: ButtonProps) {
return (
<button
className={clsx(
s.Button,
disabled && s.Button_disabled,
s['Button_' + variant],
className,
)}
onClick={onClick}
disabled={disabled}
{...props}
>
{Icon && <Icon />}
{children}
</button>
);
}

View File

@@ -0,0 +1 @@
export { default as Button } from './button';

1
src/shared/ui/index.ts Normal file
View File

@@ -0,0 +1 @@
export { Button } from './button';