diff --git a/my-app/package-lock.json b/my-app/package-lock.json index c71e348..7ec7788 100644 --- a/my-app/package-lock.json +++ b/my-app/package-lock.json @@ -16,6 +16,7 @@ "devDependencies": { "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", + "@types/webpack-env": "^1.18.4", "@vitejs/plugin-react": "^4.2.1", "eslint": "^8.55.0", "eslint-plugin-react": "^7.33.2", @@ -1184,6 +1185,12 @@ "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", "dev": true }, + "node_modules/@types/webpack-env": { + "version": "1.18.4", + "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.4.tgz", + "integrity": "sha512-I6e+9+HtWADAWeeJWDFQtdk4EVSAbj6Rtz4q8fJ7mSr1M0jzlFcs8/HZ+Xb5SHzVm1dxH7aUiI+A8kA8Gcrm0A==", + "dev": true + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", diff --git a/my-app/package.json b/my-app/package.json index e3c90fc..789d25c 100644 --- a/my-app/package.json +++ b/my-app/package.json @@ -18,6 +18,7 @@ "devDependencies": { "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", + "@types/webpack-env": "^1.18.4", "@vitejs/plugin-react": "^4.2.1", "eslint": "^8.55.0", "eslint-plugin-react": "^7.33.2", diff --git a/my-app/src/App.jsx b/my-app/src/App.jsx index ed6cedb..a37deb2 100644 --- a/my-app/src/App.jsx +++ b/my-app/src/App.jsx @@ -1,13 +1,13 @@ import "./App.css"; import { Header } from "./Components/Header/Header"; -import { LandingPage } from "./Components/LandingPage/LandingPage"; -import { Portfolio } from "./Components/Portfolio/Portfolio"; +import { LandingPage } from "./Components/LandingPage/LandingPage.tsx"; +import { Portfolio } from "./Components/Portfolio/Portfolio.tsx"; import { Pricing } from "./Components/Pricing/Pricing"; import { ContactForm } from "./Components/ContactForm/ContactForm"; import { BrowserRouter, Route, Routes } from "react-router-dom"; import { PortfolioImage } from "./Components/Portfolio/PortfolioImage/portfolioimage"; import { NotFound } from "./Components/NotFound/NotFound"; -import { ThemeProvider } from "./providers/theme"; +import { ThemeProvider } from "./providers/theme.tsx"; import { Footer } from "./Components/Footer/Footer"; function App() { @@ -41,4 +41,4 @@ function App() { ); } -export default App; \ No newline at end of file +export default App; diff --git a/my-app/src/Components/BasketModal/BasketModal.jsx b/my-app/src/Components/BasketModal/BasketModal.jsx index efcf927..83e38fe 100644 --- a/my-app/src/Components/BasketModal/BasketModal.jsx +++ b/my-app/src/Components/BasketModal/BasketModal.jsx @@ -1,7 +1,7 @@ import styles from "./BasketModal.module.css"; import { Modal } from "../Modal/Modal.jsx"; import { useContext, useEffect } from "react"; -import { ThemeContext } from "../../providers/theme.jsx"; +import { ThemeContext } from "../../providers/theme.tsx"; export const BasketModal = ({ isOpen, onClose }) => { const { theme } = useContext(ThemeContext); diff --git a/my-app/src/Components/ContactForm/ContactForm.jsx b/my-app/src/Components/ContactForm/ContactForm.jsx index a4941d6..87263c6 100644 --- a/my-app/src/Components/ContactForm/ContactForm.jsx +++ b/my-app/src/Components/ContactForm/ContactForm.jsx @@ -2,7 +2,7 @@ import styles from "./ContactForm.module.css"; import classnames from "classnames"; import { validateEmail } from "../../utils/validationEmail.js"; import { useContext, useRef, useState } from "react"; -import { ThemeContext } from "../../providers/theme.jsx"; +import { ThemeContext } from "../../providers/theme.tsx"; export const ContactForm = () => { const [emailMessage, setEmailMessage] = useState(""); diff --git a/my-app/src/Components/Footer/Footer.jsx b/my-app/src/Components/Footer/Footer.jsx index 58e4995..1ee1782 100644 --- a/my-app/src/Components/Footer/Footer.jsx +++ b/my-app/src/Components/Footer/Footer.jsx @@ -1,5 +1,5 @@ import styles from "./Footer.module.css"; -import { ThemeContext } from "../../providers/theme"; +import { ThemeContext } from "../../providers/theme.tsx"; import { useContext } from "react"; import classnames from "classnames"; @@ -14,4 +14,4 @@ export const Footer = () => {

); -}; \ No newline at end of file +}; diff --git a/my-app/src/Components/Header/Header.jsx b/my-app/src/Components/Header/Header.jsx index 8c7d5e1..e16c45c 100644 --- a/my-app/src/Components/Header/Header.jsx +++ b/my-app/src/Components/Header/Header.jsx @@ -3,7 +3,7 @@ import classnames from "classnames"; import React, { useContext, useState } from "react"; import { BasketModal } from "../BasketModal/BasketModal"; import { NavLink } from "react-router-dom"; -import { ThemeContext } from "../../providers/theme"; +import { ThemeContext } from "../../providers/theme.tsx"; export const Header = () => { const [isCartModalOpen, setCartModalOpen] = useState(false); diff --git a/my-app/src/Components/LandingPage/LandingPage.jsx b/my-app/src/Components/LandingPage/LandingPage.tsx similarity index 74% rename from my-app/src/Components/LandingPage/LandingPage.jsx rename to my-app/src/Components/LandingPage/LandingPage.tsx index 9f68269..5954d39 100644 --- a/my-app/src/Components/LandingPage/LandingPage.jsx +++ b/my-app/src/Components/LandingPage/LandingPage.tsx @@ -1,9 +1,11 @@ -import { useState, useEffect, useContext } from "react"; +import {ReactElement, useState, useEffect, useContext } from "react"; import styles from "./LandingPage.module.css"; -import { ThemeContext } from "../../providers/theme"; +import { ThemeContext } from "../../providers/theme.tsx"; +import { LandingPageProps } from "./LandingPage.types"; + +export const LandingPage = ({ quotes }:LandingPageProps):ReactElement => { + const [quote, setQuote] = useState(quotes[0]); -export const LandingPage = ({ quotes }) => { - const [quote, setQuote] = useState(quotes[0]); const { theme } = useContext(ThemeContext); useEffect(() => { @@ -36,4 +38,4 @@ export const LandingPage = ({ quotes }) => { ); -}; \ No newline at end of file +}; diff --git a/my-app/src/Components/LandingPage/LandingPage.types.ts b/my-app/src/Components/LandingPage/LandingPage.types.ts new file mode 100644 index 0000000..ac8fb18 --- /dev/null +++ b/my-app/src/Components/LandingPage/LandingPage.types.ts @@ -0,0 +1,3 @@ +export interface LandingPageProps { + quotes: string[]; + } \ No newline at end of file diff --git a/my-app/src/Components/Modal/Modal.jsx b/my-app/src/Components/Modal/Modal.jsx index 5e7cd5a..f33f0b4 100644 --- a/my-app/src/Components/Modal/Modal.jsx +++ b/my-app/src/Components/Modal/Modal.jsx @@ -1,5 +1,5 @@ import styles from "./Modal.module.css"; -import { ThemeContext } from "../../providers/theme"; +import { ThemeContext } from "../../providers/theme.tsx"; import { useContext } from "react"; export const Modal = ({ children }) => { @@ -10,4 +10,4 @@ export const Modal = ({ children }) => {
{children}
); -}; \ No newline at end of file +}; diff --git a/my-app/src/Components/NotFound/NotFound.jsx b/my-app/src/Components/NotFound/NotFound.jsx index 391082d..aafce8d 100644 --- a/my-app/src/Components/NotFound/NotFound.jsx +++ b/my-app/src/Components/NotFound/NotFound.jsx @@ -1,5 +1,5 @@ import styles from "./NotFound.module.css"; -import { ThemeContext } from "../../providers/theme"; +import { ThemeContext } from "../../providers/theme.tsx"; import { useContext } from "react"; import classnames from "classnames"; diff --git a/my-app/src/Components/Portfolio/Portfolio.jsx b/my-app/src/Components/Portfolio/Portfolio.jsx index a096cd7..a7abe4d 100644 --- a/my-app/src/Components/Portfolio/Portfolio.jsx +++ b/my-app/src/Components/Portfolio/Portfolio.jsx @@ -1,42 +1,53 @@ import styles from "./Portfolio.module.css"; -import portfolioData from "../../../public/photos.json"; -import { useContext, useState } from "react"; +import { useContext, useEffect, useState } from "react"; import { Link } from "react-router-dom"; -import { ThemeContext } from "../../providers/theme"; +import { ThemeContext } from "../../providers/theme.tsx"; export const Portfolio = () => { const [imageId, setImageId] = useState(null); const { theme } = useContext(ThemeContext); + const [portfolioData, setPortfolioData] = useState(null); + + useEffect(() => { + fetch("/photos.json") + .then((res) => res.json()) + .then((data) => { + setPortfolioData(data); + console.log(data); + }); + }, []); return ( -
-

- Our portfolio -

-
-

- We are experienced in taking photos for all kinds of circumstances. -
- Below is a summary of our extensive portfolio, with us you will always - look good! -

-
-
- {portfolioData.photos.map((photo) => ( -
- - { - setImageId(photo.id); - }} - /> - -
- ))} + portfolioData && ( +
+

+ Our portfolio +

+
+

+ We are experienced in taking photos for all kinds of circumstances. +
+ Below is a summary of our extensive portfolio, with us you will + always look good! +

+
+
+ {portfolioData.photos.map((photo) => ( +
+ + { + setImageId(photo.id); + }} + /> + +
+ ))} +
-
+ ) ); }; diff --git a/my-app/src/Components/Portfolio/Portfolio.tsx b/my-app/src/Components/Portfolio/Portfolio.tsx new file mode 100644 index 0000000..a0838c0 --- /dev/null +++ b/my-app/src/Components/Portfolio/Portfolio.tsx @@ -0,0 +1,54 @@ +import styles from "./Portfolio.module.css"; +import { useContext, useEffect, useState } from "react"; +import { Link } from "react-router-dom"; +import { ThemeContext } from "../../providers/theme.tsx"; +import { PortfolioInterface } from "./Portfolio.types"; + + +export const Portfolio = () => { + const [setImageId] = useState(null); + const { theme } = useContext(ThemeContext); + + const [portfolioData, setPortfolioData] = useState(null); + + useEffect(() => { + fetch("/photos.json") + .then((res) => res.json()) + .then((data) => + setPortfolioData(data) + ); + }, []); + return ( + portfolioData && ( +
+

+ Our portfolio +

+
+

+ We are experienced in taking photos for all kinds of circumstances. +
+ Below is a summary of our extensive portfolio, with us you will + always look good! +

+
+
+ {portfolioData.photos.map((photo) => ( +
+ + { + setImageId(photo.id); + }} + /> + +
+ ))} +
+
+ ) + ); +}; diff --git a/my-app/src/Components/Portfolio/Portfolio.types.ts b/my-app/src/Components/Portfolio/Portfolio.types.ts new file mode 100644 index 0000000..88fbc4d --- /dev/null +++ b/my-app/src/Components/Portfolio/Portfolio.types.ts @@ -0,0 +1,8 @@ +export interface PortfolioInterface { + author: string; + height: number; + id: number; + price: number; + url: string; + width: number; + } \ No newline at end of file diff --git a/my-app/src/Components/Portfolio/PortfolioImage/PortfolioImage.jsx b/my-app/src/Components/Portfolio/PortfolioImage/PortfolioImage.jsx index 8b1e3c2..af7cc5c 100644 --- a/my-app/src/Components/Portfolio/PortfolioImage/PortfolioImage.jsx +++ b/my-app/src/Components/Portfolio/PortfolioImage/PortfolioImage.jsx @@ -1,7 +1,7 @@ import { useParams } from "react-router-dom"; import portfolioData from "../../../../public/photos.json"; import styles from "./PortfolioImage.module.css"; -import { ThemeContext } from "../../../providers/theme"; +import { ThemeContext } from "../../../providers/theme.tsx"; import { useContext } from "react"; import classnames from "classnames"; diff --git a/my-app/src/Components/PortfolioModal/PortfolioModal.jsx b/my-app/src/Components/PortfolioModal/PortfolioModal.jsx index 2eb59a1..6ba480d 100644 --- a/my-app/src/Components/PortfolioModal/PortfolioModal.jsx +++ b/my-app/src/Components/PortfolioModal/PortfolioModal.jsx @@ -1,49 +1,49 @@ -import styles from "./PortfolioModal.module.css"; -import { Modal } from "../Modal/Modal.jsx"; -import { useEffect } from "react"; +// import styles from "./PortfolioModal.module.css"; +// import { Modal } from "../Modal/Modal.jsx"; +// import { useEffect } from "react"; -export const PortfolioModal = ({ isOpen, onClose }) => { - useEffect(() => { - const handleKeyDown = (event) => { - if (event.key === "Escape") { - onClose(); - } - }; +// export const PortfolioModal = ({ isOpen, onClose }) => { +// useEffect(() => { +// const handleKeyDown = (event) => { +// if (event.key === "Escape") { +// onClose(); +// } +// }; - window.addEventListener("keydown", handleKeyDown); +// window.addEventListener("keydown", handleKeyDown); - return () => { - window.removeEventListener("keydown", handleKeyDown); - }; - }, [onClose]); +// return () => { +// window.removeEventListener("keydown", handleKeyDown); +// }; +// }, [onClose]); - useEffect(() => { - document.body.style.overflow = isOpen ? "hidden" : "auto"; +// useEffect(() => { +// document.body.style.overflow = isOpen ? "hidden" : "auto"; - return () => { - document.body.style.overflow = "auto"; - }; - }, [isOpen]); +// return () => { +// document.body.style.overflow = "auto"; +// }; +// }, [isOpen]); - return ( - <> -
- {isOpen && ( -
- )} +// return ( +// <> +//
+// {isOpen && ( +//
+// )} - - -
-

