(false);
+
+ return (
+
+
+
+ {APP_NAME}
+
+
+ setIsOpen(!isOpen)} />
+
+
+
+ {headerLinks.map(({ title, link, newTab }) => (
+
+ {title}
+
+ ))}
+
+
+
+ );
+};
+
+export default Header;
diff --git a/src/components/main/rector/RectorSectionWrapper.styled.tsx b/src/components/main/rector/RectorSectionWrapper.styled.tsx
index c9eed79..7f72390 100644
--- a/src/components/main/rector/RectorSectionWrapper.styled.tsx
+++ b/src/components/main/rector/RectorSectionWrapper.styled.tsx
@@ -1,16 +1,14 @@
-import styled from 'styled-components';
-
-export const RectorSectionWrapper = styled.section`
- display: flex;
- flex-direction: column;
- padding: 0 1rem;
- max-width: 1600px;
- margin: 60px auto;
- gap: 24px;
- align-items: center;
-
- @media (min-width: ${({ theme }) => theme.breakpoints.desktop}) {
- flex-direction: row;
- gap: 82px;
- }
-`;
+import styled from 'styled-components';
+
+export const RectorSectionWrapper = styled.section`
+ display: grid;
+ padding: 0 1rem;
+ max-width: 1200px;
+ margin: 60px auto;
+ gap: 24px;
+ justify-content: center;
+
+ @media (min-width: ${({ theme }) => theme.breakpoints.desktop}) {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+`;
diff --git a/src/components/main/rector/image/RectorImage.tsx b/src/components/main/rector/image/RectorImage.tsx
index 74735a5..955c51a 100644
--- a/src/components/main/rector/image/RectorImage.tsx
+++ b/src/components/main/rector/image/RectorImage.tsx
@@ -1,7 +1,7 @@
-import rector from '../../../../assets/images/rector.jpg';
-
-import { RectorImageWrapper } from './RectorImageWrapper.styled';
-
-export const RectorImage = () => {
- return ;
-};
+import rector from '../../../../assets/images/rector.jpg';
+
+import { RectorImageWrapper } from './RectorImageWrapper.styled';
+
+export const RectorImage = () => {
+ return ;
+};
diff --git a/src/components/main/rector/image/RectorImageWrapper.styled.tsx b/src/components/main/rector/image/RectorImageWrapper.styled.tsx
index e9704bc..2ba0ed4 100644
--- a/src/components/main/rector/image/RectorImageWrapper.styled.tsx
+++ b/src/components/main/rector/image/RectorImageWrapper.styled.tsx
@@ -1,15 +1,14 @@
-import styled from 'styled-components';
-
-export const RectorImageWrapper = styled.img`
- width: 90%;
- max-width: 360px;
- height: 30vh;
- object-fit: cover;
- border-radius: 12px;
-
- @media (min-width: ${({ theme }) => theme.breakpoints.desktop}) {
- max-width: 519px;
- width: 40%;
- height: 519px;
- }
-`;
+import styled from 'styled-components';
+
+export const RectorImageWrapper = styled.img`
+ width: 100%;
+ max-width: 360px;
+ height: 30vh;
+ object-fit: cover;
+ border-radius: 12px;
+
+ @media (min-width: ${({ theme }) => theme.breakpoints.desktop}) {
+ max-width: 519px;
+ height: 519px;
+ }
+`;
diff --git a/src/components/main/rector/text/RectorText.tsx b/src/components/main/rector/text/RectorText.tsx
index 28b8290..b49e4b4 100644
--- a/src/components/main/rector/text/RectorText.tsx
+++ b/src/components/main/rector/text/RectorText.tsx
@@ -1,39 +1,39 @@
-import { RectorTextWrapper } from './RectorTextWrapper.styled';
-
-export const RectorText = () => {
- return (
-
- Vážení studenti,
-
-
- rád bych vám osobně poděkoval, že jste se rozhodli zapsat
- a nastoupit ke studiu na Univerzitě Tomáše Bati ve Zlíně
- navzdory nejistotě, která v této době panuje.
-
-
-
- Stojíte nyní na prahu nové životní etapy, abyste se naučili novým
- znalostem a dovednostem, poznali nové kamarády, a také získali
- i zahraniční zkušenost.
-
-
-
- Tento průvodce vám pomůže se rychleji zorientovat v univerzitním
- prostředí, a rovněž zpříjemnit váš studentský život.
-
-
-
- Nebojte se v případě potřeby obrátit o pomoc na studijní
- oddělení či na některou poradnu, nebo jen požádejte o radu staršího
- spolužáka. Rozhodně se nenechte odradit od studia po prvních nezdarech
- u zkoušek, ale o to více pilně studujte. Věřím, že za několik
- let sklidíte plody své práce.
-
-
- Přeji vám pevné zdraví a hodně optimismu a sil!
-
-
- Milan Adámek, rektor
-
- );
-};
+import { RectorTextWrapper } from './RectorTextWrapper.styled';
+
+export const RectorText = () => {
+ return (
+
+ Vážení studenti,
+
+
+ rád bych vám osobně poděkoval, že jste se rozhodli zapsat
+ a nastoupit ke studiu na Univerzitě Tomáše Bati ve Zlíně
+ navzdory nejistotě, která v této době panuje.
+
+
+
+ Stojíte nyní na prahu nové životní etapy, abyste se naučili novým
+ znalostem a dovednostem, poznali nové kamarády, a také získali
+ i zahraniční zkušenost.
+
+
+
+ Tento průvodce vám pomůže se rychleji zorientovat v univerzitním
+ prostředí, a rovněž zpříjemnit váš studentský život.
+
+
+
+ Nebojte se v případě potřeby obrátit o pomoc na studijní
+ oddělení či na některou poradnu, nebo jen požádejte o radu staršího
+ spolužáka. Rozhodně se nenechte odradit od studia po prvních nezdarech
+ u zkoušek, ale o to více pilně studujte. Věřím, že za několik
+ let sklidíte plody své práce.
+
+
+ Přeji vám pevné zdraví a hodně optimismu a sil!
+
+
+ Milan Adámek, rektor
+
+ );
+};
diff --git a/src/components/main/rector/text/RectorTextWrapper.styled.tsx b/src/components/main/rector/text/RectorTextWrapper.styled.tsx
index d7db52f..5d1215d 100644
--- a/src/components/main/rector/text/RectorTextWrapper.styled.tsx
+++ b/src/components/main/rector/text/RectorTextWrapper.styled.tsx
@@ -1,13 +1,15 @@
-import styled from 'styled-components';
-
-export const RectorTextWrapper = styled.article`
- p {
- font-style: normal;
- font-weight: 400;
- font-size: 16px;
-
- @media (min-width: ${({ theme }) => theme.breakpoints.tablet}) {
- font-size: 20px;
- }
- }
-`;
+import styled from 'styled-components';
+
+export const RectorTextWrapper = styled.article`
+ p {
+ font-style: normal;
+ font-weight: 400;
+ font-size: 16px;
+ max-width: 400px;
+
+ @media (min-width: ${({ theme }) => theme.breakpoints.tablet}) {
+ font-size: 20px;
+ max-width: 500px;
+ }
+ }
+`;
diff --git a/src/components/main/section/SectionWrapper.tsx b/src/components/main/section/SectionWrapper.tsx
index 0875294..742576a 100644
--- a/src/components/main/section/SectionWrapper.tsx
+++ b/src/components/main/section/SectionWrapper.tsx
@@ -1,21 +1,21 @@
-import { useContext } from 'react';
-
-import { SectionListContext } from '../../../contexts/SectionListContext';
-import { SectionWrapperStyled } from './SectionWrapper.styled';
-import { SearchSection } from './search/SearchSection';
-import { SectionList } from './sectionList/SectionList';
-
-export const SectionWrapper = () => {
- const [sectionList] = useContext(SectionListContext);
-
- const sortedSectionList = sectionList.sort((a, b) =>
- a.title.toLowerCase() > b.title.toLowerCase() ? 1 : -1,
- );
-
- return (
-
-
-
-
- );
-};
+import { useContext } from 'react';
+
+import { SectionListContext } from '../../../contexts/SectionListContext';
+import { SectionWrapperStyled } from './SectionWrapper.styled';
+import { SearchSection } from './search/SearchSection';
+import { SectionList } from './sectionList/SectionList';
+
+export const SectionWrapper = () => {
+ const [sectionList] = useContext(SectionListContext);
+
+ const sortedSectionList = sectionList.sort((a, b) =>
+ a.title.toLowerCase() > b.title.toLowerCase() ? 1 : -1,
+ );
+
+ return (
+
+
+
+
+ );
+};
diff --git a/src/components/main/section/sectionList/SectionList.tsx b/src/components/main/section/sectionList/SectionList.tsx
index c379c72..8d015df 100644
--- a/src/components/main/section/sectionList/SectionList.tsx
+++ b/src/components/main/section/sectionList/SectionList.tsx
@@ -1,27 +1,28 @@
-import { ISection } from '../../../../lib/interfaces/ISection';
-import { ContentCard } from '../../../shared/contentCard/ContentCard';
-import { SectionListWrapper } from './SectionListWrapper.styled';
-import { SectionHeader } from './header/SectionHeader';
-
-interface Props {
- sectionList: ISection[];
-}
-// TODO: Change the prefix value once it's updated in routes and backend
-export const SectionList = ({ sectionList }: Props) => {
- return (
- <>
-
-
- {sectionList.map(({ id, title, slug, color }) => (
-
- ))}
-
- >
- );
-};
+import { ISection } from '../../../../lib/interfaces/ISection';
+import { ContentCard } from '../../../shared/contentCard/ContentCard';
+import { SectionListWrapper } from './SectionListWrapper.styled';
+import { SectionHeader } from './header/SectionHeader';
+
+interface Props {
+ sectionList: ISection[];
+}
+
+export const SectionList = ({ sectionList }: Props) => {
+ return (
+ <>
+
+
+ {sectionList.map(({ id, title, slug, color, icon }) => (
+
+ ))}
+
+ >
+ );
+};
diff --git a/src/components/shared/cardSlider/CardSlider.tsx b/src/components/shared/cardSlider/CardSlider.tsx
index 1ea9453..3eb719c 100644
--- a/src/components/shared/cardSlider/CardSlider.tsx
+++ b/src/components/shared/cardSlider/CardSlider.tsx
@@ -1,79 +1,82 @@
-import { useRef, useState } from 'react';
-import 'swiper/css';
-import 'swiper/css/navigation';
-import { Navigation } from 'swiper/modules';
-import { Swiper, SwiperSlide } from 'swiper/react';
-
-import { IContent } from '../../../lib/interfaces/IContent';
-import '../../../styles/swiper-custom.css';
-import { ContentCard } from '../contentCard/ContentCard';
-import { CardSliderWrapperStyled } from './CardSliderWrapper.styled';
-import NextButton from './navigation/NextButton';
-import { PrevButton } from './navigation/PrevButton';
-
-interface CardSliderProps {
- contentCards?: IContent[];
- canReplace?: boolean;
- sectionColor?: string;
-}
-
-const sliderBreakpoints = {
- 600: {
- slidesPerView: 2,
- spaceBetween: 30,
- },
- 900: {
- slidesPerView: 3,
- spaceBetween: 40,
- },
- 1200: {
- slidesPerView: 4,
- spaceBetween: 60,
- },
-};
-
-export const CardSlider = ({
- contentCards,
- canReplace = false,
- sectionColor,
-}: CardSliderProps) => {
- const swiperRef: any = useRef();
- const [reachedStart, setReachedStart] = useState(true);
- const [reachedEnd, setReachedEnd] = useState(false);
-
- const handleSlideChange = () => {
- setReachedStart(swiperRef.current.isBeginning);
- setReachedEnd(swiperRef.current.isEnd);
- };
-
- return (
-
- {
- swiperRef.current = swiper;
- }}
- spaceBetween={10}
- slidesPerView={1}
- slidesPerGroup={1}
- scrollbar={{ draggable: true }}
- onSlideChange={() => handleSlideChange()}
- onReachEnd={() => setReachedEnd(swiperRef.current.isEnd)}
- breakpoints={sliderBreakpoints}
- >
-
- {contentCards?.map(({ id, slug, title }) => (
-
-
-
- ))}
-
-
-
- );
-};
+import { useRef, useState } from 'react';
+import 'swiper/css';
+import 'swiper/css/navigation';
+import { Navigation } from 'swiper/modules';
+import { Swiper, SwiperSlide } from 'swiper/react';
+import { v4 as uuidv4 } from 'uuid';
+
+import { IContent } from '../../../lib/interfaces/IContent';
+import '../../../styles/swiper-custom.css';
+import { ContentCard } from '../contentCard/ContentCard';
+import { CardSliderWrapperStyled } from './CardSliderWrapper.styled';
+import NextButton from './navigation/NextButton';
+import { PrevButton } from './navigation/PrevButton';
+
+interface CardSliderProps {
+ contentCards?: IContent[];
+ canReplace?: boolean;
+ sectionColor?: string;
+}
+
+const sliderBreakpoints = {
+ 600: {
+ slidesPerView: 2,
+ spaceBetween: 30,
+ },
+ 900: {
+ slidesPerView: 3,
+ spaceBetween: 40,
+ },
+ 1200: {
+ slidesPerView: 4,
+ spaceBetween: 60,
+ },
+};
+
+export const CardSlider = ({
+ contentCards,
+ canReplace = false,
+ sectionColor,
+}: CardSliderProps) => {
+ const swiperRef: any = useRef();
+ const [reachedStart, setReachedStart] = useState(true);
+ const [reachedEnd, setReachedEnd] = useState(false);
+
+ const handleSlideChange = () => {
+ setReachedStart(swiperRef.current.isBeginning);
+ setReachedEnd(swiperRef.current.isEnd);
+ };
+
+ return (
+
+ {
+ swiperRef.current = swiper;
+ }}
+ spaceBetween={10}
+ slidesPerView={1}
+ slidesPerGroup={1}
+ scrollbar={{ draggable: true }}
+ onSlideChange={() => handleSlideChange()}
+ onReachEnd={() => setReachedEnd(swiperRef.current.isEnd)}
+ breakpoints={sliderBreakpoints}
+ >
+
+ {contentCards?.map(({ slug, title, image, icon }) => (
+
+
+
+ ))}
+
+
+
+ );
+};
diff --git a/src/components/shared/contentCard/ContentCard.styled.tsx b/src/components/shared/contentCard/ContentCard.styled.tsx
index 46d08b0..ec144d1 100644
--- a/src/components/shared/contentCard/ContentCard.styled.tsx
+++ b/src/components/shared/contentCard/ContentCard.styled.tsx
@@ -2,44 +2,61 @@ import { Link } from 'react-router-dom';
import styled from 'styled-components';
interface ContentCardWrapperProps {
- bgColor?: string;
width?: number;
}
export const ContentCardWrapper = styled.div`
width: ${({ width }) => (typeof width === 'number' ? `${width}px` : '100%')};
- padding-top: ${({ width }) => (typeof width === 'number' ? 0 : '100%')};
+ max-width: 260px;
height: 258px;
border-radius: 8px;
display: flex;
flex-direction: column;
- justify-content: end;
- align-items: center;
- background: ${({ bgColor }) => bgColor || '#ffdec9'};
filter: drop-shadow(-3px -3px 15px rgba(221, 171, 139, 0.5));
- color: black;
position: relative;
`;
-export const ContentCardHeadline = styled.h4`
- font-size: 20px;
- padding: 16px 12px;
- text-align: center;
- font-weight: 700;
+export const ContentCardBgIcon = styled.div<{ bgColor?: string }>`
+ background: ${({ bgColor }) => bgColor || '#ffdec9'};
+ height: 178px;
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border-top-left-radius: 8px;
+ border-top-right-radius: 8px;
+ img {
+ object-fit: cover;
+ width: 100%;
+ height: 100%;
+ }
+`;
+
+export const ContentCardHeadline = styled.div`
background: white;
width: 100%;
+ height: 80px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
- justify-self: end;
+
+ h4 {
+ font-size: 20px;
+ font-weight: 700;
+ text-align: center;
+ color: black;
+ padding: 0 12px;
+ display: -webkit-box;
+ max-width: 100%;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ }
`;
export const StyledLink = styled(Link)`
text-decoration: none;
`;
-
-export const ContentCardImg = styled.img`
- position: absolute;
- top: 30%;
- left: 50%;
- transform: translate(-50%, -30%);
-`;
diff --git a/src/components/shared/contentCard/ContentCard.tsx b/src/components/shared/contentCard/ContentCard.tsx
index 8c364b3..cf549c8 100644
--- a/src/components/shared/contentCard/ContentCard.tsx
+++ b/src/components/shared/contentCard/ContentCard.tsx
@@ -1,6 +1,6 @@
import {
+ ContentCardBgIcon,
ContentCardHeadline,
- ContentCardImg,
ContentCardWrapper,
StyledLink,
} from './ContentCard.styled';
@@ -11,6 +11,7 @@ export interface IContentCardProps {
canReplace?: boolean;
color?: string;
width?: number;
+ image?: string;
icon?: string;
}
@@ -20,15 +21,19 @@ export const ContentCard = ({
canReplace,
color,
width,
+ image,
icon,
}: IContentCardProps) => {
+ const src = image || icon;
return (
-
- {icon && (
-
- )}
- {title}
+
+
+ {src && }
+
+
+ {title}
+
);
diff --git a/src/configs/api.ts b/src/configs/api.ts
index 284466f..76310d1 100644
--- a/src/configs/api.ts
+++ b/src/configs/api.ts
@@ -1,7 +1,7 @@
-import axios from 'axios';
-
-import { API_BASE_URL } from '../lib/constants';
-
-export const api = axios.create({
- baseURL: API_BASE_URL,
-});
+import axios from 'axios';
+
+import { API_BASE_URL } from '../lib/constants';
+
+export const api = axios.create({
+ baseURL: API_BASE_URL,
+});
diff --git a/src/hooks/useFetchLanding.ts b/src/hooks/useFetchLanding.ts
index 81dec35..40f93e5 100644
--- a/src/hooks/useFetchLanding.ts
+++ b/src/hooks/useFetchLanding.ts
@@ -1,47 +1,47 @@
-import { useContext, useEffect, useState } from 'react';
-
-import { api } from '../configs/api';
-import { SectionListContext } from '../contexts/SectionListContext';
-import { PAGES_LANDING } from '../lib/constants';
-import { ILanding } from '../lib/interfaces/ILanding';
-
-const useFetchLanding = () => {
- const [data, setData] = useState();
- const [error, setError] = useState(null);
- const [isLoading, setIsLoading] = useState(true);
- const [sectonList, setSectionList] = useContext(SectionListContext);
-
- useEffect(() => {
- if (sectonList.length !== 0) {
- setIsLoading(false);
- return;
- }
- const abortController = new AbortController();
-
- const getData = async () => {
- try {
- const { data: landing } = await api.get(PAGES_LANDING, {
- signal: abortController.signal,
- });
- setData(landing);
- setSectionList(landing.sections);
- setError(null);
- } catch (err) {
- if (err instanceof Error) {
- setError(err.message);
- } else {
- setError('Neznámá chyba.');
- }
- } finally {
- setIsLoading(false);
- }
- };
-
- getData();
- return () => abortController.abort();
- }, []);
-
- return { data, isLoading, error };
-};
-
-export default useFetchLanding;
+import { useContext, useEffect, useState } from 'react';
+
+import { api } from '../configs/api';
+import { SectionListContext } from '../contexts/SectionListContext';
+import { PAGES_LANDING } from '../lib/constants';
+import { ILanding } from '../lib/interfaces/ILanding';
+
+const useFetchLanding = () => {
+ const [data, setData] = useState();
+ const [error, setError] = useState(null);
+ const [isLoading, setIsLoading] = useState(true);
+ const [sectonList, setSectionList] = useContext(SectionListContext);
+
+ useEffect(() => {
+ if (sectonList.length !== 0) {
+ setIsLoading(false);
+ return;
+ }
+ const abortController = new AbortController();
+
+ const getData = async () => {
+ try {
+ const { data: landing } = await api.get(PAGES_LANDING, {
+ signal: abortController.signal,
+ });
+ setData(landing);
+ setSectionList(landing.sections);
+ setError(null);
+ } catch (err) {
+ if (err instanceof Error) {
+ setError(err.message);
+ } else {
+ setError('Neznámá chyba.');
+ }
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ getData();
+ return () => abortController.abort();
+ }, []);
+
+ return { data, isLoading, error };
+};
+
+export default useFetchLanding;
diff --git a/src/lib/constants.ts b/src/lib/constants.ts
index 7b3ecf3..ba9a696 100644
--- a/src/lib/constants.ts
+++ b/src/lib/constants.ts
@@ -1,10 +1,10 @@
-export const SECTION_LIST_LIMIT: number = 6;
-
-export const API_BASE_URL: string = 'https://rezervacesutb.wz.cz/api';
-export const API_TEST_URL: string = 'http://localhost/api';
-export const SECTIONS: string = 'pages/sections';
-export const TOPICS: string = 'pages/topics';
-export const PAGES_LANDING: string = 'pages/landing';
-export const API_ROUTE_SEARCH: string = '/pages/landing/search';
-
-export const APP_NAME: string = 'Průvodce studenta';
+export const SECTION_LIST_LIMIT: number = 6;
+
+export const API_BASE_URL: string = 'https://pruvodcestudenta.utb.cz/api';
+export const API_TEST_URL: string = 'http://localhost/api';
+export const SECTIONS: string = 'pages/sections';
+export const TOPICS: string = 'pages/topics';
+export const PAGES_LANDING: string = 'pages/landing';
+export const API_ROUTE_SEARCH: string = '/pages/landing/search';
+
+export const APP_NAME: string = 'Průvodce studenta';
diff --git a/src/lib/interfaces/IContent.ts b/src/lib/interfaces/IContent.ts
index ff5c461..ebcded3 100644
--- a/src/lib/interfaces/IContent.ts
+++ b/src/lib/interfaces/IContent.ts
@@ -1,11 +1,12 @@
-export interface IContent {
- id: string;
- slug: string;
- title: string;
- color: string;
- image?: string;
- description: string;
- created_at: string;
- updated_at: string;
- location?: string;
-}
+export interface IContent {
+ id: string;
+ slug: string;
+ title: string;
+ color: string;
+ image?: string;
+ icon?: string;
+ description: string;
+ created_at: string;
+ updated_at: string;
+ location?: string;
+}