diff --git a/.DS_Store b/.DS_Store index d1b4a29..885a328 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/fe/package-lock.json b/fe/package-lock.json index 1e2c050..e407eea 100644 --- a/fe/package-lock.json +++ b/fe/package-lock.json @@ -18,6 +18,7 @@ "react-helmet-async": "^2.0.5", "react-icons": "^5.2.1", "react-router-dom": "^6.23.1", + "tailwind-scrollbar-hide": "^1.1.7", "three": "^0.165.0" }, "devDependencies": { @@ -7572,6 +7573,11 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, + "node_modules/tailwind-scrollbar-hide": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/tailwind-scrollbar-hide/-/tailwind-scrollbar-hide-1.1.7.tgz", + "integrity": "sha512-X324n9OtpTmOMqEgDUEA/RgLrNfBF/jwJdctaPZDzB3mppxJk7TLIDmOreEDm1Bq4R9LSPu4Epf8VSdovNU+iA==" + }, "node_modules/tailwindcss": { "version": "3.4.4", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.4.tgz", diff --git a/fe/package.json b/fe/package.json index d9ae2d3..767e71a 100644 --- a/fe/package.json +++ b/fe/package.json @@ -22,6 +22,7 @@ "react-helmet-async": "^2.0.5", "react-icons": "^5.2.1", "react-router-dom": "^6.23.1", + "tailwind-scrollbar-hide": "^1.1.7", "three": "^0.165.0" }, "devDependencies": { diff --git a/fe/src/App.tsx b/fe/src/App.tsx index d802c90..27837c1 100644 --- a/fe/src/App.tsx +++ b/fe/src/App.tsx @@ -1,7 +1,6 @@ import { HelmetProvider } from "react-helmet-async"; import { Router } from "./app/routes"; import "./App.css"; -// import.meta.env.VITE_API_SERVER // ROUTES function App() { diff --git a/fe/src/app/layout/MainLayout.tsx b/fe/src/app/layout/MainLayout.tsx index feb2c17..eb40978 100644 --- a/fe/src/app/layout/MainLayout.tsx +++ b/fe/src/app/layout/MainLayout.tsx @@ -2,7 +2,6 @@ import MainHeader from "@/shared/ui/header/MainHeader"; import { Outlet } from "react-router-dom"; export function MainLayout() { - console.log("MainLayout"); return ( <> diff --git a/fe/src/entities/introduction/ui/Introduction.tsx b/fe/src/entities/introduction/ui/Introduction.tsx index 5a60aa1..f1669f8 100644 --- a/fe/src/entities/introduction/ui/Introduction.tsx +++ b/fe/src/entities/introduction/ui/Introduction.tsx @@ -1,4 +1,4 @@ -import { useTypingAnimation } from "@/shared/hooks/index"; +import { useTypingAnimation } from "@/shared/libs/index"; export default function Introdcution() { const { typingText } = useTypingAnimation({ diff --git a/fe/src/entities/projects/index.ts b/fe/src/entities/projects/index.ts index 4defb75..1ecc826 100644 --- a/fe/src/entities/projects/index.ts +++ b/fe/src/entities/projects/index.ts @@ -1 +1,2 @@ -export { default } from "./ui/Project"; +export { default } from "./ui/project/Project"; +export { default as FileDownloadButton } from "./ui/download-button/FileDownloadButton"; diff --git a/fe/src/features/download-file/ui/FileDownload.tsx b/fe/src/entities/projects/libs/useDownloadFile.tsx similarity index 64% rename from fe/src/features/download-file/ui/FileDownload.tsx rename to fe/src/entities/projects/libs/useDownloadFile.tsx index 871ebf2..74ef571 100644 --- a/fe/src/features/download-file/ui/FileDownload.tsx +++ b/fe/src/entities/projects/libs/useDownloadFile.tsx @@ -1,10 +1,6 @@ import { useState } from "react"; -type Props = { - fileUrl: string; -}; - -export default function FileDownload({ fileUrl }: Props) { +export function useDownloadFile(fileUrl: string) { const [isDownloading, setIsDownloading] = useState(false); const handleFileDownload = () => { if (!isDownloading) { @@ -29,18 +25,5 @@ export default function FileDownload({ fileUrl }: Props) { } }; - return ( -
- -
- -
-
- ); + return { isDownloading, handleFileDownload }; } diff --git a/fe/src/entities/projects/ui/download-button/FileDownloadButton.tsx b/fe/src/entities/projects/ui/download-button/FileDownloadButton.tsx new file mode 100644 index 0000000..42fb277 --- /dev/null +++ b/fe/src/entities/projects/ui/download-button/FileDownloadButton.tsx @@ -0,0 +1,45 @@ +import { useDownloadFile } from "@/entities/projects/libs/useDownloadFile"; + +type Props = { + fileUrl: string; +}; + +export default function FileDownload({ fileUrl }: Props) { + // const [isDownloading, setIsDownloading] = useState(false); + // const handleFileDownload = () => { + // if (!isDownloading) { + // setIsDownloading(true); + // fetch(fileUrl) + // .then((response) => response.blob()) + // .then((blob) => { + // const url = window.URL.createObjectURL(new Blob([blob])); + // const linkElem = document.createElement("a"); + // linkElem.href = url; + // linkElem.download = fileUrl.split("/").pop() || "download"; + // document.body.appendChild(linkElem); + // linkElem.click(); + + // window.URL.revokeObjectURL(url); + // setIsDownloading(false); + // }) + // .catch((error) => { + // console.error(`File download failed: ${error}`); + // setIsDownloading(false); + // }); + // } + // }; + const { isDownloading, handleFileDownload } = useDownloadFile(fileUrl); + + return ( + + */} + + ); +} diff --git a/fe/src/entities/projects/ui/Project.tsx b/fe/src/entities/projects/ui/project/Project.tsx similarity index 99% rename from fe/src/entities/projects/ui/Project.tsx rename to fe/src/entities/projects/ui/project/Project.tsx index 0c9fbb7..6ed7869 100644 --- a/fe/src/entities/projects/ui/Project.tsx +++ b/fe/src/entities/projects/ui/project/Project.tsx @@ -27,7 +27,7 @@ export default function Project({
{children}
diff --git a/fe/src/features/detect-loading/index.ts b/fe/src/features/detect-loading/index.ts deleted file mode 100644 index 85556a7..0000000 --- a/fe/src/features/detect-loading/index.ts +++ /dev/null @@ -1 +0,0 @@ -// export * from "./ui/LoadingDetector"; diff --git a/fe/src/features/detect-loading/ui/LoadingDetector.tsx b/fe/src/features/detect-loading/ui/LoadingDetector.tsx deleted file mode 100644 index 18a74b5..0000000 --- a/fe/src/features/detect-loading/ui/LoadingDetector.tsx +++ /dev/null @@ -1,18 +0,0 @@ -// import { MainLoadingScreen } from "@/shared/ui/loadingScreen/MainLoadingScreen"; -// import Main from "@/pages/root/components/Main"; -// import { useState } from "react"; - -// export default function LoadingDetector() { -// const [start, setStart] = useState(false); - -// const showStartPage = () => { -// setStart(true); -// }; - -// return ( -// <> -// {start &&
} -// -// -// ); -// } diff --git a/fe/src/features/download-file/index.ts b/fe/src/features/download-file/index.ts deleted file mode 100644 index 8593b8f..0000000 --- a/fe/src/features/download-file/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./ui/FileDownload"; diff --git a/fe/src/hooks/useLoadPercentage.tsx b/fe/src/hooks/useLoadPercentage.tsx deleted file mode 100644 index dfe6177..0000000 --- a/fe/src/hooks/useLoadPercentage.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { useEffect, useState } from "react"; - -export const useLoadPercentage = () => { - const [loadPercent, setLoadPercent] = useState(0); - const [minTimeFinish, setMinTimeFinish] = useState<"loading" | "finish">( - "loading" - ); - - useEffect(() => { - const sid = setInterval(() => { - setLoadPercent((prev) => { - const percentage = prev + Math.random() * 5 + 1; - if (percentage > 100) { - clearInterval(sid); - return 100; - } - return percentage; - }); - }, 100); - - if (loadPercent > 100) { - clearInterval(sid); - } - - return () => { - clearInterval(sid); - }; - }, []); - - useEffect(() => { - console.log(loadPercent); - if (loadPercent >= 100) { - setTimeout(() => { - setMinTimeFinish("finish"); - }, 1000); - } - }, [loadPercent]); - - return { - percentage: Number(loadPercent.toFixed(2)), - finished: minTimeFinish === "finish", - }; -}; diff --git a/fe/src/pages/main/ui/MainPageWithLoading.tsx b/fe/src/pages/main/ui/MainPageWithLoading.tsx deleted file mode 100644 index fe3971a..0000000 --- a/fe/src/pages/main/ui/MainPageWithLoading.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { MainLoadingScreen } from "@/widgets/projects-showcase/index"; -import ProjectsShowCase from "@/widgets/projects-showcase/ui/ProjectsShowCase"; -import { useState } from "react"; - -export default function MainPageWithLoading() { - const [start, setStart] = useState(false); - - const showStartPage = () => { - setStart(true); - }; - - return ( - <> - {start && } - - - ); -} diff --git a/fe/src/pages/main/ui/page.tsx b/fe/src/pages/main/ui/page.tsx index 77d85cb..4db28c5 100644 --- a/fe/src/pages/main/ui/page.tsx +++ b/fe/src/pages/main/ui/page.tsx @@ -1,6 +1,5 @@ -import MainPageWithLoading from "@/pages/main/ui/MainPageWithLoading"; import { DetailHelmet } from "@/shared/ui/meta/DetailHelmet"; -// import LoadWrapper from "@/pages/root/components/LoadWrapper"; +import { ProjectsShowCaseWithLoading } from "@/widgets/main/projectsShowcase"; export default function MainPage() { return ( @@ -11,7 +10,7 @@ export default function MainPage() { url={import.meta.env.VITE_BASE_URL + "/"} shortDesc="방구석 코딩쟁이의 포트폴리오를 소개합니다." /> - + ); } diff --git a/fe/src/shared/constants/animationScript.ts b/fe/src/shared/constants/animation/animationScript.ts similarity index 96% rename from fe/src/shared/constants/animationScript.ts rename to fe/src/shared/constants/animation/animationScript.ts index b615885..56c51a3 100644 --- a/fe/src/shared/constants/animationScript.ts +++ b/fe/src/shared/constants/animation/animationScript.ts @@ -1,6 +1,6 @@ import * as THREE from "three"; import { lerp, scalePercent } from "@/shared/utils/lerp"; -import { points } from "@/shared/constants/points"; +import { points } from "@/shared/constants/animation/points"; type AnimationTimeline = { start: number; diff --git a/fe/src/shared/constants/points.ts b/fe/src/shared/constants/animation/points.ts similarity index 100% rename from fe/src/shared/constants/points.ts rename to fe/src/shared/constants/animation/points.ts diff --git a/fe/src/shared/constants/index.ts b/fe/src/shared/constants/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/fe/src/shared/constants/webGl/StarScene.ts b/fe/src/shared/constants/webGl/StarScene.ts index 5beeb9f..4c2ac55 100644 --- a/fe/src/shared/constants/webGl/StarScene.ts +++ b/fe/src/shared/constants/webGl/StarScene.ts @@ -3,8 +3,8 @@ import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; import { animationScript, animationTimeline, -} from "@/shared/constants/animationScript"; -import { points } from "@/shared/constants/points"; +} from "@/shared/constants/animation/animationScript"; +import { points } from "@/shared/constants/animation/points"; import { Star } from "@/shared/constants/webGl/Star"; import { MyStar } from "@/shared/constants/webGl/MyStar"; diff --git a/fe/src/shared/hooks/index.ts b/fe/src/shared/libs/index.ts similarity index 100% rename from fe/src/shared/hooks/index.ts rename to fe/src/shared/libs/index.ts diff --git a/fe/src/shared/libs/media-query/__tests__/useMediaQuery.test.tsx b/fe/src/shared/libs/media-query/__tests__/useMediaQuery.test.tsx new file mode 100644 index 0000000..e25c7cd --- /dev/null +++ b/fe/src/shared/libs/media-query/__tests__/useMediaQuery.test.tsx @@ -0,0 +1,80 @@ +import { renderHook, act } from "@testing-library/react"; +import { useMediaQuery } from "@/shared/libs/media-query/useMediaQuery"; + +describe("useMediaQuery", () => { + const originalMatchMedia = window.matchMedia; + + afterEach(() => { + // Restore original window.matchMedia after each test + window.matchMedia = originalMatchMedia; + }); + + const createMockMatchMedia = (matches: boolean) => { + const addListener = vi.fn(); + const removeListener = vi.fn(); + const addEventListener = vi.fn(); + const removeEventListener = vi.fn(); + + return vi.fn().mockImplementation((query: string) => ({ + matches, + media: query, + onchange: null, + addListener, + removeListener, + addEventListener, + removeEventListener, + dispatchEvent: vi.fn(), + })) as unknown as (query: string) => MediaQueryList; + }; + + it("should return true for desktop query", () => { + window.matchMedia = createMockMatchMedia(true); + + const { result } = renderHook(() => useMediaQuery("(min-width: 1024px)")); + expect(result.current).toBe(true); + }); + + it("should return false for mobile query", () => { + window.matchMedia = createMockMatchMedia(false); + + const { result } = renderHook(() => useMediaQuery("(max-width: 767px)")); + expect(result.current).toBe(false); + }); + + it("should update when media query changes", () => { + const matchMediaListeners: { [key: string]: () => void } = {}; + window.matchMedia = vi.fn().mockImplementation((query: string) => { + // const listeners: Array<() => void> = []; + return { + matches: query === "(min-width: 1024px)", + media: query, + onchange: null, + addListener: (listener: () => void) => { + matchMediaListeners[query] = listener; + }, + removeListener: vi.fn(), + addEventListener: (event: string, listener: () => void) => { + matchMediaListeners[query] = listener; + }, + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + }; + }) as unknown as (query: string) => MediaQueryList; + + const { result, rerender } = renderHook(() => + useMediaQuery("(min-width: 1024px)") + ); + + expect(result.current).toBe(true); + + act(() => { + window.matchMedia = createMockMatchMedia(false); + if (matchMediaListeners["(min-width: 1024px)"]) { + matchMediaListeners["(min-width: 1024px)"](); + } + }); + + rerender(); + expect(result.current).toBe(false); + }); +}); diff --git a/fe/src/shared/libs/media-query/useDeviceSize.ts b/fe/src/shared/libs/media-query/useDeviceSize.ts new file mode 100644 index 0000000..5807db6 --- /dev/null +++ b/fe/src/shared/libs/media-query/useDeviceSize.ts @@ -0,0 +1,25 @@ +import { useMediaQuery } from "@/shared/libs/media-query/useMediaQuery"; + +export function useDeviceSize() { + const isDesktopQuery = "(min-width: 1024px)"; + const isTabletQuery = "(min-width: 768px) and (max-width: 1023px)"; + const isMobileQuery = "(max-width: 767px)"; + + const isDesktop = useMediaQuery(isDesktopQuery); + const isTablet = useMediaQuery(isTabletQuery); + const isMobile = useMediaQuery(isMobileQuery); + + if (isDesktop) { + return "desktop"; + } + + if (isTablet) { + return "tablet"; + } + + if (isMobile) { + return "mobile"; + } + + return "mobile"; +} diff --git a/fe/src/shared/libs/media-query/useMediaQuery.ts b/fe/src/shared/libs/media-query/useMediaQuery.ts new file mode 100644 index 0000000..c114b63 --- /dev/null +++ b/fe/src/shared/libs/media-query/useMediaQuery.ts @@ -0,0 +1,49 @@ +import { useCallback, useEffect, useState } from "react"; + +// 외부에서 주입 가능한 matchMedia 함수 +const defaultMatchMedia = (query: string) => window.matchMedia(query); + +// getMatches 함수 분리 +const getMatches = ( + query: string, + matchMedia: (query: string) => MediaQueryList +): boolean => { + if (typeof window !== "undefined") { + return matchMedia(query).matches; + } + return false; +}; + +export function useMediaQuery( + query: string, + matchMedia: (query: string) => MediaQueryList = defaultMatchMedia +): boolean { + const [matches, setMatches] = useState(() => getMatches(query, matchMedia)); + + const changeMediaQueryHandler = useCallback(() => { + setMatches(getMatches(query, matchMedia)); + }, [query, matchMedia]); + + useEffect(() => { + const matchMediaInstance = matchMedia(query); + + if (matchMediaInstance.addListener) { + matchMediaInstance.addListener(changeMediaQueryHandler); + } else { + matchMediaInstance.addEventListener("change", changeMediaQueryHandler); + } + + return () => { + if (matchMediaInstance.removeListener) { + matchMediaInstance.removeListener(changeMediaQueryHandler); + } else { + matchMediaInstance.removeEventListener( + "change", + changeMediaQueryHandler + ); + } + }; + }, [query, changeMediaQueryHandler, matchMedia]); + + return matches; +} diff --git a/fe/src/shared/hooks/typing/useTypingAnimation.ts b/fe/src/shared/libs/typing/useTypingAnimation.ts similarity index 100% rename from fe/src/shared/hooks/typing/useTypingAnimation.ts rename to fe/src/shared/libs/typing/useTypingAnimation.ts diff --git a/fe/src/widgets/main/projectsShowcase/index.ts b/fe/src/widgets/main/projectsShowcase/index.ts new file mode 100644 index 0000000..63da9cc --- /dev/null +++ b/fe/src/widgets/main/projectsShowcase/index.ts @@ -0,0 +1 @@ +export { ProjectsShowCaseWithLoading } from "./ui/ProjectsShowCase/ProjectsShowCase"; diff --git a/fe/src/widgets/projects-showcase/hooks/__tests__/useScrollAnimation.spec.ts b/fe/src/widgets/main/projectsShowcase/libs/__tests__/useScrollAnimation.spec.ts similarity index 86% rename from fe/src/widgets/projects-showcase/hooks/__tests__/useScrollAnimation.spec.ts rename to fe/src/widgets/main/projectsShowcase/libs/__tests__/useScrollAnimation.spec.ts index fa2c8cb..5e24652 100644 --- a/fe/src/widgets/projects-showcase/hooks/__tests__/useScrollAnimation.spec.ts +++ b/fe/src/widgets/main/projectsShowcase/libs/__tests__/useScrollAnimation.spec.ts @@ -5,7 +5,7 @@ import { renderHook } from "@testing-library/react"; import { MutableRefObject } from "react"; import { Mock } from "vitest"; -import { useScrollAnimation } from "@/widgets/projects-showcase/hooks/useScrollAnimation"; +import { useScrollAnimation } from "@/widgets/main/projectsShowcase/libs/useScrollAnimation"; // Mocking dependencies vi.mock("three", async () => { @@ -162,20 +162,20 @@ describe("useScrollAnimation", () => { const newContainerRef = { current: document.createElement("div") }; rerender({ container: newContainerRef, scroll: scrollRef }); - expect(StarScene).toHaveBeenCalledTimes(2); + expect(StarScene).toHaveBeenCalledTimes(1); }); - it("should reinitialize StarScene when scrollRef changes", () => { - const { rerender } = renderHook( - ({ container, scroll }) => useScrollAnimation(container, scroll), - { - initialProps: { container: containerRef, scroll: scrollRef }, - } - ); + // it("should reinitialize StarScene when scrollRef changes", () => { + // const { rerender } = renderHook( + // ({ container, scroll }) => useScrollAnimation(container, scroll), + // { + // initialProps: { container: containerRef, scroll: scrollRef }, + // } + // ); - const newScrollRef = { current: document.createElement("div") }; - rerender({ container: containerRef, scroll: newScrollRef }); + // const newScrollRef = { current: document.createElement("div") }; + // rerender({ container: containerRef, scroll: newScrollRef }); - expect(StarScene).toHaveBeenCalledTimes(1); // 여기서는 새로운 StarScene을 초기화하지 않아야 합니다. - }); + // expect(StarScene).toHaveBeenCalledTimes(1); // 여기서는 새로운 StarScene을 초기화하지 않아야 합니다. + // }); }); diff --git a/fe/src/widgets/main/projectsShowcase/libs/useLoadMainPage.ts b/fe/src/widgets/main/projectsShowcase/libs/useLoadMainPage.ts new file mode 100644 index 0000000..8eef53b --- /dev/null +++ b/fe/src/widgets/main/projectsShowcase/libs/useLoadMainPage.ts @@ -0,0 +1,48 @@ +import { useEffect, useState } from "react"; +import NProgress from "nprogress"; + +type ContentLoadState = "loading" | "error" | "finish"; +type IsFinishMinimumLoadTime = "loading" | "finish"; + +export function useLoadMainPage() { + const [contentLoadState, setContetLoadState] = + useState("loading"); + const [minTimeFinish, setMinTimeFinish] = + useState("loading"); + + // 최소 시간 대기 후 finish + useEffect(() => { + setTimeout(() => { + setMinTimeFinish("finish"); + }, 1000); + }, []); + + useEffect(() => { + NProgress.start(); + import( + "@/widgets/main/projectsShowcase/ui/ProjectsShowCase/ProjectsShowCase.tsx" + ) + .then((module) => { + // console.log(module); + if (module === undefined) { + setContetLoadState("error"); + } else { + setContetLoadState("finish"); + NProgress.done(); + } + }) + .catch((error) => { + setContetLoadState("error"); + console.error("error", error); + }); + }, []); + + const isButtonDisabled = + contentLoadState === "loading" || + minTimeFinish === "loading" || + contentLoadState === "error"; + + return { + isButtonDisabled, + }; +} diff --git a/fe/src/widgets/projects-showcase/hooks/useParallax.ts b/fe/src/widgets/main/projectsShowcase/libs/useParallax.ts similarity index 100% rename from fe/src/widgets/projects-showcase/hooks/useParallax.ts rename to fe/src/widgets/main/projectsShowcase/libs/useParallax.ts diff --git a/fe/src/widgets/projects-showcase/hooks/useScrollAnimation.ts b/fe/src/widgets/main/projectsShowcase/libs/useScrollAnimation.ts similarity index 76% rename from fe/src/widgets/projects-showcase/hooks/useScrollAnimation.ts rename to fe/src/widgets/main/projectsShowcase/libs/useScrollAnimation.ts index 84387b4..dd02c6f 100644 --- a/fe/src/widgets/projects-showcase/hooks/useScrollAnimation.ts +++ b/fe/src/widgets/main/projectsShowcase/libs/useScrollAnimation.ts @@ -13,8 +13,16 @@ export const useScrollAnimation = ( }); useEffect(() => { - // && !sceneRef.current - if (containerRef.current) { + // // && !sceneRef.current + // if (containerRef.current) { + // sceneRef.current = new StarScene( + // new THREE.WebGLRenderer({ + // antialias: true, + // }), + // containerRef.current + // ); + // } + if (containerRef.current && !sceneRef.current) { sceneRef.current = new StarScene( new THREE.WebGLRenderer({ antialias: true, @@ -22,7 +30,6 @@ export const useScrollAnimation = ( containerRef.current ); } - const unsubscribe = scrollYProgress.on("change", (scrollRate) => { if (!sceneRef.current) return; sceneRef.current.updateScrollRate(scrollRate); diff --git a/fe/src/widgets/projects-showcase/ui/ProjectsShowCase.tsx b/fe/src/widgets/main/projectsShowcase/ui/ProjectsShowCase/ProjectsShowCase.tsx similarity index 94% rename from fe/src/widgets/projects-showcase/ui/ProjectsShowCase.tsx rename to fe/src/widgets/main/projectsShowcase/ui/ProjectsShowCase/ProjectsShowCase.tsx index 5e37461..dd5d7fd 100644 --- a/fe/src/widgets/projects-showcase/ui/ProjectsShowCase.tsx +++ b/fe/src/widgets/main/projectsShowcase/ui/ProjectsShowCase/ProjectsShowCase.tsx @@ -1,7 +1,7 @@ -import { useScrollAnimation } from "@/widgets/projects-showcase/hooks/useScrollAnimation"; +import { useScrollAnimation } from "@/widgets/main/projectsShowcase/libs/useScrollAnimation"; import { useMotionValueEvent, useScroll } from "framer-motion"; import { useRef } from "react"; -import FileDownload from "@/features/download-file/index"; +import { FileDownloadButton } from "@/entities/projects/index"; import Contact from "@/entities/contact/index"; import MyProfile from "@/entities/profile/index"; @@ -15,8 +15,9 @@ import readyToWorkProjectImg from "@/shared/assets/images/ready_to_work.png"; import cryptoProjectImg from "@/shared/assets/images/crypto.png"; import eyeveProjectImg from "@/shared/assets/images/eyeve.png"; import vscodeExtensionProjectImg from "@/shared/assets/images/vscode-extension.png"; +import { withLoading } from "@/widgets/main/projectsShowcase/ui/withLoading/withLoading"; -export default function ProjectsShowCase() { +function ProjectsShowCase() { const ref = useRef(null); const scrollRef = useRef(null); const { scrollYProgress } = useScroll({ @@ -35,7 +36,7 @@ export default function ProjectsShowCase() { return ( <>
- @@ -211,3 +212,5 @@ export default function ProjectsShowCase() { ); } + +export const ProjectsShowCaseWithLoading = withLoading(ProjectsShowCase); diff --git a/fe/src/widgets/main/projectsShowcase/ui/loadingScreen/MainLoadingScreen.tsx b/fe/src/widgets/main/projectsShowcase/ui/loadingScreen/MainLoadingScreen.tsx new file mode 100644 index 0000000..a0f187b --- /dev/null +++ b/fe/src/widgets/main/projectsShowcase/ui/loadingScreen/MainLoadingScreen.tsx @@ -0,0 +1,37 @@ +import LoadAnimation from "@/shared/ui/loadingScreen/LoadAnimation"; +import { useLoadMainPage } from "@/widgets/main/projectsShowcase/libs/useLoadMainPage"; +import NProgress from "nprogress"; + +NProgress.configure({ + showSpinner: false, + trickleSpeed: 100, + trickle: true, + easing: "ease", + speed: 100, +}); + +export const MainLoadingScreen = ({ isLoading, onStarted }) => { + const { isButtonDisabled } = useLoadMainPage(); + + return ( + //absolute z-50 h-[100vh] w-[100vw] flex justify-center items-center +
+ +
+ +
+
+ ); +}; diff --git a/fe/src/widgets/main/projectsShowcase/ui/withLoading/withLoading.tsx b/fe/src/widgets/main/projectsShowcase/ui/withLoading/withLoading.tsx new file mode 100644 index 0000000..ce4a464 --- /dev/null +++ b/fe/src/widgets/main/projectsShowcase/ui/withLoading/withLoading.tsx @@ -0,0 +1,21 @@ +import { MainLoadingScreen } from "@/widgets/main/projectsShowcase/ui/loadingScreen/MainLoadingScreen"; +import { ComponentType, useState } from "react"; + +export function withLoading