Portfolio modal

-
-
-
- - ); -}; +// +// +//
+//

Portfolio modal

+//
+//
+//
+// +// ); +// }; diff --git a/my-app/src/Components/PortfolioModal/PortfolioModal.module.css b/my-app/src/Components/PortfolioModal/PortfolioModal.module.css index 6dc0a53..1f3c846 100644 --- a/my-app/src/Components/PortfolioModal/PortfolioModal.module.css +++ b/my-app/src/Components/PortfolioModal/PortfolioModal.module.css @@ -1,4 +1,4 @@ -.portfolio-modal__button-close { +/* .portfolio-modal__button-close { position: absolute; top: 20px; right: 10px; @@ -20,4 +20,4 @@ height: 100%; background: rgba(0, 0, 0, 0.5); z-index: 1; -} +} */ diff --git a/my-app/src/Components/Pricing/Pricing.jsx b/my-app/src/Components/Pricing/Pricing.jsx index c475df2..0c6ba46 100644 --- a/my-app/src/Components/Pricing/Pricing.jsx +++ b/my-app/src/Components/Pricing/Pricing.jsx @@ -1,6 +1,6 @@ import styles from "./Pricing.module.css"; -import { PricingPosition } from "./PricingPosition/PricingPosition"; -import { ThemeContext } from "../../providers/theme"; +import { PricingPosition } from "./PricingPosition/PricingPosition.tsx"; +import { ThemeContext } from "../../providers/theme.tsx"; import { useContext } from "react"; import classnames from "classnames"; diff --git a/my-app/src/Components/Pricing/PricingPosition/PricingPosition.jsx b/my-app/src/Components/Pricing/PricingPosition/PricingPosition.jsx deleted file mode 100644 index 9885806..0000000 --- a/my-app/src/Components/Pricing/PricingPosition/PricingPosition.jsx +++ /dev/null @@ -1,46 +0,0 @@ -import styles from "./PricingPosition.module.css"; -import classnames from "classnames"; -import { ThemeContext } from "../../../providers/theme"; -import { useContext } from "react"; - -export const PricingPosition = (props) => { - const { theme } = useContext(ThemeContext); - - return ( - <> -
-
-

