From d76f54b2b1d181137086630bfe82ace1a9a75c47 Mon Sep 17 00:00:00 2001 From: Zoe <7711zoe@gmail.com> Date: Sat, 18 Jan 2025 00:24:32 +0800 Subject: [PATCH 1/6] BLOG-5 feat: mobile home page first view --- frontend/src/app/globals.css | 5 ++++- frontend/src/app/page.tsx | 34 ++++++++++++++++++++++++++++++- frontend/src/ui/layout/navbar.tsx | 2 +- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index 7502d79..034d269 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -3,5 +3,8 @@ @tailwind utilities; body { - @apply bg-white text-gray-600; + @apply bg-white text-base font-normal text-gray-600; + + --tool-bar-height: 4rem; + --content-height: calc(100vh - var(--tool-bar-height)); } diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index 66e7168..d68c76d 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -1,5 +1,37 @@ export default function HomePage() { return ( -
+
+

Hello 大家好!

+

+ 我是 +
+ Squid +
+ 魷魚 +

+
+
+
+ + + + + + + + + + + + + + +
+
+
); } + +function Hashtag(props: { tag: string }) { + return # {props.tag}; +} diff --git a/frontend/src/ui/layout/navbar.tsx b/frontend/src/ui/layout/navbar.tsx index 49893fe..040610c 100644 --- a/frontend/src/ui/layout/navbar.tsx +++ b/frontend/src/ui/layout/navbar.tsx @@ -5,7 +5,7 @@ type Props = {}; export default function Navbar({}: Props) { return (
-
+
魚之魷魂 -- 2.47.1 From 90c8a2f6276ff06c62201536a7f5e069bfbbd283 Mon Sep 17 00:00:00 2001 From: SquidSpirit Date: Sat, 18 Jan 2025 00:38:47 +0800 Subject: [PATCH 2/6] BLOG-5 feat: home page fisrt view desktop layout --- frontend/src/app/page.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index d68c76d..470e2c9 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -1,15 +1,17 @@ export default function HomePage() { return ( -
-

Hello 大家好!

-

+
+

+ Hello 大家好! +

+

我是
Squid
魷魚

-
+
-- 2.47.1 From 738008b983a44ac14b4162bd8955c506488ab848 Mon Sep 17 00:00:00 2001 From: SquidSpirit Date: Sat, 18 Jan 2025 00:40:24 +0800 Subject: [PATCH 3/6] BLOG-5 refactor: remove unused props definition --- frontend/src/app/page.tsx | 2 ++ frontend/src/ui/layout/footer.tsx | 4 +--- frontend/src/ui/layout/navbar.tsx | 4 +--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index 470e2c9..81dae41 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -1,3 +1,5 @@ +import React from "react"; + export default function HomePage() { return (
diff --git a/frontend/src/ui/layout/footer.tsx b/frontend/src/ui/layout/footer.tsx index e30caac..7ed636f 100644 --- a/frontend/src/ui/layout/footer.tsx +++ b/frontend/src/ui/layout/footer.tsx @@ -3,9 +3,7 @@ import { faEnvelope } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import React from "react"; -type Props = {}; - -export default function Footer({}: Props) { +export default function Footer() { return (
diff --git a/frontend/src/ui/layout/navbar.tsx b/frontend/src/ui/layout/navbar.tsx index 040610c..145b4aa 100644 --- a/frontend/src/ui/layout/navbar.tsx +++ b/frontend/src/ui/layout/navbar.tsx @@ -1,8 +1,6 @@ import React from "react"; -type Props = {}; - -export default function Navbar({}: Props) { +export default function Navbar() { return (
-- 2.47.1 From 7f1a202cc7c6e4f44a3cf5678f8f83ceb425034e Mon Sep 17 00:00:00 2001 From: SquidSpirit Date: Sat, 18 Jan 2025 03:01:11 +0800 Subject: [PATCH 4/6] BLOG-5 feat: self tags animation --- frontend/next.config.ts | 2 +- frontend/package.json | 4 +- frontend/pnpm-lock.yaml | 86 +++++++++++++++++++ frontend/src/app/layout.tsx | 14 +-- frontend/src/app/page.tsx | 26 +----- .../common/presenter/ui/Footer.tsx} | 1 - .../common/presenter/ui/Navbar.tsx} | 2 - .../src/lib/home/presenter/redux/tagHooks.ts | 6 ++ .../src/lib/home/presenter/redux/tagSlice.ts | 72 ++++++++++++++++ .../src/lib/home/presenter/redux/tagStore.ts | 10 +++ .../src/lib/home/presenter/ui/SelfTags.tsx | 55 ++++++++++++ frontend/src/lib/util/shuffleArray.ts | 8 ++ frontend/tailwind.config.ts | 2 +- 13 files changed, 251 insertions(+), 37 deletions(-) rename frontend/src/{ui/layout/footer.tsx => lib/common/presenter/ui/Footer.tsx} (97%) rename frontend/src/{ui/layout/navbar.tsx => lib/common/presenter/ui/Navbar.tsx} (96%) create mode 100644 frontend/src/lib/home/presenter/redux/tagHooks.ts create mode 100644 frontend/src/lib/home/presenter/redux/tagSlice.ts create mode 100644 frontend/src/lib/home/presenter/redux/tagStore.ts create mode 100644 frontend/src/lib/home/presenter/ui/SelfTags.tsx create mode 100644 frontend/src/lib/util/shuffleArray.ts diff --git a/frontend/next.config.ts b/frontend/next.config.ts index e9ffa30..9ab38a3 100644 --- a/frontend/next.config.ts +++ b/frontend/next.config.ts @@ -1,7 +1,7 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { - /* config options here */ + reactStrictMode: false, }; export default nextConfig; diff --git a/frontend/package.json b/frontend/package.json index 722ae0b..060b633 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,9 +15,11 @@ "@fortawesome/free-regular-svg-icons": "^6.7.2", "@fortawesome/free-solid-svg-icons": "^6.7.2", "@fortawesome/react-fontawesome": "^0.2.2", + "@reduxjs/toolkit": "^2.5.0", "next": "15.1.4", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "react-redux": "^9.2.0" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 7a17382..d3648f3 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: '@fortawesome/react-fontawesome': specifier: ^0.2.2 version: 0.2.2(@fortawesome/fontawesome-svg-core@6.7.2)(react@19.0.0) + '@reduxjs/toolkit': + specifier: ^2.5.0 + version: 2.5.0(react-redux@9.2.0(@types/react@19.0.7)(react@19.0.0)(redux@5.0.1))(react@19.0.0) next: specifier: 15.1.4 version: 15.1.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -32,6 +35,9 @@ importers: react-dom: specifier: ^19.0.0 version: 19.0.0(react@19.0.0) + react-redux: + specifier: ^9.2.0 + version: 9.2.0(@types/react@19.0.7)(react@19.0.0)(redux@5.0.1) devDependencies: '@eslint/eslintrc': specifier: ^3.2.0 @@ -357,6 +363,17 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@reduxjs/toolkit@2.5.0': + resolution: {integrity: sha512-awNe2oTodsZ6LmRqmkFhtb/KH03hUhxOamEQy411m3Njj3BbFvoBovxo4Q1cBWnV1ErprVj9MlF0UPXkng0eyg==} + peerDependencies: + react: ^16.9.0 || ^17.0.0 || ^18 || ^19 + react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 + peerDependenciesMeta: + react: + optional: true + react-redux: + optional: true + '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} @@ -389,6 +406,9 @@ packages: '@types/react@19.0.7': resolution: {integrity: sha512-MoFsEJKkAtZCrC1r6CM8U22GzhG7u2Wir8ons/aCKH6MBdD1ibV24zOSSkdZVUKqN5i396zG5VKLYZ3yaUZdLA==} + '@types/use-sync-external-store@0.0.6': + resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} + '@typescript-eslint/eslint-plugin@8.20.0': resolution: {integrity: sha512-naduuphVw5StFfqp4Gq4WhIBE2gN1GEmMUExpJYknZJdRnc+2gDzB8Z3+5+/Kv33hPQRDGzQO/0opHE72lZZ6A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -979,6 +999,9 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + immer@10.1.1: + resolution: {integrity: sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==} + import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} @@ -1462,6 +1485,18 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-redux@9.2.0: + resolution: {integrity: sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==} + peerDependencies: + '@types/react': ^18.2.25 || ^19 + react: ^18.0 || ^19 + redux: ^5.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + redux: + optional: true + react@19.0.0: resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} engines: {node: '>=0.10.0'} @@ -1473,6 +1508,14 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + redux-thunk@3.1.0: + resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==} + peerDependencies: + redux: ^5.0.0 + + redux@5.0.1: + resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} + reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} @@ -1481,6 +1524,9 @@ packages: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} + reselect@5.1.1: + resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -1729,6 +1775,11 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + use-sync-external-store@1.4.0: + resolution: {integrity: sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -2010,6 +2061,16 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@reduxjs/toolkit@2.5.0(react-redux@9.2.0(@types/react@19.0.7)(react@19.0.0)(redux@5.0.1))(react@19.0.0)': + dependencies: + immer: 10.1.1 + redux: 5.0.1 + redux-thunk: 3.1.0(redux@5.0.1) + reselect: 5.1.1 + optionalDependencies: + react: 19.0.0 + react-redux: 9.2.0(@types/react@19.0.7)(react@19.0.0)(redux@5.0.1) + '@rtsao/scc@1.1.0': {} '@rushstack/eslint-patch@1.10.5': {} @@ -2038,6 +2099,8 @@ snapshots: dependencies: csstype: 3.1.3 + '@types/use-sync-external-store@0.0.6': {} + '@typescript-eslint/eslint-plugin@8.20.0(@typescript-eslint/parser@8.20.0(eslint@9.18.0(jiti@1.21.7))(typescript@5.7.3))(eslint@9.18.0(jiti@1.21.7))(typescript@5.7.3)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -2840,6 +2903,8 @@ snapshots: ignore@5.3.2: {} + immer@10.1.1: {} + import-fresh@3.3.0: dependencies: parent-module: 1.0.1 @@ -3266,6 +3331,15 @@ snapshots: react-is@16.13.1: {} + react-redux@9.2.0(@types/react@19.0.7)(react@19.0.0)(redux@5.0.1): + dependencies: + '@types/use-sync-external-store': 0.0.6 + react: 19.0.0 + use-sync-external-store: 1.4.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + redux: 5.0.1 + react@19.0.0: {} read-cache@1.0.0: @@ -3276,6 +3350,12 @@ snapshots: dependencies: picomatch: 2.3.1 + redux-thunk@3.1.0(redux@5.0.1): + dependencies: + redux: 5.0.1 + + redux@5.0.1: {} + reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.8 @@ -3296,6 +3376,8 @@ snapshots: gopd: 1.2.0 set-function-name: 2.0.2 + reselect@5.1.1: {} + resolve-from@4.0.0: {} resolve-pkg-maps@1.0.0: {} @@ -3642,6 +3724,10 @@ snapshots: dependencies: punycode: 2.3.1 + use-sync-external-store@1.4.0(react@19.0.0): + dependencies: + react: 19.0.0 + util-deprecate@1.0.2: {} which-boxed-primitive@1.1.1: diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index e0721fe..d1c1cb2 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -1,8 +1,8 @@ import type { Metadata } from "next"; import { Inter } from "next/font/google"; import "./globals.css"; -import Navbar from "@/ui/layout/navbar"; -import Footer from "@/ui/layout/footer"; +import Navbar from "@/lib/common/presenter/ui/Navbar"; +import Footer from "@/lib/common/presenter/ui/Footer"; const inter = Inter({ subsets: ["latin"], @@ -21,11 +21,11 @@ export default function RootLayout({ return ( -
- - {children} -
-
+
+ + {children} +
+
); diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index 81dae41..3c02804 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import SelfTags from "@/lib/home/presenter/ui/SelfTags"; export default function HomePage() { return ( @@ -13,29 +13,7 @@ export default function HomePage() {
魷魚

-
-
-
- - - - - - - - - - - - - - -
-
+
); } - -function Hashtag(props: { tag: string }) { - return # {props.tag}; -} diff --git a/frontend/src/ui/layout/footer.tsx b/frontend/src/lib/common/presenter/ui/Footer.tsx similarity index 97% rename from frontend/src/ui/layout/footer.tsx rename to frontend/src/lib/common/presenter/ui/Footer.tsx index 7ed636f..8386ec7 100644 --- a/frontend/src/ui/layout/footer.tsx +++ b/frontend/src/lib/common/presenter/ui/Footer.tsx @@ -1,7 +1,6 @@ import { faGithub, faYoutube } from "@fortawesome/free-brands-svg-icons"; import { faEnvelope } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import React from "react"; export default function Footer() { return ( diff --git a/frontend/src/ui/layout/navbar.tsx b/frontend/src/lib/common/presenter/ui/Navbar.tsx similarity index 96% rename from frontend/src/ui/layout/navbar.tsx rename to frontend/src/lib/common/presenter/ui/Navbar.tsx index 145b4aa..1270cac 100644 --- a/frontend/src/ui/layout/navbar.tsx +++ b/frontend/src/lib/common/presenter/ui/Navbar.tsx @@ -1,5 +1,3 @@ -import React from "react"; - export default function Navbar() { return (
diff --git a/frontend/src/lib/home/presenter/redux/tagHooks.ts b/frontend/src/lib/home/presenter/redux/tagHooks.ts new file mode 100644 index 0000000..a4c799f --- /dev/null +++ b/frontend/src/lib/home/presenter/redux/tagHooks.ts @@ -0,0 +1,6 @@ +import { useDispatch, useSelector } from "react-redux"; +import tagStore from "./tagStore"; + +export const useTagDispatch = useDispatch.withTypes(); +export const useTagSelector = + useSelector.withTypes>(); diff --git a/frontend/src/lib/home/presenter/redux/tagSlice.ts b/frontend/src/lib/home/presenter/redux/tagSlice.ts new file mode 100644 index 0000000..67f05ac --- /dev/null +++ b/frontend/src/lib/home/presenter/redux/tagSlice.ts @@ -0,0 +1,72 @@ +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; +import tagStore from "./tagStore"; +import shuffleArray from "@/lib/util/shuffleArray"; + +export interface TagState { + tags: string[]; + timer?: NodeJS.Timeout; +} + +export interface TagStartedActionPayload { + interval: number; +} + +export const tagSlice = createSlice({ + name: "tag", + initialState: { + tags: [], + timer: undefined, + } as TagState, + reducers: { + started: (state, action: PayloadAction) => { + state.tags = shuffleArray(tagsCollection); + state.timer = setInterval(() => { + tagStore.dispatch(tagSlice.actions.shuffled()); + }, action.payload.interval); + }, + shuffled: (state) => { + state.tags = shuffleArray(tagsCollection); + }, + stopped: (state) => { + clearInterval(state.timer); + state.timer = undefined; + }, + }, +}); + +export const tagStartedAction = tagSlice.actions.started; +export const tagStoppedAction = tagSlice.actions.stopped; + +const tagReducer = tagSlice.reducer; +export default tagReducer; + +const tagsCollection = [ + "APP", + "C++", + "Design Pattern", + "Docker", + "Flutter", + "Go", + "Java", + "LINER", + "Linux", + "Python", + "Squid", + "TypeScript", + "中央大學", + "全端", + "分享", + "前端", + "後端", + "教學", + "暴肝", + "知識", + "碼農", + "科技", + "科普", + "程式設計", + "資工系", + "軟體工程", + "遊戲", + "魷魚", +]; diff --git a/frontend/src/lib/home/presenter/redux/tagStore.ts b/frontend/src/lib/home/presenter/redux/tagStore.ts new file mode 100644 index 0000000..557fd1a --- /dev/null +++ b/frontend/src/lib/home/presenter/redux/tagStore.ts @@ -0,0 +1,10 @@ +import { configureStore } from "@reduxjs/toolkit"; +import tagReducer from "./tagSlice"; + +const tagStore = configureStore({ + reducer: { + tag: tagReducer, + }, +}); + +export default tagStore; diff --git a/frontend/src/lib/home/presenter/ui/SelfTags.tsx b/frontend/src/lib/home/presenter/ui/SelfTags.tsx new file mode 100644 index 0000000..1a9b44e --- /dev/null +++ b/frontend/src/lib/home/presenter/ui/SelfTags.tsx @@ -0,0 +1,55 @@ +"use client"; + +import { Provider } from "react-redux"; +import tagStore from "../redux/tagStore"; +import { useTagDispatch, useTagSelector } from "../redux/tagHooks"; +import { useEffect, useState } from "react"; +import { tagStartedAction, tagStoppedAction } from "../redux/tagSlice"; + +export default function SelfTags() { + return ( + + <_SelfTags /> + + ); +} + +function _SelfTags() { + const tags = useTagSelector((state) => state.tag.tags); + const dispatch = useTagDispatch(); + + const [isTagsVisible, setIsTagsVisible] = useState(false); + + useEffect(() => { + dispatch(tagStartedAction({ interval: 4000 })); + return () => { + dispatch(tagStoppedAction()); + setIsTagsVisible(false); + }; + }, []); + + useEffect(() => { + if (tags.length === 0) return; + setIsTagsVisible(true); + setTimeout(() => { + setIsTagsVisible(false); + }, 3500); + }, [tags]); + + return ( +
+
+
+ {tags.map((tag) => ( + + ))} +
+
+ ); +} + +function Hashtag(props: { tag: string }) { + return # {props.tag}; +} diff --git a/frontend/src/lib/util/shuffleArray.ts b/frontend/src/lib/util/shuffleArray.ts new file mode 100644 index 0000000..851ed97 --- /dev/null +++ b/frontend/src/lib/util/shuffleArray.ts @@ -0,0 +1,8 @@ +export default function shuffleArray(array: T[]): T[] { + const newArray = [...array]; + for (let i = newArray.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [newArray[i], newArray[j]] = [newArray[j], newArray[i]]; + } + return newArray; +} diff --git a/frontend/tailwind.config.ts b/frontend/tailwind.config.ts index 85afc41..11fcf7f 100644 --- a/frontend/tailwind.config.ts +++ b/frontend/tailwind.config.ts @@ -2,7 +2,7 @@ import type { Config } from "tailwindcss"; export default { content: [ - "./src/ui/**/*.{js,ts,jsx,tsx,mdx}", + "./src/lib/**/*.{js,ts,jsx,tsx,mdx}", "./src/app/**/*.{js,ts,jsx,tsx,mdx}", ], theme: { -- 2.47.1 From c16e3f29a0eda664c0d812d5a3d2bd55b6cfbe3f Mon Sep 17 00:00:00 2001 From: SquidSpirit Date: Sat, 18 Jan 2025 03:22:55 +0800 Subject: [PATCH 5/6] BLOG-5 refactor: apply clean architecture directory structure --- frontend/src/app/page.tsx | 2 +- .../src/lib/home/{presenter => framework}/ui/SelfTags.tsx | 6 +++--- frontend/src/lib/home/presenter/{redux => }/tagHooks.ts | 0 frontend/src/lib/home/presenter/{redux => }/tagSlice.ts | 0 frontend/src/lib/home/presenter/{redux => }/tagStore.ts | 0 5 files changed, 4 insertions(+), 4 deletions(-) rename frontend/src/lib/home/{presenter => framework}/ui/SelfTags.tsx (86%) rename frontend/src/lib/home/presenter/{redux => }/tagHooks.ts (100%) rename frontend/src/lib/home/presenter/{redux => }/tagSlice.ts (100%) rename frontend/src/lib/home/presenter/{redux => }/tagStore.ts (100%) diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index 3c02804..bc9a6c2 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -1,4 +1,4 @@ -import SelfTags from "@/lib/home/presenter/ui/SelfTags"; +import SelfTags from "@/lib/home/framework/ui/SelfTags"; export default function HomePage() { return ( diff --git a/frontend/src/lib/home/presenter/ui/SelfTags.tsx b/frontend/src/lib/home/framework/ui/SelfTags.tsx similarity index 86% rename from frontend/src/lib/home/presenter/ui/SelfTags.tsx rename to frontend/src/lib/home/framework/ui/SelfTags.tsx index 1a9b44e..00d2f3a 100644 --- a/frontend/src/lib/home/presenter/ui/SelfTags.tsx +++ b/frontend/src/lib/home/framework/ui/SelfTags.tsx @@ -1,10 +1,10 @@ "use client"; import { Provider } from "react-redux"; -import tagStore from "../redux/tagStore"; -import { useTagDispatch, useTagSelector } from "../redux/tagHooks"; +import tagStore from "../../presenter/tagStore"; +import { useTagDispatch, useTagSelector } from "../../presenter/tagHooks"; import { useEffect, useState } from "react"; -import { tagStartedAction, tagStoppedAction } from "../redux/tagSlice"; +import { tagStartedAction, tagStoppedAction } from "../../presenter/tagSlice"; export default function SelfTags() { return ( diff --git a/frontend/src/lib/home/presenter/redux/tagHooks.ts b/frontend/src/lib/home/presenter/tagHooks.ts similarity index 100% rename from frontend/src/lib/home/presenter/redux/tagHooks.ts rename to frontend/src/lib/home/presenter/tagHooks.ts diff --git a/frontend/src/lib/home/presenter/redux/tagSlice.ts b/frontend/src/lib/home/presenter/tagSlice.ts similarity index 100% rename from frontend/src/lib/home/presenter/redux/tagSlice.ts rename to frontend/src/lib/home/presenter/tagSlice.ts diff --git a/frontend/src/lib/home/presenter/redux/tagStore.ts b/frontend/src/lib/home/presenter/tagStore.ts similarity index 100% rename from frontend/src/lib/home/presenter/redux/tagStore.ts rename to frontend/src/lib/home/presenter/tagStore.ts -- 2.47.1 From 756112cb21e58d41d0da1dde76ef335a738c6c8e Mon Sep 17 00:00:00 2001 From: SquidSpirit Date: Sat, 18 Jan 2025 03:33:25 +0800 Subject: [PATCH 6/6] BLOG-5 docs: add comment for next config --- frontend/next.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/next.config.ts b/frontend/next.config.ts index 9ab38a3..fb53d7a 100644 --- a/frontend/next.config.ts +++ b/frontend/next.config.ts @@ -1,6 +1,7 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { + // Avoid from rendering twice in development mode reactStrictMode: false, }; -- 2.47.1