diff --git a/public/icons/filters.svg b/public/icons/filters.svg new file mode 100644 index 00000000..fb24e710 --- /dev/null +++ b/public/icons/filters.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/app/(main)/blog/[articleId]/edit/page.tsx b/src/app/(main)/blog/[articleId]/edit/page.tsx index 60d18f47..45f1b668 100644 --- a/src/app/(main)/blog/[articleId]/edit/page.tsx +++ b/src/app/(main)/blog/[articleId]/edit/page.tsx @@ -1,18 +1,11 @@ 'use client'; -import { ArticleActions } from '@/components/ArticleActions'; import { ArticleHeader } from '@/components/ArticleHeader'; -import { ArticleContentInput } from '@/components/articleInputs/ArticleContentInput'; -import { ArticleSliderInput } from '@/components/articleInputs/ArticleSliderInput'; -import { IArticleFormInput } from '@/components/modals/ArticleFormModal'; import { ArticleContent } from '@/components/pages/BlogPage/ArticleContent'; import { IArticle } from '@/types/IArticle'; import { Button } from '@/ui/Button'; -import { reorderFields } from '@/utils/reorderFields'; -import { Reorder } from 'framer-motion'; import { useParams } from 'next/navigation'; -import { useEffect, useState } from 'react'; -import { useFieldArray, useForm, useWatch } from 'react-hook-form'; +import { useState } from 'react'; export default function DashboardArticlePage() { const { articleId } = useParams<{ articleId: string }>(); @@ -20,13 +13,13 @@ export default function DashboardArticlePage() { const [showPreview, setShowPreview] = useState(false); const [article, setArticle] = useState(); - const { control, handleSubmit, setValue, getValues, watch } = - useForm(); + // const { control, handleSubmit, setValue, getValues, watch } = + // useForm(); - const { fields, append, swap, remove, insert } = useFieldArray({ - name: 'blocks', - control, - }); + // const { fields, append, swap, remove, insert } = useFieldArray({ + // name: 'blocks', + // control, + // }); // useGetArticleByIdQuery({ // variables: { id: +articleId }, @@ -55,22 +48,22 @@ export default function DashboardArticlePage() { // const client = useApolloClient(); - const [title, description, createdAt, cardImage, tags, blocks] = useWatch({ - name: ['title', 'description', 'createdAt', 'cardImage', 'tags', 'blocks'], - control, - }); + // const [title, description, createdAt, cardImage, tags, blocks] = useWatch({ + // name: ['title', 'description', 'createdAt', 'cardImage', 'tags', 'blocks'], + // control, + // }); - useEffect(() => { - setArticle({ - title, - description, - createdAt: new Date(createdAt), - cardImage, - tags, - blocks, - id: articleId, - }); - }, [title, description, createdAt, cardImage, tags, blocks, articleId]); + // useEffect(() => { + // setArticle({ + // title, + // description, + // createdAt: new Date(createdAt), + // cardImage, + // tags, + // blocks, + // id: articleId, + // }); + // }, [title, description, createdAt, cardImage, tags, blocks, articleId]); async function onSubmit() { if (!article) return; @@ -81,7 +74,7 @@ export default function DashboardArticlePage() { // blocks: JSON.stringify(getValues('blocks')), // }); // client.refetchQueries({ include: ['GetArticlesCount'] }); - window.location.href = '/blog'; + // window.location.href = '/blog'; } if (!article) return
not found
; @@ -98,9 +91,9 @@ export default function DashboardArticlePage() { ) : (
- + {/* */} {article.title && } -
+ {/*
)} diff --git a/src/app/(main)/page.tsx b/src/app/(main)/page.tsx index 75a6575a..b3620282 100644 --- a/src/app/(main)/page.tsx +++ b/src/app/(main)/page.tsx @@ -3,8 +3,10 @@ import { Awards } from '@/components/pages/MainPage/Awards'; import { Calculator } from '@/components/pages/MainPage/Calculator/Calculator'; import { Clients } from '@/components/pages/MainPage/Clients'; import { ProjectsMap } from '@/components/pages/MainPage/Map/ProjectsMap'; +import { Motivation } from '@/components/pages/MainPage/Motivation'; import { Presentation } from '@/components/pages/MainPage/Presentation/Presentation'; import { Projects } from '@/components/pages/MainPage/Projects'; +import { Reviews } from '@/components/pages/MainPage/Reviews/Reviews'; import { Statistics } from '@/components/pages/MainPage/Statistics'; import { Streaming } from '@/components/pages/MainPage/Streaming/Streaming'; import { ICompany } from '@/types/ICompany'; @@ -14,23 +16,6 @@ import { HydrationBoundary, QueryClient, } from '@tanstack/react-query'; -import dynamic from 'next/dynamic'; - -const Motivation = dynamic( - () => - import('@/components/pages/MainPage/Motivation').then( - (mod) => mod.Motivation - ), - { ssr: false } -); - -const Reviews = dynamic( - () => - import('@/components/pages/MainPage/Reviews/Reviews').then( - (mod) => mod.Reviews - ), - { ssr: false } -); export default async function HomePage() { const queryClient = new QueryClient(); diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 27cf0ee0..520b06dd 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,6 +1,7 @@ import { ModalContainer } from '@/components/Layout/ModalContainer'; -import { Providers } from '@/lib/Providers'; +// import { Providers } from '@/lib/Providers'; import type { Metadata } from 'next'; +import dynamic from 'next/dynamic'; import Script from 'next/script'; import './globals.css'; @@ -26,6 +27,11 @@ export const metadata: Metadata = { }, }; +const Providers = dynamic( + () => import('@/lib/Providers').then((mod) => mod.Providers), + { ssr: false } +); + export default function RootLayout({ children, }: Readonly<{ diff --git a/src/components/ArticleActions.tsx b/src/components/ArticleActions.tsx index 0f749fcb..64e5c93f 100644 --- a/src/components/ArticleActions.tsx +++ b/src/components/ArticleActions.tsx @@ -1,90 +1,90 @@ -'use client'; +// 'use client'; -import { useModalStore } from '@/stores/useModalStore'; -import { IArticle } from '@/types/IArticle'; -import { Button } from '@/ui/Button'; -import { Icon } from '@/ui/Icon'; -import { usePathname, useRouter } from 'next/navigation'; -import { UseFormSetValue } from 'react-hook-form'; -import { ArticleFormModal, IArticleInput } from './modals/ArticleFormModal'; -import { DeleteArticleModal } from './modals/DeleteArticleModal'; +// import { useModalStore } from '@/stores/useModalStore'; +// import { IArticle } from '@/types/IArticle'; +// import { Button } from '@/ui/Button'; +// import { Icon } from '@/ui/Icon'; +// import { usePathname, useRouter } from 'next/navigation'; +// import { UseFormSetValue } from 'react-hook-form'; +// import { ArticleFormModal, IArticleInput } from './modals/ArticleFormModal'; +// import { DeleteArticleModal } from './modals/DeleteArticleModal'; -export function ArticleActions({ - blocks, - cardImage, - createdAt, - tags, - title, - id, - setValue, - inCard = false, -}: IArticle & { - setValue?: UseFormSetValue; - inCard?: boolean; -}) { - const { push } = useRouter(); +// export function ArticleActions({ +// blocks, +// cardImage, +// createdAt, +// tags, +// title, +// id, +// setValue, +// inCard = false, +// }: IArticle & { +// setValue?: UseFormSetValue; +// inCard?: boolean; +// }) { +// const { push } = useRouter(); - const { setModal } = useModalStore(); +// const { setModal } = useModalStore(); - function handleEditArticle() { - if (setValue) - setModal( - , - 'editArticle' - ); - else push(`/blog/${id}/edit`); - } +// function handleEditArticle() { +// if (setValue) +// setModal( +// , +// 'editArticle' +// ); +// else push(`/blog/${id}/edit`); +// } - function handleDeleteArticle() { - setModal(, 'deleteArticle'); - } +// function handleDeleteArticle() { +// setModal(, 'deleteArticle'); +// } - const pathname = usePathname(); +// const pathname = usePathname(); - return ( -
- {inCard ? ( - <> - - - - ) : ( - <> - - - - )} -
- ); -} +// return ( +//
+// {inCard ? ( +// <> +// +// +// +// ) : ( +// <> +// +// +// +// )} +//
+// ); +// } diff --git a/src/components/BlockActions.tsx b/src/components/BlockActions.tsx index af3c0c1b..cb01b5aa 100644 --- a/src/components/BlockActions.tsx +++ b/src/components/BlockActions.tsx @@ -1,66 +1,66 @@ -import { useModalStore } from '@/stores/useModalStore'; -import { IContent } from '@/types/IArticle'; -import { Icon } from '@/ui/Icon'; -import { RefObject, SyntheticEvent } from 'react'; -import { - Control, - UseFieldArrayInsert, - UseFieldArrayRemove, -} from 'react-hook-form'; -import { ArticleContentEditorModal } from './modals/ArticleContentEditorModal'; -import { IArticleFormInput } from './modals/ArticleFormModal'; +// import { useModalStore } from '@/stores/useModalStore'; +// import { IContent } from '@/types/IArticle'; +// import { Icon } from '@/ui/Icon'; +// import { RefObject, SyntheticEvent } from 'react'; +// import { +// Control, +// UseFieldArrayInsert, +// UseFieldArrayRemove, +// } from 'react-hook-form'; +// import { ArticleContentEditorModal } from './modals/ArticleContentEditorModal'; +// import { IArticleFormInput } from './modals/ArticleFormModal'; -interface IBlockActionsProps { - item: IContent & Record<'id', string>; - index: number; - control: Control; - remove: UseFieldArrayRemove; - insert: UseFieldArrayInsert; - btnref: RefObject; -} +// interface IBlockActionsProps { +// item: IContent & Record<'id', string>; +// index: number; +// control: Control; +// remove: UseFieldArrayRemove; +// insert: UseFieldArrayInsert; +// btnref: RefObject; +// } -export function BlockActions({ - control, - index, - item, - remove, - insert, - btnref, -}: IBlockActionsProps) { - const { setModal } = useModalStore(); +// export function BlockActions({ +// control, +// index, +// item, +// remove, +// insert, +// btnref, +// }: IBlockActionsProps) { +// const { setModal } = useModalStore(); - function handleEditBlock(e: SyntheticEvent) { - e.preventDefault(); - setModal( - , - 'content' - ); - } +// function handleEditBlock(e: SyntheticEvent) { +// e.preventDefault(); +// setModal( +// , +// 'content' +// ); +// } - function handleDublicateBlock(e: SyntheticEvent) { - e.preventDefault(); - insert(index, item); - } +// function handleDublicateBlock(e: SyntheticEvent) { +// e.preventDefault(); +// insert(index, item); +// } - function handleRemoveBlock(e: SyntheticEvent) { - e.preventDefault(); - remove(index); - } +// function handleRemoveBlock(e: SyntheticEvent) { +// e.preventDefault(); +// remove(index); +// } - return ( -
- - - -
- ); -} +// return ( +//
+// +// +// +//
+// ); +// } diff --git a/src/components/Layout/Header.tsx b/src/components/Layout/Header.tsx index 102f26c2..7f924e94 100644 --- a/src/components/Layout/Header.tsx +++ b/src/components/Layout/Header.tsx @@ -16,6 +16,8 @@ import Link from 'next/link'; import { usePathname } from 'next/navigation'; import { useRef, useState } from 'react'; import { useOnClickOutside } from 'usehooks-ts'; +import BurgerIcon from '../../../public/icons/burger.svg'; +import CloseIcon from '../../../public/icons/close.svg'; import { LogoIcon } from '../icons/LogoIcon'; import { LogoWithTextIcon } from '../icons/LogoWithTextIcon'; import { ModalWithFeedbackForm } from '../modals/ModalWithFeedbackForm'; @@ -131,11 +133,11 @@ export function Header() { className="!border-none p-[18px] hover:bg-[#232425] rounded-2xl active:opacity-50 outline-none" onClick={() => setBurgerOpened((prev) => !prev)} > - + {burgerOpened ? ( + + ) : ( + + )}
{auth && ( diff --git a/src/components/Layout/SelectPhoneCode.tsx b/src/components/Layout/SelectPhoneCode.tsx index 1d997ce2..0ce0c5d0 100644 --- a/src/components/Layout/SelectPhoneCode.tsx +++ b/src/components/Layout/SelectPhoneCode.tsx @@ -1,4 +1,3 @@ -import { Icon } from '@/ui/Icon'; import countries from 'countries-phone-masks'; import { CountryCode, @@ -8,6 +7,8 @@ import { import Image from 'next/image'; import { SyntheticEvent, useRef, useState } from 'react'; import { useOnClickOutside } from 'usehooks-ts'; +import ChevronDownIcon from '../../../public/icons/chevron_down.svg'; +import ChevronUpIcon from '../../../public/icons/chevron_up.svg'; export function SelectPhoneCode({ currentPhoneCodeAndCountry: [currentPhoneCode, currentCountry], @@ -47,11 +48,11 @@ export function SelectPhoneCode({ sizes="" />

{currentPhoneCode}

- + {open ? ( + + ) : ( + + )} {open && (
diff --git a/src/components/articleInputs/ArticleContentInput.tsx b/src/components/articleInputs/ArticleContentInput.tsx index 18e2e73e..6a3b9cf0 100644 --- a/src/components/articleInputs/ArticleContentInput.tsx +++ b/src/components/articleInputs/ArticleContentInput.tsx @@ -1,61 +1,61 @@ -import { IContent } from '@/types/IArticle'; -import { Reorder } from 'framer-motion'; -import parse from 'html-react-parser'; -import { useEffect, useRef, useState } from 'react'; -import { - Control, - UseFieldArrayInsert, - UseFieldArrayRemove, - UseFormSetValue, - UseFormWatch, -} from 'react-hook-form'; -import { BlockActions } from '../BlockActions'; -import { IArticleFormInput } from '../modals/ArticleFormModal'; +// import { IContent } from '@/types/IArticle'; +// import { Reorder } from 'framer-motion'; +// import parse from 'html-react-parser'; +// import { useEffect, useRef, useState } from 'react'; +// import { +// Control, +// UseFieldArrayInsert, +// UseFieldArrayRemove, +// UseFormSetValue, +// UseFormWatch, +// } from 'react-hook-form'; +// import { BlockActions } from '../BlockActions'; +// import { IArticleFormInput } from '../modals/ArticleFormModal'; -export interface IArticleContentInputProps { - item: IContent & Record<'id', string>; - index: number; - control: Control; - setValue: UseFormSetValue; - watch: UseFormWatch; - remove: UseFieldArrayRemove; - insert: UseFieldArrayInsert; -} +// export interface IArticleContentInputProps { +// item: IContent & Record<'id', string>; +// index: number; +// control: Control; +// setValue: UseFormSetValue; +// watch: UseFormWatch; +// remove: UseFieldArrayRemove; +// insert: UseFieldArrayInsert; +// } -export function ArticleContentInput({ - control, - index, - item, - setValue, - watch, - remove, - insert, -}: IArticleContentInputProps) { - const [content, setContent] = useState(item.content); +// export function ArticleContentInput({ +// control, +// index, +// item, +// setValue, +// watch, +// remove, +// insert, +// }: IArticleContentInputProps) { +// const [content, setContent] = useState(item.content); - useEffect(() => { - const { unsubscribe } = watch((value) => { - if (value.blocks?.[index]?.type === 'Content') - setContent(value.blocks[index].content!); - }); - return unsubscribe; - }, [index, setValue, watch]); +// useEffect(() => { +// const { unsubscribe } = watch((value) => { +// if (value.blocks?.[index]?.type === 'Content') +// setContent(value.blocks[index].content!); +// }); +// return unsubscribe; +// }, [index, setValue, watch]); - const ref = useRef(null); +// const ref = useRef(null); - return ( - ref.current && ref.current?.click()} - > -
{parse(content)}
- -
- ); -} +// return ( +// ref.current && ref.current?.click()} +// > +//
{parse(content)}
+// +//
+// ); +// } diff --git a/src/components/articleInputs/ArticleSliderImageInput.tsx b/src/components/articleInputs/ArticleSliderImageInput.tsx index 8f955335..02955295 100644 --- a/src/components/articleInputs/ArticleSliderImageInput.tsx +++ b/src/components/articleInputs/ArticleSliderImageInput.tsx @@ -1,42 +1,42 @@ -import { Icon } from '@/ui/Icon'; -import { Reorder } from 'framer-motion'; -import { SyntheticEvent } from 'react'; -import { UseFieldArrayRemove, UseFormSetValue } from 'react-hook-form'; -import { ImageUploader } from '../ImageUploader'; -import { IArticleFormInput } from '../modals/ArticleFormModal'; +// import { Icon } from '@/ui/Icon'; +// import { Reorder } from 'framer-motion'; +// import { SyntheticEvent } from 'react'; +// import { UseFieldArrayRemove, UseFormSetValue } from 'react-hook-form'; +// import { ImageUploader } from '../ImageUploader'; +// import { IArticleFormInput } from '../modals/ArticleFormModal'; -interface IArticleSliderImageInputProps { - setValue: UseFormSetValue; - remove: UseFieldArrayRemove; - item: Record<'img', string> & Record<'id', string>; - index: number; - imgIndex: number; -} +// interface IArticleSliderImageInputProps { +// setValue: UseFormSetValue; +// remove: UseFieldArrayRemove; +// item: Record<'img', string> & Record<'id', string>; +// index: number; +// imgIndex: number; +// } -export function ArticleSliderImageInput({ - item, - imgIndex, - index, - remove, - setValue, -}: IArticleSliderImageInputProps) { - function handleClickClose(e: SyntheticEvent) { - e.preventDefault(); - remove(imgIndex); - } +// export function ArticleSliderImageInput({ +// item, +// imgIndex, +// index, +// remove, +// setValue, +// }: IArticleSliderImageInputProps) { +// function handleClickClose(e: SyntheticEvent) { +// e.preventDefault(); +// remove(imgIndex); +// } - return ( - - - - - ); -} +// return ( +// +// +// +// +// ); +// } diff --git a/src/components/articleInputs/ArticleSliderInput.tsx b/src/components/articleInputs/ArticleSliderInput.tsx index 1e31fa47..e621ccd7 100644 --- a/src/components/articleInputs/ArticleSliderInput.tsx +++ b/src/components/articleInputs/ArticleSliderInput.tsx @@ -1,75 +1,75 @@ -import { ISlider } from '@/types/IArticle'; -import { Icon } from '@/ui/Icon'; -import { reorderFields } from '@/utils/reorderFields'; -import { Reorder } from 'framer-motion'; -import { SyntheticEvent } from 'react'; -import { - Control, - useFieldArray, - UseFieldArrayRemove, - UseFormSetValue, -} from 'react-hook-form'; -import { IArticleFormInput } from '../modals/ArticleFormModal'; -import { ArticleSliderImageInput } from './ArticleSliderImageInput'; +// import { ISlider } from '@/types/IArticle'; +// import { Icon } from '@/ui/Icon'; +// import { reorderFields } from '@/utils/reorderFields'; +// import { Reorder } from 'framer-motion'; +// import { SyntheticEvent } from 'react'; +// import { +// Control, +// useFieldArray, +// UseFieldArrayRemove, +// UseFormSetValue, +// } from 'react-hook-form'; +// import { IArticleFormInput } from '../modals/ArticleFormModal'; +// import { ArticleSliderImageInput } from './ArticleSliderImageInput'; -interface IArticleSliderInputProps { - setValue: UseFormSetValue; - item: ISlider & Record<'id', string>; - index: number; - control: Control; - remove: UseFieldArrayRemove; -} +// interface IArticleSliderInputProps { +// setValue: UseFormSetValue; +// item: ISlider & Record<'id', string>; +// index: number; +// control: Control; +// remove: UseFieldArrayRemove; +// } -export function ArticleSliderInput({ - index, - item, - setValue, - control, - remove: removeSlider, -}: IArticleSliderInputProps) { - const { swap, append, remove, fields } = useFieldArray({ - control, - name: `blocks.${index}.images`, - }); +// export function ArticleSliderInput({ +// index, +// item, +// setValue, +// control, +// remove: removeSlider, +// }: IArticleSliderInputProps) { +// const { swap, append, remove, fields } = useFieldArray({ +// control, +// name: `blocks.${index}.images`, +// }); - function handleAddSlide(e: SyntheticEvent) { - e.preventDefault(); - append({ img: '' }); - } +// function handleAddSlide(e: SyntheticEvent) { +// e.preventDefault(); +// append({ img: '' }); +// } - function handleRemoveSlider(e: SyntheticEvent) { - e.preventDefault(); - removeSlider(index); - } +// function handleRemoveSlider(e: SyntheticEvent) { +// e.preventDefault(); +// removeSlider(index); +// } - return ( - -
- - -
- - {fields.map((item, imgIndex) => ( - - ))} - -
- ); -} +// return ( +// +//
+// +// +//
+// +// {fields.map((item, imgIndex) => ( +// +// ))} +// +//
+// ); +// } diff --git a/src/components/modals/ArticleContentEditorModal.tsx b/src/components/modals/ArticleContentEditorModal.tsx index c54e3458..613ce4cb 100644 --- a/src/components/modals/ArticleContentEditorModal.tsx +++ b/src/components/modals/ArticleContentEditorModal.tsx @@ -1,132 +1,132 @@ -import { api } from '@/api'; -import { useModalStore } from '@/stores/useModalStore'; -import { Icon } from '@/ui/Icon'; -import { Editor } from '@tinymce/tinymce-react'; -import { useRef } from 'react'; -import { Controller } from 'react-hook-form'; -import { Editor as Tinymce } from 'tinymce'; -import { IArticleContentInputProps } from '../articleInputs/ArticleContentInput'; +// import { api } from '@/api'; +// import { useModalStore } from '@/stores/useModalStore'; +// import { Icon } from '@/ui/Icon'; +// import { Editor } from '@tinymce/tinymce-react'; +// import { useRef } from 'react'; +// import { Controller } from 'react-hook-form'; +// import { Editor as Tinymce } from 'tinymce'; +// import { IArticleContentInputProps } from '../articleInputs/ArticleContentInput'; -export function ArticleContentEditorModal({ - control, - index, - item, -}: Pick) { - const { setModal } = useModalStore(); +// export function ArticleContentEditorModal({ +// control, +// index, +// item, +// }: Pick) { +// const { setModal } = useModalStore(); - const editorRef = useRef(null); - const videoUploadRef = useRef(null); +// const editorRef = useRef(null); +// const videoUploadRef = useRef(null); - return ( -
- ( - { - editorRef.current = editor; - }} - init={{ - content_style: - 'body {color: #fff; background: #14161f; font-size:16px;display:grid;grid-template-columns:repeat(4,1fr);} body > * {grid-column-start: 2;grid-column-end:4', - height: '100%', - font_size_formats: '10px 12px 14px 16px 18px 20px 24px 28px 30px', - video_template_callback: (data: { source: string }) => - '', - images_upload_credentials: true, - images_upload_handler: async (blobInfo) => { - const formData = new FormData(); - formData.append('files', blobInfo.blob(), blobInfo.filename()); - formData.append('dest', 'blog'); - const res = await api - .post('upload', { body: formData }) - .json<{ files: string[] }>(); - return process.env.NEXT_PUBLIC_S3_BUCKET + res.files[0]; - }, - file_picker_types: 'image media', - file_picker_callback: async (cb) => { - videoUploadRef.current!.onchange = async function () { - const reader = new FileReader(); - const file = videoUploadRef.current?.files?.[0]; - reader.onload = async function () { - const id = 'blobId' + new Date().getTime(); - const blobCache = editorRef.current?.editorUpload.blobCache; - const base64 = reader.result?.toString().split(',')[1]; - const blobInfo = blobCache?.create(id, file!, base64!); - blobCache?.add(blobInfo!); - const formData = new FormData(); - formData.append( - 'files', - blobInfo?.blob()!, - blobInfo?.filename() - ); - formData.append('dest', 'blog'); - const res = await api - .post('upload', { body: formData }) - .json<{ files: string[] }>(); +// return ( +//
+// ( +// { +// editorRef.current = editor; +// }} +// init={{ +// content_style: +// 'body {color: #fff; background: #14161f; font-size:16px;display:grid;grid-template-columns:repeat(4,1fr);} body > * {grid-column-start: 2;grid-column-end:4', +// height: '100%', +// font_size_formats: '10px 12px 14px 16px 18px 20px 24px 28px 30px', +// video_template_callback: (data: { source: string }) => +// '', +// images_upload_credentials: true, +// images_upload_handler: async (blobInfo) => { +// const formData = new FormData(); +// formData.append('files', blobInfo.blob(), blobInfo.filename()); +// formData.append('dest', 'blog'); +// const res = await api +// .post('upload', { body: formData }) +// .json<{ files: string[] }>(); +// return process.env.NEXT_PUBLIC_S3_BUCKET + res.files[0]; +// }, +// file_picker_types: 'image media', +// file_picker_callback: async (cb) => { +// videoUploadRef.current!.onchange = async function () { +// const reader = new FileReader(); +// const file = videoUploadRef.current?.files?.[0]; +// reader.onload = async function () { +// const id = 'blobId' + new Date().getTime(); +// const blobCache = editorRef.current?.editorUpload.blobCache; +// const base64 = reader.result?.toString().split(',')[1]; +// const blobInfo = blobCache?.create(id, file!, base64!); +// blobCache?.add(blobInfo!); +// const formData = new FormData(); +// formData.append( +// 'files', +// blobInfo?.blob()!, +// blobInfo?.filename() +// ); +// formData.append('dest', 'blog'); +// const res = await api +// .post('upload', { body: formData }) +// .json<{ files: string[] }>(); - cb(process.env.NEXT_PUBLIC_S3_BUCKET + res.files[0], { - title: file?.name, - }); - }; - reader.readAsDataURL(file!); - }; - videoUploadRef.current!.click(); - }, - automatic_uploads: true, - plugins: [ - 'anchor', - 'autolink', - 'charmap', - 'codesample', - 'emoticons', - 'image', - 'link', - 'lists', - 'media', - 'nonbreaking', - 'preview', - 'save', - 'searchreplace', - 'table', - 'visualblocks', - 'wordcount', - ], - toolbar: - 'undo redo | blocks fontfamily fontsize | bold italic underline strikethrough | link image media table mergetags | addcomment showcomments | spellcheckdialog a11ycheck typography | align lineheight | checklist numlist bullist indent outdent | emoticons charmap | removeformat', - tinycomments_mode: 'embedded', - tinycomments_author: 'Author name', - mergetags_list: [ - { value: 'First.Name', title: 'First Name' }, - { value: 'Email', title: 'Email' }, - ], - }} - licenseKey="gpl" - apiKey={process.env.NEXT_PUBLIC_TINYMCE_API_KEY} - /> - )} - /> - - -
- ); -} +// cb(process.env.NEXT_PUBLIC_S3_BUCKET + res.files[0], { +// title: file?.name, +// }); +// }; +// reader.readAsDataURL(file!); +// }; +// videoUploadRef.current!.click(); +// }, +// automatic_uploads: true, +// plugins: [ +// 'anchor', +// 'autolink', +// 'charmap', +// 'codesample', +// 'emoticons', +// 'image', +// 'link', +// 'lists', +// 'media', +// 'nonbreaking', +// 'preview', +// 'save', +// 'searchreplace', +// 'table', +// 'visualblocks', +// 'wordcount', +// ], +// toolbar: +// 'undo redo | blocks fontfamily fontsize | bold italic underline strikethrough | link image media table mergetags | addcomment showcomments | spellcheckdialog a11ycheck typography | align lineheight | checklist numlist bullist indent outdent | emoticons charmap | removeformat', +// tinycomments_mode: 'embedded', +// tinycomments_author: 'Author name', +// mergetags_list: [ +// { value: 'First.Name', title: 'First Name' }, +// { value: 'Email', title: 'Email' }, +// ], +// }} +// licenseKey="gpl" +// apiKey={process.env.NEXT_PUBLIC_TINYMCE_API_KEY} +// /> +// )} +// /> +// +// +//
+// ); +// } diff --git a/src/components/pages/BlogPage/ArticleContent.tsx b/src/components/pages/BlogPage/ArticleContent.tsx index fec85618..35d57caa 100644 --- a/src/components/pages/BlogPage/ArticleContent.tsx +++ b/src/components/pages/BlogPage/ArticleContent.tsx @@ -1,4 +1,3 @@ -import { ArticleHeader } from '@/components/ArticleHeader'; import { IArticle } from '@/types/IArticle'; import parse from 'html-react-parser'; import { ArticleSlider } from './ArticleSlider'; @@ -12,7 +11,7 @@ export function ArticleContent({ }: IArticle) { return ( <> - + {/* */}
{blocks.map((block, index) => block.type === 'Content' ? ( diff --git a/src/components/pages/BlogPage/RelevantArticles.tsx b/src/components/pages/BlogPage/RelevantArticles.tsx index 7b66cda2..1f023412 100644 --- a/src/components/pages/BlogPage/RelevantArticles.tsx +++ b/src/components/pages/BlogPage/RelevantArticles.tsx @@ -11,7 +11,6 @@ export function RelevantArticle({ id, tags, createdAt, - description, relevantTags, }: IArticle & { relevantTags: string[] }) { const [year, month, date] = new Date(createdAt) @@ -44,11 +43,6 @@ export function RelevantArticle({

{title}

- {description && ( -

- {description} -

- )}

diff --git a/src/components/pages/MainPage/Calculator/ConsultationsRange.tsx b/src/components/pages/MainPage/Calculator/ConsultationsRange.tsx index af0e8f56..1e5458a4 100644 --- a/src/components/pages/MainPage/Calculator/ConsultationsRange.tsx +++ b/src/components/pages/MainPage/Calculator/ConsultationsRange.tsx @@ -1,5 +1,7 @@ -import { Icon } from '@/ui/Icon'; -import { MouseEvent, useRef, useState } from 'react'; +'use client'; + +import { MouseEvent, Suspense, useRef, useState } from 'react'; +import DotsIcon from '../../../../../public/icons/dots.svg'; export function ConsultationRange({ consultations, @@ -17,7 +19,6 @@ export function ConsultationRange({ const [isMouseDown, setIsMouseDown] = useState(false); function handleMouseDown(e: MouseEvent) { - console.log(e.clientX - root.current!.getBoundingClientRect().x); setIsMouseDown(true); setStart( Math.max( @@ -71,12 +72,9 @@ export function ConsultationRange({ onMouseLeave={handleMouseUp} onMouseUp={handleMouseUp} > - + }> + +

diff --git a/src/components/pages/MainPage/Calculator/RegionSelector.tsx b/src/components/pages/MainPage/Calculator/RegionSelector.tsx index b6964086..ae92cb48 100644 --- a/src/components/pages/MainPage/Calculator/RegionSelector.tsx +++ b/src/components/pages/MainPage/Calculator/RegionSelector.tsx @@ -1,7 +1,10 @@ +'use client'; + import regionsData from '@/consts/regionsData.json'; -import { Icon } from '@/ui/Icon'; -import { useRef, useState } from 'react'; +import { LazySvg } from '@/ui/LazySvg'; +import { Suspense, useRef, useState } from 'react'; import { useOnClickOutside } from 'usehooks-ts'; +import ChevronDownIcon from '../../../../../public/icons/chevron_down.svg'; export interface Region { id: number; @@ -26,19 +29,23 @@ export function RegionSelector({ useOnClickOutside([dropdownRef, root], () => setOpened(false)); return ( -

-

Регион

+
+

+ Регион +

setOpened(!opened)} + onClick={() => setOpened((prev) => !prev)} >

{chosen.name}

- +
+ +
{opened && (
{(regionsData as Region[]).map((region, index) => ( -

{ @@ -55,10 +62,20 @@ export function RegionSelector({ }} > {region.name} - {chosen.name === region.name && ( - - )} -

+
+ {chosen.name === region.name && ( + }> + + + )} +
+
))}
)} diff --git a/src/components/pages/MainPage/Map/ProjectsSlider.tsx b/src/components/pages/MainPage/Map/ProjectsSlider.tsx index 2aa9f167..57672e7e 100644 --- a/src/components/pages/MainPage/Map/ProjectsSlider.tsx +++ b/src/components/pages/MainPage/Map/ProjectsSlider.tsx @@ -109,7 +109,7 @@ export function ProjectsSlider({ setCurrent((prev) => Math.min(projects.length, prev + 1)) } > - + {/* */}
diff --git a/src/components/pages/MainPage/Presentation/Engine.tsx b/src/components/pages/MainPage/Presentation/Engine.tsx index 3c8f85df..55b695b6 100644 --- a/src/components/pages/MainPage/Presentation/Engine.tsx +++ b/src/components/pages/MainPage/Presentation/Engine.tsx @@ -18,14 +18,14 @@ export function Engine({ slide }: { slide?: number }) {

{engine.map((item) => ( - + ))}
)} ) : ( -
+

Модуль инженерных систем

@@ -36,11 +36,11 @@ export function Engine({ slide }: { slide?: number }) { key={title} >

{title}

-
+
{title} diff --git a/src/components/pages/MainPage/Presentation/Infrastructure.tsx b/src/components/pages/MainPage/Presentation/Infrastructure.tsx index 5b92fba1..b308ab1d 100644 --- a/src/components/pages/MainPage/Presentation/Infrastructure.tsx +++ b/src/components/pages/MainPage/Presentation/Infrastructure.tsx @@ -49,7 +49,7 @@ export function Infrastructure({ slide }: { slide?: number }) { )} ) : ( -
+

Демонстрация инфраструктуры вокруг будущего комплекса @@ -58,7 +58,7 @@ export function Infrastructure({ slide }: { slide?: number }) { Режим «Инфраструктура» знакомит пользователя с перспективной застройкой целого района. В зависимости от срока сдачи либо функциональной нагрузки того или иного блока можно ввести выделение - цветом. + цветом

diff --git a/src/components/pages/MainPage/Presentation/Insolation.tsx b/src/components/pages/MainPage/Presentation/Insolation.tsx index 6b8325e3..f1ac4c20 100644 --- a/src/components/pages/MainPage/Presentation/Insolation.tsx +++ b/src/components/pages/MainPage/Presentation/Insolation.tsx @@ -36,7 +36,7 @@ export function Insolation({ slide }: { slide?: number }) { )} ) : ( -
+

Интерактивная инсоляция

diff --git a/src/components/pages/MainPage/Presentation/IntegrationCRM.tsx b/src/components/pages/MainPage/Presentation/IntegrationCRM.tsx index 09c673ba..5817dc88 100644 --- a/src/components/pages/MainPage/Presentation/IntegrationCRM.tsx +++ b/src/components/pages/MainPage/Presentation/IntegrationCRM.tsx @@ -69,7 +69,7 @@ export function IntegrationCRM({ slide }: { slide?: number }) { )} ) : ( -

+

Интеграция с CRM-системой застройщика

diff --git a/src/components/pages/MainPage/Presentation/PresentationMini.tsx b/src/components/pages/MainPage/Presentation/PresentationMini.tsx index 79ecc123..c4cc37d2 100644 --- a/src/components/pages/MainPage/Presentation/PresentationMini.tsx +++ b/src/components/pages/MainPage/Presentation/PresentationMini.tsx @@ -42,8 +42,8 @@ export function PresentationMini() { }, [slide, videoRefs]); return ( -
-
+
+
Интерактивная презентация{' '} <span className="text-gradient"> @@ -77,6 +77,7 @@ export function PresentationMini() { <Insolation /> <Engine /> <IntegrationCRM /> + <div className="h-[50vh] bg-[#0F1011]" /> </div> </div> ); diff --git a/src/components/pages/MainPage/Presentation/SearchAndSelect.tsx b/src/components/pages/MainPage/Presentation/SearchAndSelect.tsx index 429ea3fa..82e19f4b 100644 --- a/src/components/pages/MainPage/Presentation/SearchAndSelect.tsx +++ b/src/components/pages/MainPage/Presentation/SearchAndSelect.tsx @@ -4,7 +4,7 @@ import { Icon } from '@/ui/Icon'; export function SearchAndSelect({ slide }: { slide?: number }) { return ( <div - className={`max-md:p-6 flex max-md:flex-col lg:flex-col lg:h-full md:gap-3 gap-y-7 lg:z-10 lg:max-w-[33vw] md:h-[348px] lg:transition-all max-md:rounded-2xl max-lg:sticky md:max-lg:top-[calc(100vh-388px)] max-md:top-100 lg:duration-1000 lg:col-span-2 select-none max-md:bg-radial-[at_100%_100%] from-[#7A7A7A66] max-md:backdrop-blur-[500px]${ + className={`max-md:p-6 flex max-md:flex-col lg:flex-col lg:h-full md:gap-3 gap-y-7 lg:z-10 lg:max-w-[33vw] md:h-[348px] h-[340px] lg:transition-all max-md:rounded-2xl max-lg:sticky md:max-lg:top-[calc(100vh-388px)] max-md:top-120 lg:duration-1000 lg:col-span-2 select-none max-md:bg-radial-[at_100%_100%] from-[#7A7A7A66] max-md:backdrop-blur-[500px]${ slide ? ' lg:absolute lg:translate-x-[33%] lg:opacity-0' : '' }`} > diff --git a/src/components/pages/MainPage/Presentation/ThreeDTour.tsx b/src/components/pages/MainPage/Presentation/ThreeDTour.tsx index eacf0f29..35fae8c4 100644 --- a/src/components/pages/MainPage/Presentation/ThreeDTour.tsx +++ b/src/components/pages/MainPage/Presentation/ThreeDTour.tsx @@ -26,7 +26,7 @@ export function ThreeDTour({ slide }: { slide?: number }) { )} </AnimatePresence> ) : ( - <div className="md:space-y-6 space-y-7 before:bg-[#0F1011] before:max-md:bg-radial-[at_100%_100%] before:w-full before:absolute before:rounded-2xl before:top-0 before:left-0 before:h-full before:-z-1 before:from-[#7A7A7A66] backdrop-blur-[500px] md:backdrop-blur-xs md:h-[348px] sticky max-md:px-4 max-md:py-6 max-md:rounded-2xl md:top-[calc(100vh-388px)] top-100"> + <div className="md:space-y-6 space-y-7 before:bg-[#0F1011] before:max-md:bg-radial-[at_100%_100%] before:w-full before:absolute before:rounded-2xl before:top-0 before:left-0 before:h-full before:-z-1 before:from-[#7A7A7A66] h-[340px] backdrop-blur-[500px] md:backdrop-blur-xs md:h-[348px] sticky max-md:px-4 max-md:py-6 max-md:rounded-2xl md:top-[calc(100vh-388px)] top-120"> <p className="heading2 md:text-center font-medium">3D-тур</p> <div className="max-md:w-fit md:items-stretch md:gap-2 gap-x-3 gap-y-6 grid grid-cols-3"> {threeDTour.map((item) => ( diff --git a/src/components/pages/MainPage/Reviews/Reviews.tsx b/src/components/pages/MainPage/Reviews/Reviews.tsx index 0819298e..2384b6a1 100644 --- a/src/components/pages/MainPage/Reviews/Reviews.tsx +++ b/src/components/pages/MainPage/Reviews/Reviews.tsx @@ -22,7 +22,7 @@ export function Reviews() { <div className="max-lg:space-y-2"> <div ref={ref} - className="relative m-auto max-sm:aspect-[340/480] lg:space-y-20 lg:aspect-[1400/616] lg:min-w-[1040px] max-w-full sm:max-lg:aspect-[736/480] lg:mt-[140px] mt-[100px] max-lg:flex max-lg:flex-col transition-all group" + className="relative m-auto max-sm:aspect-[340/480] lg:aspect-[1400/616] lg:min-w-[1040px] max-w-full sm:max-lg:aspect-[736/480] lg:mt-[140px] mt-[100px] max-lg:flex max-lg:flex-col transition-all group" style={{ width: isLg ? scroll < 500 diff --git a/src/components/pages/MainPage/Streaming/Streaming.tsx b/src/components/pages/MainPage/Streaming/Streaming.tsx index 1afc0094..d643e544 100644 --- a/src/components/pages/MainPage/Streaming/Streaming.tsx +++ b/src/components/pages/MainPage/Streaming/Streaming.tsx @@ -37,7 +37,6 @@ export function Streaming() { const [point, setPoint] = useState([0, 0]); const [muted, setMuted] = useState(true); const [playing, setPlaying] = useState(true); - const [mouseDown, setMouseDown] = useState(false); function handleProgressbarClick(e: MouseEvent) { videoRef.current!.currentTime = @@ -125,10 +124,10 @@ export function Streaming() { className="lg:aspect-[1400/640] sm:aspect-[736/480] aspect-[340/600] rounded-2xl w-full h-full object-cover" /> <div className="absolute left-0 top-0 h-5/6 w-full z-[1]"> - <div ref={ref} className="relative w-full h-full"> + <div ref={ref} className="relative w-full h-full group"> <button ref={btnRef} - className="bg-[#37393B99] p-[50px] backdrop-blur-[30.72px] rounded-full in-hover:opacity-100 transition-opacity in-hover:cursor-none opacity-0 sticky" + className="bg-[#37393B99] p-[50px] backdrop-blur-[30.72px] rounded-full group-hover:opacity-100 transition-opacity group-hover:cursor-none opacity-0 sticky outline-none" style={{ left: point[0] - 64, top: point[1] - 64 }} onClick={handleVideoClick} > diff --git a/src/components/pages/ProjectsPage/AwardsCard.tsx b/src/components/pages/ProjectsPage/AwardsCard.tsx index 7c36dcc3..79ec6ce6 100644 --- a/src/components/pages/ProjectsPage/AwardsCard.tsx +++ b/src/components/pages/ProjectsPage/AwardsCard.tsx @@ -25,7 +25,7 @@ export function AwardsCard({ className }: { className?: string }) { <Image src={'/img/components/header/show_case_card.png'} fill - sizes="calc(225/361*100%)" + sizes="100%" alt="upside" className="object-cover !relative" /> diff --git a/src/components/pages/ProjectsPage/ProjectsSection.tsx b/src/components/pages/ProjectsPage/ProjectsSection.tsx index 63da8cd8..b5d32693 100644 --- a/src/components/pages/ProjectsPage/ProjectsSection.tsx +++ b/src/components/pages/ProjectsPage/ProjectsSection.tsx @@ -1,7 +1,6 @@ 'use client'; import { IProject } from '@/types/IProject'; -import { Icon } from '@/ui/Icon'; import Link from 'next/link'; import { usePathname } from 'next/navigation'; import { AwardsCard } from './AwardsCard'; @@ -30,7 +29,7 @@ export function ProjectsSection({ projects }: { projects: IProject[] }) { className="rounded-xl bg-[#232425] aspect-square h-fit self-center p-5 opacity-60 hover:opacity-100 transition-opacity flex items-center justify-center btnl font-medium gap-2" > Смотреть все - <Icon name="arrow_more" color="white" size={20} /> + {/* <Icon name="arrow_more" color="white" size={20} /> */} </Link> )} </div> diff --git a/src/components/pages/ProjectsPage/TagsFilters.tsx b/src/components/pages/ProjectsPage/TagsFilters.tsx index 192eeb66..473db62f 100644 --- a/src/components/pages/ProjectsPage/TagsFilters.tsx +++ b/src/components/pages/ProjectsPage/TagsFilters.tsx @@ -3,8 +3,9 @@ import { postTags } from '@/consts/postTags'; import { projectsTags } from '@/consts/projectsTags'; import { Icon } from '@/ui/Icon'; +import { LazySvg } from '@/ui/LazySvg'; import { usePathname, useRouter, useSearchParams } from 'next/navigation'; -import { useRef, useState } from 'react'; +import { Suspense, useRef, useState } from 'react'; import { useOnClickOutside } from 'usehooks-ts'; import { TagFilter } from './TagsFilter'; @@ -90,7 +91,9 @@ export function TagsFilters({ className="gap-x-2 rounded-2xl flex items-center pl-6 p-4 bg-[#37393B99] backdrop-blur-sm" > <p className="btnm font-medium">Фильтры</p> - <Icon name={'filters'} color="white" /> + <Suspense fallback={<div className="w-4 h-4" />}> + <LazySvg name="filters" color="white" width={16} height={16} /> + </Suspense> </button> )} </div> diff --git a/src/hooks/useDynamicSvgImport.ts b/src/hooks/useDynamicSvgImport.ts index a2dc3a27..fd12ca57 100644 --- a/src/hooks/useDynamicSvgImport.ts +++ b/src/hooks/useDynamicSvgImport.ts @@ -9,14 +9,11 @@ export function useDynamicSvgImport(iconName: string) { useEffect(() => { setLoading(true); - // dynamically import the mentioned svg icon name in props const importSvgIcon = async (): Promise<void> => { - // please make sure all your svg icons are placed in the same directory - // if we want that part to be configurable then instead of iconName we will send iconPath as prop try { importedIconRef.current = ( await import(`../../public/icons/${iconName}.svg`) - ).default; // svgr provides ReactComponent for given svg path + ).default; } catch (err) { setError(err); console.error(err); diff --git a/src/hooks/useMediaQueries.ts b/src/hooks/useMediaQueries.ts index e5a60128..e1e94fcd 100644 --- a/src/hooks/useMediaQueries.ts +++ b/src/hooks/useMediaQueries.ts @@ -15,25 +15,25 @@ export function useMediaQueries(lg = 1024, md = 768, sm = 640) { const handler = (e: MediaQueryListEvent) => setIsLg(e.matches); lgMedia.addEventListener('change', handler); return () => lgMedia.removeEventListener('change', handler); - }, []); + }, [lgMedia]); useEffect(() => { const handler = (e: MediaQueryListEvent) => setIsMd(e.matches); mdMedia.addEventListener('change', handler); return () => mdMedia.removeEventListener('change', handler); - }, []); + }, [mdMedia]); useEffect(() => { const handler = (e: MediaQueryListEvent) => setIsSm(e.matches); smMedia.addEventListener('change', handler); return () => smMedia.removeEventListener('change', handler); - }, []); + }, [smMedia]); useEffect(() => { const handler = (e: MediaQueryListEvent) => setIsXs(e.matches); xsMedia.addEventListener('change', handler); return () => xsMedia.removeEventListener('change', handler); - }, []); + }, [xsMedia]); return { isLg, isMd, isSm, isXs }; } diff --git a/src/ui/Figure.tsx b/src/ui/Figure.tsx index f4207a52..16dff57c 100644 --- a/src/ui/Figure.tsx +++ b/src/ui/Figure.tsx @@ -1,10 +1,9 @@ 'use client'; import { motion, useInView, useMotionValue, useSpring } from 'framer-motion'; -import { Manrope } from 'next/font/google'; import { useEffect, useRef } from 'react'; -const manrope = Manrope({ subsets: ['latin'] }); +// const manrope = Manrope({ subsets: ['latin'] }); export function Figure({ percent, diff --git a/src/ui/LazySvg.tsx b/src/ui/LazySvg.tsx new file mode 100644 index 00000000..b784fa62 --- /dev/null +++ b/src/ui/LazySvg.tsx @@ -0,0 +1,15 @@ +import dynamic from 'next/dynamic'; +import { ComponentProps } from 'react'; + +interface LazySvgProps extends ComponentProps<'svg'> { + name: string; +} + +export const LazySvg = async ({ name, ...props }: LazySvgProps) => { + const Svg = dynamic(() => import('../../public/icons/' + name + '.svg')); + + // Or without using `dynamic`: + // We use `default` here because `@svgr/webpack` converts all other *.svg imports to React components, this might be different for other loaders. + + return <Svg {...props} />; +}; diff --git a/src/ui/SeasonCard.tsx b/src/ui/SeasonCard.tsx index 05ee7d43..63dfa5d9 100644 --- a/src/ui/SeasonCard.tsx +++ b/src/ui/SeasonCard.tsx @@ -21,7 +21,7 @@ export function SeasonCard({ className="!relative lg:min-w-full md:min-w-[calc(138/224*100%)]" alt={title} fill - sizes="(min-width: 768px) calc(138/224*100%), (min-width: 1024px) 100%" + sizes="100%" /> </div> <p className="text1 md:font-medium text-center">{title}</p> diff --git a/src/ui/SlideBadge.tsx b/src/ui/SlideBadge.tsx index 641e4bbf..5c690d9b 100644 --- a/src/ui/SlideBadge.tsx +++ b/src/ui/SlideBadge.tsx @@ -21,7 +21,7 @@ export function SlideBadge({ alt={title} fill className="rounded-xl !relative" - sizes="(min-width: 1024px) 48px, (min-width: 768px) 125px, 64px" + sizes="100%" /> </div> <p className="text1">{title}</p>