diff --git a/package-lock.json b/package-lock.json index 02e8c03..34836fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2337,34 +2337,6 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.14", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", @@ -2587,52 +2559,6 @@ } } }, - "node_modules/@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "optional": true, - "peer": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "optional": true, - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/express": { - "version": "4.17.14", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", - "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", - "optional": true, - "peer": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.17.31", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", - "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", - "optional": true, - "peer": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, "node_modules/@types/http-proxy": { "version": "1.17.9", "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", @@ -2641,13 +2567,6 @@ "@types/node": "*" } }, - "node_modules/@types/mime": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", - "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", - "optional": true, - "peer": true - }, "node_modules/@types/node": { "version": "18.17.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.1.tgz", @@ -2658,20 +2577,6 @@ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, - "node_modules/@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", - "optional": true, - "peer": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", - "optional": true, - "peer": true - }, "node_modules/@types/react": { "version": "18.0.21", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.21.tgz", @@ -2695,17 +2600,6 @@ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, - "node_modules/@types/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", - "optional": true, - "peer": true, - "dependencies": { - "@types/mime": "*", - "@types/node": "*" - } - }, "node_modules/@types/yoga-layout": { "version": "1.9.2", "resolved": "https://registry.npmjs.org/@types/yoga-layout/-/yoga-layout-1.9.2.tgz", @@ -2750,20 +2644,6 @@ "node": ">= 0.6" } }, - "node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true, - "optional": true, - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/ajv-formats": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", @@ -7515,34 +7395,6 @@ "rimraf": "bin.js" } }, - "node_modules/terser": { - "version": "5.15.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", - "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -9579,33 +9431,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" }, - "@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - } - } - }, "@jridgewell/sourcemap-codec": { "version": "1.4.14", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", @@ -9753,52 +9578,6 @@ "use-sync-external-store": "^1.2.0" } }, - "@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "optional": true, - "peer": true, - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "optional": true, - "peer": true, - "requires": { - "@types/node": "*" - } - }, - "@types/express": { - "version": "4.17.14", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", - "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", - "optional": true, - "peer": true, - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.31", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", - "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", - "optional": true, - "peer": true, - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, "@types/http-proxy": { "version": "1.17.9", "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", @@ -9807,13 +9586,6 @@ "@types/node": "*" } }, - "@types/mime": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", - "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", - "optional": true, - "peer": true - }, "@types/node": { "version": "18.17.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.1.tgz", @@ -9824,20 +9596,6 @@ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, - "@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", - "optional": true, - "peer": true - }, - "@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", - "optional": true, - "peer": true - }, "@types/react": { "version": "18.0.21", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.21.tgz", @@ -9861,17 +9619,6 @@ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, - "@types/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", - "optional": true, - "peer": true, - "requires": { - "@types/mime": "*", - "@types/node": "*" - } - }, "@types/yoga-layout": { "version": "1.9.2", "resolved": "https://registry.npmjs.org/@types/yoga-layout/-/yoga-layout-1.9.2.tgz", @@ -9906,14 +9653,6 @@ "negotiator": "0.6.3" } }, - "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true, - "optional": true, - "peer": true - }, "ajv-formats": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", @@ -13375,30 +13114,6 @@ } } }, - "terser": { - "version": "5.15.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", - "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "optional": true, - "peer": true - } - } - }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", diff --git a/src/App.tsx b/src/App.tsx index 09a4d53..91424ba 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -13,6 +13,8 @@ import { ProfilePage } from "./pages/profile"; import { SettingsPage } from "./pages/settings"; import { EditorPage, EditArticlePage } from "./pages/editor"; import { ArticlePage } from "./pages/article"; +import { TopicListPage } from "./pages/topic"; +import { TopicDetailPage } from "./pages/topic/detail"; import { TOKEN_KEY } from "./constants"; @@ -75,6 +77,8 @@ function App() { } /> } /> } /> + } /> + } /> } /> } /> diff --git a/src/components/Header.tsx b/src/components/Header.tsx index aa88295..54140c6 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -20,6 +20,11 @@ export const Header: React.FC = () => { Home +
  • + + Topics + +
  • {!isLoggedIn ? ( <>
  • diff --git a/src/interfaces/index.d.ts b/src/interfaces/index.d.ts index a15cc74..645d1b5 100644 --- a/src/interfaces/index.d.ts +++ b/src/interfaces/index.d.ts @@ -33,3 +33,21 @@ export interface IAuthor { image: string; username: string; } + +export interface ITopic { + id: string; + title: string; + description: string; + coverImage: string; + articleCount: number; + createdAt: string; +} + +export interface ITopicArticle { + slug: string; + title: string; + description: string; + author: IAuthor; + createdAt: string; + favoritesCount: number; +} diff --git a/src/pages/topic/detail.tsx b/src/pages/topic/detail.tsx new file mode 100644 index 0000000..10cb41e --- /dev/null +++ b/src/pages/topic/detail.tsx @@ -0,0 +1,190 @@ +import { useList, useOne } from "@refinedev/core"; +import { Link, useParams } from "react-router-dom"; +import { ITopic, IArticle } from "../../interfaces"; +import dayjs from "dayjs"; + +export const TopicDetailPage: React.FC = () => { + const { id } = useParams<{ id: string }>(); + + const { data: topic, isLoading: topicLoading } = useOne({ + resource: "topics", + id: id || "", + }); + + const { data: articles, isLoading: articlesLoading } = useList({ + resource: "articles", + filters: [ + { + field: "topicId", + operator: "eq", + value: id, + }, + ], + pagination: { + current: 1, + pageSize: 10, + }, + }); + + const mockTopic: ITopic = { + id: id || "1", + title: "前端技术前沿", + description: "探索最新的前端技术趋势,包括React、Vue、Angular等框架的最新发展动态,以及WebAssembly、TypeScript等技术的应用实践。", + coverImage: "https://picsum.photos/seed/topic1/1200/400", + articleCount: 12, + createdAt: "2024-01-15T00:00:00.000Z", + }; + + const mockArticles: IArticle[] = [ + { + slug: "react-18-features", + title: "React 18 新特性详解", + description: "深入了解React 18带来的并发渲染、自动批处理、Suspense改进等重要新特性", + body: "", + createdAt: "2024-03-01T00:00:00.000Z", + updatedAt: "2024-03-01T00:00:00.000Z", + favorited: false, + favoritesCount: 156, + tagList: ["React", "Frontend"], + author: { + username: "张三", + image: "https://picsum.photos/seed/user1/100/100", + bio: "前端开发工程师", + following: false, + }, + }, + { + slug: "typescript-advanced", + title: "TypeScript 高级类型技巧", + description: "掌握TypeScript中的条件类型、映射类型、模板字面量类型等高级特性", + body: "", + createdAt: "2024-02-28T00:00:00.000Z", + updatedAt: "2024-02-28T00:00:00.000Z", + favorited: true, + favoritesCount: 234, + tagList: ["TypeScript", "Frontend"], + author: { + username: "李四", + image: "https://picsum.photos/seed/user2/100/100", + bio: "全栈开发者", + following: true, + }, + }, + { + slug: "vue3-composition-api", + title: "Vue 3 Composition API 实战指南", + description: "从实际项目出发,学习如何使用Composition API构建可维护的Vue应用", + body: "", + createdAt: "2024-02-20T00:00:00.000Z", + updatedAt: "2024-02-20T00:00:00.000Z", + favorited: false, + favoritesCount: 89, + tagList: ["Vue", "Frontend"], + author: { + username: "王五", + image: "https://picsum.photos/seed/user3/100/100", + bio: "Vue核心贡献者", + following: false, + }, + }, + { + slug: "webassembly-intro", + title: "WebAssembly 入门与实践", + description: "了解WebAssembly的基本概念,以及如何在浏览器中运行高性能的C/C++代码", + body: "", + createdAt: "2024-02-15T00:00:00.000Z", + updatedAt: "2024-02-15T00:00:00.000Z", + favorited: false, + favoritesCount: 178, + tagList: ["WebAssembly", "Performance"], + author: { + username: "赵六", + image: "https://picsum.photos/seed/user4/100/100", + bio: "性能优化专家", + following: false, + }, + }, + ]; + + const displayTopic = topic?.data || mockTopic; + const displayArticles = articles?.data || mockArticles; + + return ( +
    +
    +
    + + 返回专题列表 + +

    {displayTopic.title}

    +

    {displayTopic.description}

    +
    + + {displayTopic.articleCount} 篇文章 + + + 创建于 {dayjs(displayTopic.createdAt).format("YYYY年MM月DD日")} + +
    +
    +
    +
    +

    专题文章

    + {articlesLoading && ( +
    Loading articles...
    + )} + {!displayArticles.length && !articlesLoading && ( +
    + 该专题暂无文章... +
    + )} + {displayArticles.map((article) => ( +
    +
    + + {article.author.username} + +
    + + {article.author.username} + + + {dayjs(article.createdAt).format("MMM DD, YYYY")} + +
    + +
    + +

    {article.title}

    +

    {article.description}

    + Read more... +
      + {article.tagList.map((tag, index) => ( +
    • + {tag} +
    • + ))} +
    + +
    + ))} +
    +
    + ); +}; diff --git a/src/pages/topic/index.tsx b/src/pages/topic/index.tsx new file mode 100644 index 0000000..cb79907 --- /dev/null +++ b/src/pages/topic/index.tsx @@ -0,0 +1,232 @@ +import { useList } from "@refinedev/core"; +import { Link } from "react-router-dom"; +import { ITopic } from "../../interfaces"; +import dayjs from "dayjs"; + +export const TopicListPage: React.FC = () => { + const { data: topics, isLoading } = useList({ + resource: "topics", + pagination: { + current: 1, + pageSize: 10, + }, + }); + + const mockTopics: ITopic[] = [ + { + id: "1", + title: "前端技术前沿", + description: "探索最新的前端技术趋势,包括React、Vue、Angular等框架的最新发展动态,以及WebAssembly、TypeScript等技术的应用实践。", + coverImage: "https://picsum.photos/seed/topic1/800/400", + articleCount: 12, + createdAt: "2024-01-15T00:00:00.000Z", + }, + { + id: "2", + title: "后端架构设计", + description: "深入探讨微服务架构、分布式系统设计、数据库优化等后端核心技术,分享企业级应用的架构实践经验。", + coverImage: "https://picsum.photos/seed/topic2/800/400", + articleCount: 8, + createdAt: "2024-02-20T00:00:00.000Z", + }, + { + id: "3", + title: "DevOps与CI/CD", + description: "分享DevOps最佳实践,包括Docker容器化、Kubernetes编排、Jenkins流水线、GitOps等现代化运维技术。", + coverImage: "https://picsum.photos/seed/topic3/800/400", + articleCount: 15, + createdAt: "2024-03-10T00:00:00.000Z", + }, + { + id: "4", + title: "人工智能与机器学习", + description: "从基础算法到深度学习应用,了解AI/ML在实际项目中的落地,包括自然语言处理、计算机视觉等领域。", + coverImage: "https://picsum.photos/seed/topic4/800/400", + articleCount: 20, + createdAt: "2024-04-05T00:00:00.000Z", + }, + { + id: "5", + title: "移动开发跨平台", + description: "关注Flutter、React Native等跨平台移动开发技术,分享移动端应用开发的最佳实践和性能优化技巧。", + coverImage: "https://picsum.photos/seed/topic5/800/400", + articleCount: 9, + createdAt: "2024-05-18T00:00:00.000Z", + }, + { + id: "6", + title: "云原生技术", + description: "探索云原生生态系统,包括Serverless架构、服务网格、可观测性等云原生核心技术的应用与实践。", + coverImage: "https://picsum.photos/seed/topic6/800/400", + articleCount: 11, + createdAt: "2024-06-22T00:00:00.000Z", + }, + ]; + + const displayTopics = topics?.data || mockTopics; + + return ( +
    +
    +
    +

    + 专题专栏 +

    +

    + 探索精选技术专题,深度学习专业领域知识 +

    +
    +
    +
    + {isLoading && ( +
    +
    + Loading... +
    +

    Loading topics...

    +
    + )} +
    + {displayTopics.map((topic) => ( +
    + +
    { + e.currentTarget.style.transform = "translateY(-8px)"; + e.currentTarget.style.boxShadow = + "0 20px 40px rgba(0,0,0,0.15)"; + }} + onMouseLeave={(e) => { + e.currentTarget.style.transform = "translateY(0)"; + e.currentTarget.style.boxShadow = + "0 1px 3px rgba(0,0,0,0.1)"; + }} + > +
    + {topic.title} { + e.currentTarget.style.transform = "scale(1.05)"; + }} + onMouseLeave={(e) => { + e.currentTarget.style.transform = "scale(1)"; + }} + /> +
    + + {topic.articleCount} 篇 +
    +
    +
    +
    + {topic.title} +
    +

    + {topic.description} +

    +
    + + + {dayjs(topic.createdAt).format("YYYY年MM月DD日")} + + + 查看专题 + + +
    +
    +
    + +
    + ))} +
    +
    +
    + ); +};