diff --git a/src/components/Object/Object.jsx b/src/components/Object/Object.jsx
index 5ab7ad6..5e45bac 100644
--- a/src/components/Object/Object.jsx
+++ b/src/components/Object/Object.jsx
@@ -1,16 +1,55 @@
-import './Object.scss';
+import "./Object.scss";
+import { useState } from "react";
function Object(props) {
- return (
-
-

-
-
{props.price}
-
{props.desc}
-
{props.address}
-
+ const [isExpanded, setIsExpanded] = useState(false);
+
+ const addressLimit = 30;
+ const isAddressTooLong = props.address && props.address.length > addressLimit;
+ const needsExpansion = isAddressTooLong;
+
+ const truncateAddress = (text) => {
+ if (!text) return "";
+ if (isExpanded) return text;
+ if (text.length <= addressLimit) return text;
+
+ const truncated = text.substring(0, addressLimit);
+ const lastSpaceIndex = truncated.lastIndexOf(" ");
+ if (lastSpaceIndex > 0) {
+ return truncated.substring(0, lastSpaceIndex) + "...";
+ }
+ return truncated + "...";
+ };
+
+ const toggleExpansion = () => {
+ setIsExpanded(!isExpanded);
+ };
+
+ return (
+
+

+
+
+
{props.price}
+
+ {props.desc}
+
+
+ {truncateAddress(props.address)}
+
- );
+ {needsExpansion && (
+
+ )}
+
+
+ );
}
export { Object };
diff --git a/src/components/Object/Object.scss b/src/components/Object/Object.scss
index b2deba1..1d64e70 100644
--- a/src/components/Object/Object.scss
+++ b/src/components/Object/Object.scss
@@ -1,158 +1,281 @@
-@import '../../styles/vars.scss';
+@import "../../styles/vars.scss";
.item__info p {
- margin: 0 0 12px 0;
+ margin: 0 0 12px 0;
}
.item {
- display: flex;
- flex-direction: column;
- // width: 381px;
- // height: 381px;
- margin: 0 20px;
- border-radius: 15px;
- background-color: white;
+ display: flex;
+ flex-direction: column;
+ margin: 0 20px;
+ border-radius: 15px;
+ background-color: white;
+ min-height: 450px;
+ transition: height 0.3s ease;
- @media (max-width: 1300px) {
- height: 381px;
- }
+ &--expanded {
+ height: auto;
+ min-height: 450px;
+ }
- @media (max-width: 1200px) {
- height: 361px;
- }
+ @media (min-width: 1800px) {
+ min-height: 480px;
- @media (max-width: 1100px) {
- height: 341px;
+ &--expanded {
+ min-height: 480px;
}
+ }
- @media (max-width: $laptopWidth) {
- height: 321px;
- margin: 0 15px;
- }
+ @media (max-width: 1300px) {
+ min-height: 430px;
- @media (max-width: $tabletWidth) {
- height: 505px;
+ &--expanded {
+ min-height: 430px;
}
+ }
- @media (max-width: 740px) {
- height: 473px;
- }
+ @media (max-width: 1200px) {
+ min-height: 410px;
- @media (max-width: 690px) {
- height: 435px;
+ &--expanded {
+ min-height: 410px;
}
+ }
- @media (max-width: 635px) {
- height: 400px;
- }
+ @media (max-width: 1100px) {
+ min-height: 390px;
- @media (max-width: 570px) {
- height: 361px;
+ &--expanded {
+ min-height: 390px;
}
+ }
- @media (max-width: $mobileWidth) {
- height: 381px;
- }
+ @media (max-width: $laptopWidth) {
+ min-height: 370px;
+ margin: 0 15px;
- @media (max-width: 420px) {
- height: 361px;
+ &--expanded {
+ min-height: 370px;
}
+ }
+
+ @media (max-width: $tabletWidth) {
+ min-height: 500px;
+
+ &--expanded {
+ min-height: 500px;
+ }
+ }
+
+ @media (max-width: 740px) {
+ min-height: 480px;
+
+ &--expanded {
+ min-height: 480px;
+ }
+ }
+
+ @media (max-width: 690px) {
+ min-height: 460px;
+
+ &--expanded {
+ min-height: 460px;
+ }
+ }
+
+ @media (max-width: 635px) {
+ min-height: 440px;
+
+ &--expanded {
+ min-height: 440px;
+ }
+ }
+
+ @media (max-width: 570px) {
+ min-height: 420px;
+
+ &--expanded {
+ min-height: 420px;
+ }
+ }
+
+ @media (max-width: $mobileWidth) {
+ min-height: 400px;
+ margin: 0 10px;
+
+ &--expanded {
+ min-height: 400px;
+ }
+ }
+
+ @media (max-width: 420px) {
+ min-height: 380px;
+
+ &--expanded {
+ min-height: 380px;
+ }
+ }
}
-
.item__image:hover {
- text-decoration: none;
+ text-decoration: none;
}
.item__image {
- border-top-right-radius: 15px;
- border-top-left-radius: 15px;
- width: 100%;
+ border-top-right-radius: 15px;
+ border-top-left-radius: 15px;
+ width: 100%;
+ height: 250px;
+ object-fit: cover;
+ object-position: center;
+ display: block;
+
+ @media (max-width: 1300px) {
+ height: 230px;
+ }
+
+ @media (max-width: 1200px) {
+ height: 210px;
+ }
+
+ @media (max-width: 1100px) {
+ height: 190px;
+ }
+
+ @media (max-width: $laptopWidth) {
+ height: 170px;
+ }
+
+ @media (max-width: $tabletWidth) {
+ height: 300px;
+ }
+
+ @media (max-width: 740px) {
+ height: 280px;
+ }
+
+ @media (max-width: 690px) {
height: 250px;
- object-fit: cover;
- object-position: center;
- display: block;
+ }
- @media (max-width: 1300px) {
- height: 230px;
- }
+ @media (max-width: 635px) {
+ height: 220px;
+ }
- @media (max-width: 1200px) {
- height: 210px;
- }
+ @media (max-width: 570px) {
+ height: 190px;
+ }
- @media (max-width: 1100px) {
- height: 190px;
- }
+ @media (max-width: $mobileWidth) {
+ height: 210px;
+ }
- @media (max-width: $laptopWidth) {
- height: 170px;
- }
-
- @media (max-width: $tabletWidth) {
- height: 300px;
- }
-
- @media (max-width: 740px) {
- height: 280px;
- }
-
- @media (max-width: 690px) {
- height: 250px;
- }
-
- @media (max-width: 635px) {
- height: 220px;
- }
-
- @media (max-width: 570px) {
- height: 190px;
- }
-
- @media (max-width: $mobileWidth) {
- height: 210px;
- }
-
- @media (max-width: 420px) {
- height: 190px;
- }
+ @media (max-width: 420px) {
+ height: 190px;
+ }
}
.item__info {
- margin: 25px 0 13px 25px;
+ margin: 20px 20px 15px 20px;
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ min-height: 0;
+
+ @media (max-width: $mobileWidth) {
+ margin: 15px 15px 10px 15px;
+ }
+}
+
+.item__content {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
}
.item__price {
- font-size: 25px;
+ font-size: 25px;
- @media (min-width: 1800px) {
- font-size: 29px;
- }
+ @media (min-width: 1800px) {
+ font-size: 29px;
+ }
- @media (min-width: 768.98px) and (max-width: $laptopWidth) {
- font-size: 23px;
- }
+ @media (min-width: 768.98px) and (max-width: $laptopWidth) {
+ font-size: 23px;
+ }
}
.item__desc {
- font-size: 20px;
+ font-size: 20px;
+ line-height: 1.4;
+ margin-bottom: 8px !important;
+ word-wrap: break-word;
+ hyphens: auto;
- @media (min-width: 1800px) {
- font-size: 24px;
- }
+ @media (min-width: 1800px) {
+ font-size: 24px;
+ }
- @media (min-width: 768.98px) and (max-width: $laptopWidth) {
- font-size: 18px;
- }
+ @media (min-width: 768.98px) and (max-width: $laptopWidth) {
+ font-size: 18px;
+ }
}
.item__address {
- font-size: 17px;
+ font-size: 17px;
+ line-height: 1.3;
+ word-wrap: break-word;
+ hyphens: auto;
- @media (min-width: 1800px) {
- font-size: 21px;
- }
+ @media (min-width: 1800px) {
+ font-size: 21px;
+ }
- @media (min-width: 768.98px) and (max-width: $laptopWidth) {
- font-size: 16px;
- }
-}
\ No newline at end of file
+ @media (min-width: 768.98px) and (max-width: $laptopWidth) {
+ font-size: 16px;
+ }
+}
+
+.item__expand-btn {
+ background: none;
+ border: none;
+ color: #007bff;
+ font-size: 11px;
+ font-weight: 500;
+ cursor: pointer;
+ padding: 4px 0;
+ margin-top: auto;
+ margin-bottom: 5px;
+ text-align: left;
+ transition: color 0.2s ease;
+ font-family: inherit;
+ flex-shrink: 0;
+ max-width: 100%;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+
+ &:hover {
+ color: #0056b3;
+ text-decoration: underline;
+ }
+
+ &:focus {
+ outline: none;
+ }
+
+ @media (min-width: 1800px) {
+ font-size: 13px;
+ padding: 5px 0;
+ }
+
+ @media (min-width: 768.98px) and (max-width: $laptopWidth) {
+ font-size: 10px;
+ padding: 3px 0;
+ }
+
+ @media (max-width: $mobileWidth) {
+ font-size: 11px;
+ margin-bottom: 3px;
+ }
+}
diff --git a/src/components/Sliders/SliderObjects.jsx b/src/components/Sliders/SliderObjects.jsx
index fc04b00..02dd93f 100644
--- a/src/components/Sliders/SliderObjects.jsx
+++ b/src/components/Sliders/SliderObjects.jsx
@@ -1,119 +1,124 @@
-import React, { useState, useEffect } from 'react';
-import Slider from 'react-slick';
-import { Link } from 'react-router-dom';
-import { useMediaQuery } from 'react-responsive';
+import React, { useState, useEffect } from "react";
+import Slider from "react-slick";
+import { useMediaQuery } from "react-responsive";
-import 'slick-carousel/slick/slick.css';
-import 'slick-carousel/slick/slick-theme.css';
-import './SliderObjects.scss';
-import { Object } from '../Object/Object';
-import { API_CONFIG } from '../../config/contacts';
+import "slick-carousel/slick/slick.css";
+import "slick-carousel/slick/slick-theme.css";
+import "./SliderObjects.scss";
+import { Object } from "../Object/Object";
+import { API_CONFIG } from "../../config/contacts";
-import objectPicOne from '../../assets/images/apartaments/image-44.jpg';
-import objectPicTwo from '../../assets/images/apartaments/image-45.jpg';
-import objectPicThree from '../../assets/images/apartaments/image-46.jpg';
+import objectPicOne from "../../assets/images/apartaments/image-44.jpg";
+import objectPicTwo from "../../assets/images/apartaments/image-45.jpg";
+import objectPicThree from "../../assets/images/apartaments/image-46.jpg";
const NextArrow = ({ onClick }) => {
- return (
-
- );
+ return (
+
+ );
};
const PrevArrow = ({ onClick }) => {
- return (
-
- );
+ return (
+
+ );
};
const SliderComponent = () => {
- const [objects, setObjects] = useState([]);
- const [loading, setLoading] = useState(true);
-
- const isMobileResolution = useMediaQuery({ maxWidth: 768 });
-
- // Загрузка данных с API
- useEffect(() => {
- const fetchObjects = async () => {
- try {
- const response = await fetch(API_CONFIG.getFullURL(API_CONFIG.endpoints.rental), {
- method: 'GET',
- headers: {
- 'accept': '*/*'
- }
- });
+ const [objects, setObjects] = useState([]);
+ const [loading, setLoading] = useState(true);
- if (response.ok) {
- const data = await response.json();
- setObjects(data);
- }
- } catch (error) {
- console.error('Ошибка при загрузке объектов:', error);
- // В случае ошибки оставляем пустой массив, компонент не сломается
- } finally {
- setLoading(false);
- }
- };
+ const isMobileResolution = useMediaQuery({ maxWidth: 768 });
- fetchObjects();
- }, []);
-
- const settings = {
- dots: objects.length > (isMobileResolution ? 1 : 3), // Показываем точки если объектов больше чем влезает
- infinite: objects.length > (isMobileResolution ? 1 : 3), // Бесконечная прокрутка только если объектов достаточно
- speed: 500,
- slidesToShow: isMobileResolution ? 1 : 3,
- slidesToScroll: isMobileResolution ? 1 : 3,
- arrows: true,
- nextArrow:
,
- prevArrow:
,
+ // Загрузка данных с API
+ useEffect(() => {
+ const fetchObjects = async () => {
+ try {
+ const response = await fetch(
+ API_CONFIG.getFullURL(API_CONFIG.endpoints.rental),
+ {
+ method: "GET",
+ headers: {
+ accept: "*/*",
+ },
+ }
+ );
+
+ if (response.ok) {
+ const data = await response.json();
+ setObjects(data);
+ }
+ } catch (error) {
+ console.error("Ошибка при загрузке объектов:", error);
+
+ } finally {
+ setLoading(false);
+ }
};
- // Если загружаем данные, показываем статические объекты как fallback
- if (loading || objects.length === 0) {
- return (
-
-
-
-
-
-
-
-
-
- );
- }
+ fetchObjects();
+ }, []);
+ const settings = {
+ dots: objects.length > (isMobileResolution ? 1 : 3),
+ infinite: objects.length > (isMobileResolution ? 1 : 3),
+ speed: 500,
+ slidesToShow: isMobileResolution ? 1 : 3,
+ slidesToScroll: isMobileResolution ? 1 : 3,
+ arrows: true,
+ nextArrow:
,
+ prevArrow:
,
+ };
+
+
+ if (loading || objects.length === 0) {
return (
-
-
- {objects.map((object) => (
-
-
-
- ))}
-
-
+
+
+
+
+
+
+
);
+ }
+
+ return (
+
+
+ {objects.map((object) => (
+
+ ))}
+
+
+ );
};
export { SliderComponent };
diff --git a/src/config/contacts.js b/src/config/contacts.js
index 6dca52a..432d72e 100644
--- a/src/config/contacts.js
+++ b/src/config/contacts.js
@@ -15,12 +15,6 @@ export const CONTACTS = {
postalCode: "454052",
full: "ул. Комаровского, 4А, офис 210, Челябинск, 454052",
},
- office: {
- street: "Ленина, д. 60 В, оф. 701",
- city: "Челябинск",
- description: "Вход в офис со двора",
- full: "Ленина, д. 60 В, оф. 701, Челябинск",
- },
},
coordinates: [55.242355, 61.37697],
diff --git a/src/pages/Office/Office.jsx b/src/pages/Office/Office.jsx
index 1372afe..c4bee58 100644
--- a/src/pages/Office/Office.jsx
+++ b/src/pages/Office/Office.jsx
@@ -90,10 +90,8 @@ function Office() {
Адрес:
- {CONTACTS.address.office.full}
-
- {CONTACTS.address.office.description}
-
+ {CONTACTS.address.main.full}
+ Вход в офис со двора
Телефон: