From c6472abab6ecd6b4f4c15e7265b46fb54effd78a Mon Sep 17 00:00:00 2001 From: iliiiiiili <68847099+IlIIIIIIlI@users.noreply.github.com> Date: Thu, 11 Apr 2024 00:21:24 +1000 Subject: [PATCH] feat(Image&Location): swiper, auto update location --- frontend/package-lock.json | 190 +++++++++++++++++- frontend/package.json | 7 +- .../components/StorySwiper/StorySwiper.css | 38 ++++ frontend/src/components/forms/PostForm.tsx | 18 ++ frontend/src/components/shared/PostCard.tsx | 57 +++++- 5 files changed, 294 insertions(+), 16 deletions(-) create mode 100644 frontend/src/components/StorySwiper/StorySwiper.css diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 990e375..e240da9 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -16,14 +16,17 @@ "@radix-ui/react-toast": "^1.1.5", "@tanstack/react-query": "^4.36.1", "@tanstack/react-query-devtools": "^4.35.7", + "@types/swiper": "^6.0.0", "appwrite": "^13.0.0", "attr-accept": "^2.2.2", + "axios": "^1.6.8", "class-variance-authority": "^0.7.0", "clsx": "^2.0.0", "date-fns": "^3.6.0", "eslint-config-prettier": "^9.0.0", "eslint-config-standard": "^17.1.0", "eslint-plugin-tailwindcss": "^3.13.0", + "gsap": "^3.12.5", "lucide-react": "^0.105.0-alpha.4", "next-auth": "^4.24.7", "prettier": "^3.0.3", @@ -37,13 +40,15 @@ "react-slick": "^0.30.2", "slick-carousel": "^1.8.1", "solidjs-dropzone": "^1.0.0", + "styled-components": "^6.1.8", + "swiper": "^11.1.0", "tailwind-merge": "^1.14.0", "tailwindcss-animate": "^1.0.7", "zod": "^3.22.4" }, "devDependencies": { "@types/node": "^20.8.0", - "@types/react": "^18.2.15", + "@types/react": "^18.2.74", "@types/react-dom": "^18.2.7", "@types/react-slick": "^0.23.13", "@typescript-eslint/eslint-plugin": "^6.0.0", @@ -447,6 +452,24 @@ "node": ">=6.9.0" } }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", + "integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==", + "dependencies": { + "@emotion/memoize": "^0.8.1" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", + "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" + }, "node_modules/@esbuild/android-arm": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", @@ -1759,13 +1782,12 @@ "devOptional": true }, "node_modules/@types/react": { - "version": "18.2.28", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.28.tgz", - "integrity": "sha512-ad4aa/RaaJS3hyGz0BGegdnSRXQBkd1CCYDCdNjBPg90UUpLgo+WlJqb9fMYUxtehmzF3PJaTWqRZjko6BRzBg==", + "version": "18.2.74", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.74.tgz", + "integrity": "sha512-9AEqNZZyBx8OdZpxzQlaFEVCSFUM2YXJH46yPOiOpm078k6ZLOCcuAzGum/zK8YBwY+dbahVNbHrbgrAwIRlqw==", "devOptional": true, "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, @@ -1787,18 +1809,26 @@ "@types/react": "*" } }, - "node_modules/@types/scheduler": { - "version": "0.16.4", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.4.tgz", - "integrity": "sha512-2L9ifAGl7wmXwP4v3pN4p2FLhD0O1qsJpvKmNin5VA8+UvNVb447UDaAEV6UdrkA+m/Xs58U1RFps44x6TFsVQ==", - "devOptional": true - }, "node_modules/@types/semver": { "version": "7.5.3", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", "integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==", "dev": true }, + "node_modules/@types/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-n4sx2bqL0mW1tvDf/loQ+aMX7GQD3lc3fkCMC55VFNDu/vBOabO+LTIeXKM14xK0ppk5TUGcWRjiSpIlUpghKw==" + }, + "node_modules/@types/swiper": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/swiper/-/swiper-6.0.0.tgz", + "integrity": "sha512-QPZRgxZ+ivXXtzV43B3LxpXUIC7FE/EoKM+rtxngmgt2M7eeUYypZhyqZD8UxJtlBcUDw/ATGoVeSNpvBBrz2w==", + "deprecated": "This is a stub types definition. swiper provides its own type definitions, so you do not need this installed.", + "dependencies": { + "swiper": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.7.5", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.5.tgz", @@ -2276,6 +2306,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2391,6 +2444,14 @@ "node": ">= 6" } }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001603", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001603.tgz", @@ -2579,6 +2640,24 @@ "node": ">= 8" } }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "engines": { + "node": ">=4" + } + }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -3432,6 +3511,25 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==" }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -3667,6 +3765,11 @@ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" }, + "node_modules/gsap": { + "version": "3.12.5", + "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.12.5.tgz", + "integrity": "sha512-srBfnk4n+Oe/ZnMIOXt3gT605BX9x5+rh/prT2F1SsNJsU1XuMiP0E2aptW481OnonOGACZWBqseH5Z7csHxhQ==" + }, "node_modules/has": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", @@ -4915,6 +5018,11 @@ "react-is": "^16.13.1" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -5315,6 +5423,11 @@ "node": ">= 0.4" } }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -5485,6 +5598,38 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/styled-components": { + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.8.tgz", + "integrity": "sha512-PQ6Dn+QxlWyEGCKDS71NGsXoVLKfE1c3vApkvDYS5KAK+V8fNWGhbSUEo9Gg2iaID2tjLXegEW3bZDUGpofRWw==", + "dependencies": { + "@emotion/is-prop-valid": "1.2.1", + "@emotion/unitless": "0.8.0", + "@types/stylis": "4.2.0", + "css-to-react-native": "3.2.0", + "csstype": "3.1.2", + "postcss": "8.4.31", + "shallowequal": "1.1.0", + "stylis": "4.3.1", + "tslib": "2.5.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0" + } + }, + "node_modules/styled-components/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, "node_modules/styled-jsx": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", @@ -5508,6 +5653,11 @@ } } }, + "node_modules/stylis": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz", + "integrity": "sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ==" + }, "node_modules/sucrase": { "version": "3.34.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", @@ -5582,6 +5732,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swiper": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.0.tgz", + "integrity": "sha512-Pm78CgU7Wvg+w/MgIL/1NwMSLgx0XqFof25EnVyX8iZFCYJv5CppH7LHkBj43qW2k5Cp3Iz7FcdBxrox7XX2AQ==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/swiperjs" + }, + { + "type": "open_collective", + "url": "http://opencollective.com/swiper" + } + ], + "engines": { + "node": ">= 4.7.0" + } + }, "node_modules/tailwind-merge": { "version": "1.14.0", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.14.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 4f6d915..06b2988 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -18,14 +18,17 @@ "@radix-ui/react-toast": "^1.1.5", "@tanstack/react-query": "^4.36.1", "@tanstack/react-query-devtools": "^4.35.7", + "@types/swiper": "^6.0.0", "appwrite": "^13.0.0", "attr-accept": "^2.2.2", + "axios": "^1.6.8", "class-variance-authority": "^0.7.0", "clsx": "^2.0.0", "date-fns": "^3.6.0", "eslint-config-prettier": "^9.0.0", "eslint-config-standard": "^17.1.0", "eslint-plugin-tailwindcss": "^3.13.0", + "gsap": "^3.12.5", "lucide-react": "^0.105.0-alpha.4", "next-auth": "^4.24.7", "prettier": "^3.0.3", @@ -39,13 +42,15 @@ "react-slick": "^0.30.2", "slick-carousel": "^1.8.1", "solidjs-dropzone": "^1.0.0", + "styled-components": "^6.1.8", + "swiper": "^11.1.0", "tailwind-merge": "^1.14.0", "tailwindcss-animate": "^1.0.7", "zod": "^3.22.4" }, "devDependencies": { "@types/node": "^20.8.0", - "@types/react": "^18.2.15", + "@types/react": "^18.2.74", "@types/react-dom": "^18.2.7", "@types/react-slick": "^0.23.13", "@typescript-eslint/eslint-plugin": "^6.0.0", diff --git a/frontend/src/components/StorySwiper/StorySwiper.css b/frontend/src/components/StorySwiper/StorySwiper.css new file mode 100644 index 0000000..5cb8198 --- /dev/null +++ b/frontend/src/components/StorySwiper/StorySwiper.css @@ -0,0 +1,38 @@ +/* .swiper { + width: 30%; + height: 30%; +} */ + +.swiper-slide { + text-align: center; + font-size: 18px; + background: #fff; + + /* Center slide text vertically */ + display: flex; + justify-content: center; + align-items: center; +} + +.swiper-slide img { + display: block; + object-fit: cover; +} + +.mySwiper { + width: 500px !important; /* 或者任何具体的宽度值 */ + height: 500px !important; /* 根据你的需求调整高度 */ +} + +.mySwiper img { + width: 100%; /* 图片宽度占满容器 */ + height: 100%; /* 图片高度占满容器 */ + object-fit: cover; /* 保持宽高比,可能会裁剪图片 */ +} + +@media (max-width: 600px) { + .mySwiper { + width: 350px !important; + height: 200px !important; /* 在小屏幕上减小高度 */ + } +} diff --git a/frontend/src/components/forms/PostForm.tsx b/frontend/src/components/forms/PostForm.tsx index 02c1970..f082385 100644 --- a/frontend/src/components/forms/PostForm.tsx +++ b/frontend/src/components/forms/PostForm.tsx @@ -1,8 +1,10 @@ +import React, { useEffect } from "react"; import * as z from "zod"; import { Models } from "appwrite"; import { useForm } from "react-hook-form"; import { useNavigate } from "react-router-dom"; import { zodResolver } from "@hookform/resolvers/zod"; +import axios from "axios"; import { Form, @@ -40,6 +42,22 @@ const PostForm = ({ post, action }: PostFormProps) => { }, }); + useEffect(() => { + const fetchLocation = async () => { + try { + const { data } = await axios.get( + "https://ipinfo.io/json?token=467f453bf210c1" + ); + const location = data.city; // 或者使用data.loc分割来获取经纬度 + form.setValue("location", location, { shouldValidate: true }); + } catch (error) { + console.error("Error fetching location:", error); + } + }; + + fetchLocation(); + }, [form]); + // Query const { mutateAsync: createPost, isLoading: isLoadingCreate } = useCreatePost(); diff --git a/frontend/src/components/shared/PostCard.tsx b/frontend/src/components/shared/PostCard.tsx index 1fbf29e..4e66469 100644 --- a/frontend/src/components/shared/PostCard.tsx +++ b/frontend/src/components/shared/PostCard.tsx @@ -5,6 +5,15 @@ import { PostStats } from "@/components/shared"; import { multiFormatDateString } from "@/lib/utils"; import { useUserContext } from "@/context/AuthContext"; +// Swiper imports +import { Swiper, SwiperSlide } from "swiper/react"; +import "swiper/css"; +import "swiper/css/effect-cube"; +// import "swiper/css/pagination"; +import "swiper/css/scrollbar"; +import "../StorySwiper/StorySwiper.css"; +import { EffectCube, Scrollbar, Autoplay, Navigation } from "swiper/modules"; + type PostCardProps = { post: Models.Document; }; @@ -68,13 +77,53 @@ const PostCard = ({ post }: PostCardProps) => { ))} - + + {post.imageS && post.imageS.length > 0 ? ( +
+ + {post.imageS.map( + ( + imageUrl: string, + index: number // Explicitly declare types here + ) => ( + + {`post + + ) + )} + +
+ ) : ( post image - + )}