- {props.title} -

-
-

{props.price}

-
-
-
    - {props.description.map((el, index) => { - const key = `${index}-${el}`; - return
  • {el}
  • ; - })} -
-
-
-
- - ); -}; diff --git a/my-app/src/Components/Pricing/PricingPosition/PricingPosition.tsx b/my-app/src/Components/Pricing/PricingPosition/PricingPosition.tsx new file mode 100644 index 0000000..805f50d --- /dev/null +++ b/my-app/src/Components/Pricing/PricingPosition/PricingPosition.tsx @@ -0,0 +1,49 @@ +import styles from "./PricingPosition.module.css"; +import classnames from "classnames"; +import { ThemeContext } from "../../../providers/theme.tsx"; +import { ReactElement, useContext } from "react"; +import { PricingPositionProps } from "./PricingPosition.types"; + + +export const PricingPosition = ({title, price, description}:PricingPositionProps):ReactElement => { + + const { theme } = useContext(ThemeContext); + + return ( + <> +
+
+

+ {title} +

+
+

{price}

+
+
+
    + {description.map((el, index) => { + const key = `${index}-${el}`; + return
  • {el}
  • ; + })} +
+
+
+
+ + ); +} \ No newline at end of file diff --git a/my-app/src/Components/Pricing/PricingPosition/PricingPosition.types.ts b/my-app/src/Components/Pricing/PricingPosition/PricingPosition.types.ts new file mode 100644 index 0000000..9beeb71 --- /dev/null +++ b/my-app/src/Components/Pricing/PricingPosition/PricingPosition.types.ts @@ -0,0 +1,5 @@ +export interface PricingPositionProps { + title: string; + price: string; + description: string[]; + } \ No newline at end of file diff --git a/my-app/src/css.d.ts b/my-app/src/css.d.ts new file mode 100644 index 0000000..4baac35 --- /dev/null +++ b/my-app/src/css.d.ts @@ -0,0 +1 @@ +declare module "*.css" \ No newline at end of file diff --git a/my-app/src/providers/theme.jsx b/my-app/src/providers/theme.jsx index da77276..b837e40 100644 --- a/my-app/src/providers/theme.jsx +++ b/my-app/src/providers/theme.jsx @@ -1,25 +1,25 @@ -import { createContext, useEffect, useState } from "react"; +// import { createContext, useEffect, useState } from "react"; -export const ThemeContext = createContext("theme"); +// export const ThemeContext = createContext("theme"); -export const ThemeProvider = ({ children }) => { - const [theme, setTheme] = useState("light"); - const toggleLightTheme = () => { - setTheme("light"); - }; +// export const ThemeProvider = ({ children }) => { +// const [theme, setTheme] = useState("light"); +// const toggleLightTheme = () => { +// setTheme("light"); +// }; - const toggleDarkTheme = () => { - setTheme("dark"); - }; +// const toggleDarkTheme = ()=> { +// setTheme("dark"); +// }; - useEffect(() => { - document.body.className = theme; - }, [theme]); +// useEffect(() => { +// document.body.className = theme; +// }, [theme]); - console.log(theme); - return ( - - {children} - - ); -}; +// console.log(theme); +// return ( +// +// {children} +// +// ); +// }; diff --git a/my-app/src/providers/theme.tsx b/my-app/src/providers/theme.tsx new file mode 100644 index 0000000..75adab4 --- /dev/null +++ b/my-app/src/providers/theme.tsx @@ -0,0 +1,33 @@ +import { FC, PropsWithChildren, createContext, useEffect, useState } from "react"; + + +type ContextType = { theme:"light"|"dark", toggleLightTheme:()=>void, toggleDarkTheme:() => void }; + +export const ThemeContext = createContext({ + theme: "light", + toggleLightTheme: () => {}, + toggleDarkTheme: () => {} +}); + +export const ThemeProvider:FC = ({ children }:PropsWithChildren) => { + + const [theme, setTheme] = useState("light"); + + const toggleLightTheme = ():void => { + setTheme("light"); + }; + + const toggleDarkTheme = ():void => { + setTheme("dark"); + }; + + useEffect(() => { + document.body.className = theme; + }, [theme]); + + return ( + + {children} + + ); +}; diff --git a/my-app/tsconfig.json b/my-app/tsconfig.json new file mode 100644 index 0000000..4b6a0d9 --- /dev/null +++ b/my-app/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] + } + \ No newline at end of file diff --git a/my-app/tsconfig.node.json b/my-app/tsconfig.node.json new file mode 100644 index 0000000..97ede7e --- /dev/null +++ b/my-app/tsconfig.node.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "strict": true + }, + "include": ["vite.config.ts"] +}