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 @@
-{}