( + WrappedComponent: ComponentType

+) { + return function (props: P) { + const [isLoading, setIsLoading] = useState(true); + + const showStartPage = () => { + setIsLoading(false); + }; + + return ( + <> + {!isLoading && } + + + ); + }; +} diff --git a/fe/src/widgets/projects-showcase/index.ts b/fe/src/widgets/projects-showcase/index.ts deleted file mode 100644 index 7da4c86..0000000 --- a/fe/src/widgets/projects-showcase/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./ui/MainLoadingScreen"; -export * from "./ui/ProjectsShowCase"; diff --git a/fe/src/widgets/projects-showcase/ui/MainLoadingScreen.tsx b/fe/src/widgets/projects-showcase/ui/MainLoadingScreen.tsx deleted file mode 100644 index 1488abe..0000000 --- a/fe/src/widgets/projects-showcase/ui/MainLoadingScreen.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import LoadAnimation from "@/shared/ui/loadingScreen/LoadAnimation"; -import NProgress from "nprogress"; -import { useEffect, useState } from "react"; - -NProgress.configure({ - showSpinner: false, - trickleSpeed: 100, - trickle: true, - easing: "ease", - speed: 100, -}); - -export const MainLoadingScreen = ({ started, onStarted }) => { - const [contentLoadState, setContetLoadState] = useState< - "loading" | "error" | "finish" - >("loading"); - const [minTimeFinish, setMinTimeFinish] = useState<"loading" | "finish">( - "loading" - ); - - // 최소 시간 대기 후 finish - useEffect(() => { - setTimeout(() => { - setMinTimeFinish("finish"); - }, 1000); - }, []); - - useEffect(() => { - NProgress.start(); - import("@/widgets/projects-showcase/ui/ProjectsShowCase.tsx") - .then((module) => { - setContetLoadState("finish"); - console.log(module.default); - NProgress.done(); - }) - .catch((error) => { - setContetLoadState("error"); - console.error("error", error); - }); - // import("./ProjectsShowCase") - }, []); - - const buttonDisabled = - contentLoadState === "loading" || - minTimeFinish === "loading" || - contentLoadState === "error"; - - return ( - //absolute z-50 h-[100vh] w-[100vw] flex justify-center items-center -

- -
- -
-
- ); -}; diff --git a/fe/tailwind.config.js b/fe/tailwind.config.js index e801255..3af792d 100644 --- a/fe/tailwind.config.js +++ b/fe/tailwind.config.js @@ -4,5 +4,5 @@ export default { theme: { extend: {}, }, - plugins: [], + plugins: [require("tailwind-scrollbar-hide")], }; diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 21b7acf..0000000 --- a/package-lock.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "ci-cd-test", - "lockfileVersion": 3, - "requires": true, - "packages": {} -} diff --git a/package.json b/package.json deleted file mode 100644 index 0967ef4..0000000 --- a/package.json +++ /dev/null @@ -1 +0,0 @@ -{}