From 7d88da66676f1f70f2e0376c88b7117b4c87c1f6 Mon Sep 17 00:00:00 2001 From: sadorowo Date: Fri, 31 May 2024 15:49:30 +0200 Subject: [PATCH] add: docker files + loading spinner & theme context --- Dockerfile | 11 ++++ docker-compose.yml | 11 ++++ .../components/navigation_bar.component.tsx | 5 -- src/app/layout.tsx | 51 +++++++++++++++---- src/app/page.tsx | 31 ++++------- src/app/themes.tsx | 7 +-- src/components/loader.component.tsx | 34 +++++++++++++ src/components/navigation_bar.component.tsx | 33 ++++++++++++ src/providers/theme.provider.tsx | 41 +++++++++++++++ src/{app => }/styles.tsx | 3 +- src/{app => }/types/styled-components.d.ts | 0 src/{app => }/utils/local_storage.ts | 3 +- 12 files changed, 191 insertions(+), 39 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.yml delete mode 100644 src/app/components/navigation_bar.component.tsx create mode 100644 src/components/loader.component.tsx create mode 100644 src/components/navigation_bar.component.tsx create mode 100644 src/providers/theme.provider.tsx rename src/{app => }/styles.tsx (92%) rename src/{app => }/types/styled-components.d.ts (100%) rename src/{app => }/utils/local_storage.ts (95%) diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..132aa30 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM node:18-alpine + +WORKDIR /app + +COPY package.json ./ + +RUN yarn install + +COPY . . + +CMD ["yarn", "start"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..f694431 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,11 @@ +services: + parafiaborzeta: + build: + context: . + dockerfile: Dockerfile + container_name: parafiaborzeta + ports: + - '3000:3000' + volumes: + - .:/app + - /app/node_modules \ No newline at end of file diff --git a/src/app/components/navigation_bar.component.tsx b/src/app/components/navigation_bar.component.tsx deleted file mode 100644 index 91416d6..0000000 --- a/src/app/components/navigation_bar.component.tsx +++ /dev/null @@ -1,5 +0,0 @@ -export default function NavigationBar() { - return -} \ No newline at end of file diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 84644e9..ad872a2 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,23 +1,56 @@ +'use client' + import { Montserrat } from "next/font/google"; -import type { Metadata } from "next"; +import { useState, useEffect } from "react"; + +import NavigationBar from "@/components/navigation_bar.component"; +import { ThemeProvider } from "@/providers/theme.provider"; +import { GlobalLayout, MainBlock } from "@/styles"; +import Loader from "@/components/loader.component"; const inter = Montserrat({ subsets: ["latin"] }); -export const metadata: Metadata = { - title: "Parafia pw. Niepokalanego Serca NMP w Borzęcie", - description: "Parafia pw. Niepokalanego Serca NMP w Borzęcie", -}; - export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { - return ( + const [loading, setLoading] = useState(true); + + useEffect(() => { + const handleComplete = () => setLoading(false); + + // simulate loading delay + const timer = setTimeout(handleComplete, 1000); + return () => clearTimeout(timer); + }, []); + + return <> + {/* + can't use next.Metadata, + because 'use client' + styled components are + preventing it. + + next/head wouldn't work too, so legacy solution is used + */} + + Parafia pw. Niepokalanego Serca NMP w Borzęcie + + - {children} + + + {loading + ? + : <> + + + {children} + + } + - ); + ; } \ No newline at end of file diff --git a/src/app/page.tsx b/src/app/page.tsx index aa73995..1934cc5 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,26 +1,17 @@ 'use client' -import { ThemeProvider } from "styled-components"; - -import { Button, GlobalLayout, MainBlock } from "./styles"; -import { Theme, darkTheme, lightTheme } from "./themes"; -import useLocalStorage from "./utils/local_storage"; - -const themes: Record = { - light: lightTheme, - dark: darkTheme -} +import { useTheme } from "@/providers/theme.provider"; +import { Button } from "../styles"; export default function Home() { - const [theme, setTheme] = useLocalStorage("theme", "light"); + const { theme, toggleTheme } = useTheme(); - return - - -

Parafia w Borzęcie

-

Już wkrótce powstanie tutaj świeża strona parafii pod wezwaniem Niepokalanego Serca Maryi w Borzęcie.

- zadzwoń do proboszcza - -
-
; + return <> +

Parafia w Borzęcie

+

Już wkrótce powstanie tutaj świeża strona parafii pod wezwaniem Niepokalanego Serca Maryi w Borzęcie.

+ zadzwoń do proboszcza +
+

Aktualny motyw: {theme}

+ + ; } \ No newline at end of file diff --git a/src/app/themes.tsx b/src/app/themes.tsx index 57bc4de..6ed032c 100644 --- a/src/app/themes.tsx +++ b/src/app/themes.tsx @@ -1,17 +1,18 @@ +export type ThemeMode = 'light' | 'dark' export interface Theme { background: string, - padding: number, + space_px: number, text: string } export const darkTheme: Theme = { - padding: 10, + space_px: 10, background: "#2f3136", text: "#fff" } export const lightTheme: Theme = { - padding: 10, + space_px: 10, background: "#eee", text: "#000" } \ No newline at end of file diff --git a/src/components/loader.component.tsx b/src/components/loader.component.tsx new file mode 100644 index 0000000..e283e97 --- /dev/null +++ b/src/components/loader.component.tsx @@ -0,0 +1,34 @@ +import styled, { keyframes } from "styled-components"; + +const spin = keyframes` + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +`; + +const LoaderOverlay = styled.div` + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(255, 255, 255, 0.8); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; +`; + +const Spinner = styled.div` + border: 8px solid ${({ theme }) => theme.text}; + border-top: 8px solid ${({ theme }) => theme.background}; + border-radius: 50%; + width: 50px; + height: 50px; + animation: ${spin} 1s linear infinite; +`; + +export default function Loader() { + return + + +}; \ No newline at end of file diff --git a/src/components/navigation_bar.component.tsx b/src/components/navigation_bar.component.tsx new file mode 100644 index 0000000..333581f --- /dev/null +++ b/src/components/navigation_bar.component.tsx @@ -0,0 +1,33 @@ +import styled from "styled-components" +import Link from "next/link" + +export default function NavigationBar() { + return +

Parafia w Borzęcie

+ +
  • Strona główna
  • +
  • Kontakt
  • +
    +
    +} + +const Navigation = styled.nav` + display: flex; + align-items: center; + justify-content: space-between; + + padding: ${({ theme }) => theme.space_px}px; + position: fixed; + width: 100%; + left: 0; + top: 0; +` + +const NavigationLinks = styled.ul` + list-style-type: none; + li { + margin: ${({ theme }) => theme.space_px}px; + display: block; + float: left; + } +` \ No newline at end of file diff --git a/src/providers/theme.provider.tsx b/src/providers/theme.provider.tsx new file mode 100644 index 0000000..5184308 --- /dev/null +++ b/src/providers/theme.provider.tsx @@ -0,0 +1,41 @@ +import { createContext, useContext, useMemo, PropsWithChildren } from "react"; +import { ThemeProvider as StyledThemeProvider } from "styled-components"; + +import { ThemeMode, lightTheme, darkTheme } from "@/app/themes"; +import useLocalStorage from "@/utils/local_storage"; + +const ThemeContext = createContext({ + theme: "light", + toggleTheme: () => { }, +} as { + theme: ThemeMode, + toggleTheme: () => void +}); + +export const ThemeProvider = ({ children }: PropsWithChildren) => { + const [theme, setTheme] = useLocalStorage("theme", "light"); + + const toggleTheme = () => { + setTheme(previous => previous === "light" ? "dark" : "light"); + }; + + const value = useMemo(() => ({ theme, toggleTheme }), [theme]); + + return ( + + + {children} + + + ); +}; + +export const useTheme = () => { + const context = useContext(ThemeContext); + + if (!context) { + throw new Error("useTheme must be used within a ThemeProvider"); + } + + return context; +}; \ No newline at end of file diff --git a/src/app/styles.tsx b/src/styles.tsx similarity index 92% rename from src/app/styles.tsx rename to src/styles.tsx index 52376a8..0df1e2d 100644 --- a/src/app/styles.tsx +++ b/src/styles.tsx @@ -39,7 +39,8 @@ export const MainBlock = styled.main` export const Button = styled.button` border: none; outline: none; - padding: ${({ theme }) => theme.padding}px; + cursor: pointer; + padding: ${({ theme }) => theme.space_px}px; color: ${({ theme }) => theme.background}; background-color: ${({ theme }) => theme.text}; `; \ No newline at end of file diff --git a/src/app/types/styled-components.d.ts b/src/types/styled-components.d.ts similarity index 100% rename from src/app/types/styled-components.d.ts rename to src/types/styled-components.d.ts diff --git a/src/app/utils/local_storage.ts b/src/utils/local_storage.ts similarity index 95% rename from src/app/utils/local_storage.ts rename to src/utils/local_storage.ts index 7c23baf..1ff60c8 100644 --- a/src/app/utils/local_storage.ts +++ b/src/utils/local_storage.ts @@ -9,8 +9,9 @@ export default function useLocalStorage( useEffect(() => { const item = window.localStorage.getItem(key) + if (item) { - setValue(JSON.parse(item)) + setValue(JSON.parse(item)) } return () => {