From a993e678f640b070e9a7766173ea54127d822034 Mon Sep 17 00:00:00 2001 From: Zeyu Wang Date: Sun, 15 Oct 2023 03:03:47 -0400 Subject: [PATCH 1/3] add new dropdown component to the main page with styles --- app/page.tsx | 2 ++ components/dropdown.tsx | 41 ++++++++++++++++++++++++++++ components/header.tsx | 2 +- components/selection.tsx | 56 ++++++++++++++++++++++++++++++++++++++ lib/data.ts | 4 +++ package-lock.json | 59 ++++++++++++++++++++++++++++++---------- package.json | 11 ++++---- 7 files changed, 155 insertions(+), 20 deletions(-) create mode 100644 components/dropdown.tsx create mode 100644 components/selection.tsx diff --git a/app/page.tsx b/app/page.tsx index 63955de3..b1ee4404 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -5,6 +5,7 @@ import Intro from "@/components/intro"; import Projects from "@/components/projects"; import SectionDivider from "@/components/section-divider"; import Skills from "@/components/skills"; +import Selection from "@/components/selection"; export default function Home() { return ( @@ -16,6 +17,7 @@ export default function Home() { + ); } diff --git a/components/dropdown.tsx b/components/dropdown.tsx new file mode 100644 index 00000000..957ddd8a --- /dev/null +++ b/components/dropdown.tsx @@ -0,0 +1,41 @@ +"use client"; + +import { useState } from 'react'; + +interface DropdownProps { + items: { name: string, message: string, created_at: string | number }[]; + onSelect: (item: any) => void; +} + +function Dropdown({ items, onSelect }: DropdownProps) { + const [isOpen, setIsOpen] = useState(false); + const maxHeight = Math.min(items.length, 5) * 30 + + return ( +
+ +
+ {isOpen && ( +
    + {items.map((item, idx) => { + const date = String(new Date(item.created_at)).split('(')[0]; + const parse = `${item.name} "${item.message}" ${date}`; + return ( +
  • { onSelect(parse); setIsOpen(false) }} className="bg-white borderBlack rounded-xl px-5 py-3 dark:bg-white/10 dark:text-white/80"> + {parse} +
  • + ) + })} +
+ )} +
+ ); +} + +export default Dropdown; diff --git a/components/header.tsx b/components/header.tsx index a1e53f21..f210b310 100644 --- a/components/header.tsx +++ b/components/header.tsx @@ -14,7 +14,7 @@ export default function Header() { return (
diff --git a/components/selection.tsx b/components/selection.tsx new file mode 100644 index 00000000..29355ea2 --- /dev/null +++ b/components/selection.tsx @@ -0,0 +1,56 @@ +"use client"; + +import { useState } from 'react'; +import useSWR from 'swr'; +import Dropdown from './dropdown'; +import { motion } from "framer-motion"; +import { useSectionInView } from "@/lib/hooks"; +import SectionHeading from './section-heading'; + + +interface Item { + name: string; + message: string; + created_at: string | number; +} + +interface Response { + rows: Item[]; +} + +const fetcher = (url: string) => fetch(url).then((res) => res.json()); + +const Selection = () => { + const { data } = useSWR('https://generic-web-app-be.azurewebsites.net/api/generic_data/messages/?collection_name=monolith&skip=0&limit=32', fetcher); + + const items: Item[] = data?.rows || []; + const [selectedItem, setSelectedItem] = useState(null); + const { ref } = useSectionInView("Selection"); + + return ( + + Dropdown Selection + {selectedItem &&
Selected: {selectedItem}
} +
+ +
+ ); +} + +export default Selection; diff --git a/lib/data.ts b/lib/data.ts index 2558095d..5af0eaf1 100644 --- a/lib/data.ts +++ b/lib/data.ts @@ -31,6 +31,10 @@ export const links = [ name: "Contact", hash: "#contact", }, + { + name: "Selection", + hash: "#selection", + }, ] as const; export const experiencesData = [ diff --git a/package-lock.json b/package-lock.json index 82f90853..eb3fe160 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,8 +10,6 @@ "dependencies": { "@react-email/components": "^0.0.7", "@react-email/tailwind": "^0.0.8", - "@types/node": "20.3.2", - "@types/react": "18.2.14", "@types/react-dom": "18.2.6", "autoprefixer": "10.4.14", "clsx": "^1.2.1", @@ -27,11 +25,14 @@ "react-intersection-observer": "^9.5.2", "react-vertical-timeline-component": "^3.6.0", "resend": "^0.16.0", - "tailwindcss": "3.3.2", - "typescript": "5.1.5" + "swr": "^2.2.4", + "tailwindcss": "3.3.2" }, "devDependencies": { - "@types/react-vertical-timeline-component": "^3.3.3" + "@types/node": "20.8.6", + "@types/react": "18.2.28", + "@types/react-vertical-timeline-component": "^3.3.3", + "typescript": "5.2.2" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -672,9 +673,13 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" }, "node_modules/@types/node": { - "version": "20.3.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.2.tgz", - "integrity": "sha512-vOBLVQeCQfIcF/2Y7eKFTqrMnizK5lRNQ7ykML/5RuwVXVWxYkgwS7xbt4B6fKCUPgbSL5FSsjHQpaGQP/dQmw==" + "version": "20.8.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.6.tgz", + "integrity": "sha512-eWO4K2Ji70QzKUqRy6oyJWUeB7+g2cRagT3T/nxYibYcT4y2BDL8lqolRXjTHmkZCdJfIPaY73KbJAZmcryxTQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.25.1" + } }, "node_modules/@types/prop-types": { "version": "15.7.5", @@ -682,9 +687,9 @@ "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "node_modules/@types/react": { - "version": "18.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.14.tgz", - "integrity": "sha512-A0zjq+QN/O0Kpe30hA1GidzyFjatVvrpIvWLxD+xv67Vt91TWWgco9IvrJBkeyHm1trGaFS/FSGqPlhyeZRm0g==", + "version": "18.2.28", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.28.tgz", + "integrity": "sha512-ad4aa/RaaJS3hyGz0BGegdnSRXQBkd1CCYDCdNjBPg90UUpLgo+WlJqb9fMYUxtehmzF3PJaTWqRZjko6BRzBg==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -4790,6 +4795,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swr": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.4.tgz", + "integrity": "sha512-njiZ/4RiIhoOlAaLYDqwz5qH/KZXVilRLvomrx83HjzCWTfa+InyfAjv05PSFxnmLzZkNO9ZfvgoqzAaEI4sGQ==", + "dependencies": { + "client-only": "^0.0.1", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/synckit": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", @@ -5118,9 +5135,9 @@ } }, "node_modules/typescript": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.5.tgz", - "integrity": "sha512-FOH+WN/DQjUvN6WgW+c4Ml3yi0PH+a/8q+kNIfRehv1wLhWONedw85iu+vQ39Wp49IzTJEsZ2lyLXpBF7mkF1g==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -5143,6 +5160,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici-types": { + "version": "5.25.3", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", + "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", + "dev": true + }, "node_modules/untildify": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", @@ -5188,6 +5211,14 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index a2602249..75de88b8 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,6 @@ "dependencies": { "@react-email/components": "^0.0.7", "@react-email/tailwind": "^0.0.8", - "@types/node": "20.3.2", - "@types/react": "18.2.14", "@types/react-dom": "18.2.6", "autoprefixer": "10.4.14", "clsx": "^1.2.1", @@ -28,10 +26,13 @@ "react-intersection-observer": "^9.5.2", "react-vertical-timeline-component": "^3.6.0", "resend": "^0.16.0", - "tailwindcss": "3.3.2", - "typescript": "5.1.5" + "swr": "^2.2.4", + "tailwindcss": "3.3.2" }, "devDependencies": { - "@types/react-vertical-timeline-component": "^3.3.3" + "@types/node": "20.8.6", + "@types/react": "18.2.28", + "@types/react-vertical-timeline-component": "^3.3.3", + "typescript": "5.2.2" } } From 52a43799459d24cfb453a47338b2635ab406329a Mon Sep 17 00:00:00 2001 From: Zeyu Wang Date: Sun, 15 Oct 2023 13:08:35 -0400 Subject: [PATCH 2/3] modify the height of the list --- components/dropdown.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/dropdown.tsx b/components/dropdown.tsx index 957ddd8a..bff9e4f2 100644 --- a/components/dropdown.tsx +++ b/components/dropdown.tsx @@ -9,7 +9,7 @@ interface DropdownProps { function Dropdown({ items, onSelect }: DropdownProps) { const [isOpen, setIsOpen] = useState(false); - const maxHeight = Math.min(items.length, 5) * 30 + const maxHeight = Math.min(items.length, 5)*3; return (
@@ -22,7 +22,7 @@ function Dropdown({ items, onSelect }: DropdownProps) {
{isOpen && ( -
    +
      {items.map((item, idx) => { const date = String(new Date(item.created_at)).split('(')[0]; const parse = `${item.name} "${item.message}" ${date}`; From 89c2b81104b85460ad9b6e51cf2e01322d516567 Mon Sep 17 00:00:00 2001 From: Zeyu Wang Date: Sun, 15 Oct 2023 13:15:43 -0400 Subject: [PATCH 3/3] add cursor pointer to the list items --- components/dropdown.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/dropdown.tsx b/components/dropdown.tsx index bff9e4f2..f745f400 100644 --- a/components/dropdown.tsx +++ b/components/dropdown.tsx @@ -27,7 +27,7 @@ function Dropdown({ items, onSelect }: DropdownProps) { const date = String(new Date(item.created_at)).split('(')[0]; const parse = `${item.name} "${item.message}" ${date}`; return ( -
    • { onSelect(parse); setIsOpen(false) }} className="bg-white borderBlack rounded-xl px-5 py-3 dark:bg-white/10 dark:text-white/80"> +
    • { onSelect(parse); setIsOpen(false) }} className="bg-white borderBlack rounded-xl px-5 py-3 dark:bg-white/10 dark:text-white/80 cursor-pointer"> {parse}
    • )