From 56677616b4cdb992d51f88b5750a5c5a1210a3b8 Mon Sep 17 00:00:00 2001 From: yanyongyu Date: Fri, 31 Dec 2021 11:27:37 +0800 Subject: [PATCH] :construction: add tag selection --- website/package.json | 1 - website/src/components/Card/index.tsx | 29 ++++- website/src/components/Paginate/index.tsx | 91 ++++++++++++--- .../src/components/Paginate/styles.module.css | 6 +- website/src/components/Plugin.tsx | 108 +++++++++++++++++- 5 files changed, 207 insertions(+), 28 deletions(-) diff --git a/website/package.json b/website/package.json index bdbe2031..4533d091 100644 --- a/website/package.json +++ b/website/package.json @@ -32,7 +32,6 @@ "react": "^17.0.1", "react-color": "^2.19.3", "react-dom": "^17.0.1", - "react-paginate": "^8.1.0", "react-use-pagination": "^2.0.1", "resize-observer-polyfill": "^1.5.1", "url-loader": "^4.1.1" diff --git a/website/src/components/Card/index.tsx b/website/src/components/Card/index.tsx index a37ca74a..636fb4aa 100644 --- a/website/src/components/Card/index.tsx +++ b/website/src/components/Card/index.tsx @@ -1,9 +1,10 @@ +import clsx from "clsx"; import React from "react"; import Link from "@docusaurus/Link"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import type { Obj } from "../../libs/store"; +import type { Obj, Tag as TagType } from "../../libs/store"; function pickTextColor(bgColor, lightColor, darkColor) { var color = bgColor.charAt(0) === "#" ? bgColor.substring(1, 7) : bgColor; @@ -13,6 +14,32 @@ function pickTextColor(bgColor, lightColor, darkColor) { return r * 0.299 + g * 0.587 + b * 0.114 > 186 ? darkColor : lightColor; } +export function Tag({ + label, + color, + className, + onClick, +}: TagType & { + className?: string; + onClick?: React.MouseEventHandler; +}): JSX.Element { + return ( + + {label} + + ); +} + export default function Card({ module_name, name, diff --git a/website/src/components/Paginate/index.tsx b/website/src/components/Paginate/index.tsx index 3e288faa..b3df7416 100644 --- a/website/src/components/Paginate/index.tsx +++ b/website/src/components/Paginate/index.tsx @@ -1,5 +1,5 @@ +import clsx from "clsx"; import React, { useCallback, useRef } from "react"; -import ReactPaginate from "react-paginate"; import { usePagination } from "react-use-pagination"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -9,11 +9,19 @@ import styles from "./styles.module.css"; export default function Paginate({ totalPages, + setPreviousPage, + setNextPage, setPage, currentPage, + previousEnabled, + nextEnabled, }: ReturnType): JSX.Element { const ref = useRef(); const maxWidth = useContentWidth(ref.current?.parentElement ?? undefined); + const maxLength = Math.min( + (maxWidth && Math.floor(maxWidth / 50) - 2) || totalPages, + totalPages + ); const onPageChange = useCallback( (selectedItem: { selected: number }) => { @@ -21,27 +29,74 @@ export default function Paginate({ }, [setPage] ); + const range = useCallback((start: number, end: number) => { + const result = []; + start = start > 0 ? start : 1; + for (let i = start; i <= end; i++) { + result.push(i); + } + return result; + }, []); // FIXME: responsive width + const pages: (React.ReactNode | number)[] = []; + const ellipsis = ; + + const even = maxLength % 2 === 0 ? 1 : 0; + const left = Math.floor(maxLength / 2); + const right = totalPages - left + even + 1; + currentPage = currentPage + 1; + + if (totalPages <= maxLength) { + pages.push(...range(1, totalPages)); + } else if (currentPage > left && currentPage < right) { + const firstItem = 1; + const lastItem = totalPages; + const start = currentPage - left + 2; + const end = currentPage + left - 2 - even; + const secondItem = start - 1 === firstItem + 1 ? 2 : ellipsis; + const beforeLastItem = end + 1 === lastItem - 1 ? end + 1 : ellipsis; + + pages.push(1, secondItem, ...range(start, end), beforeLastItem, totalPages); + } else if (currentPage === left) { + const end = currentPage + left - 1 - even; + pages.push(...range(1, end), ellipsis, totalPages); + } else if (currentPage === right) { + const start = currentPage - left + 1; + pages.push(1, ellipsis, ...range(start, totalPages)); + } else { + pages.push(...range(1, left), ellipsis, ...range(right, totalPages)); + } + return ( ); } diff --git a/website/src/components/Paginate/styles.module.css b/website/src/components/Paginate/styles.module.css index fb0931a3..0abb409a 100644 --- a/website/src/components/Paginate/styles.module.css +++ b/website/src/components/Paginate/styles.module.css @@ -6,7 +6,7 @@ @apply flex items-center; } -.a { +.button { height: 34px; width: auto; min-width: 34px; @@ -15,12 +15,12 @@ @apply text-black bg-light-nonepress-100; } -:global(.dark) .a { +:global(.dark) .button { @apply border-dark-nonepress-200 shadow-dark-nonepress-300; @apply text-white bg-dark-nonepress-100; } -.a.active { +.button.active { @apply bg-hero text-white border-hero; } diff --git a/website/src/components/Plugin.tsx b/website/src/components/Plugin.tsx index e66efd89..9651a167 100644 --- a/website/src/components/Plugin.tsx +++ b/website/src/components/Plugin.tsx @@ -1,9 +1,11 @@ -import React, { useCallback, useState } from "react"; +import clsx from "clsx"; +import React, { useState } from "react"; +import { ChromePicker } from "react-color"; import { usePagination } from "react-use-pagination"; import plugins from "../../static/plugins.json"; -import { useFilteredObjs } from "../libs/store"; -import Card from "./Card"; +import { Tag, useFilteredObjs } from "../libs/store"; +import Card, { Tag as TagComponent } from "./Card"; import Modal from "./Modal"; import Paginate from "./Paginate"; @@ -29,8 +31,45 @@ export default function Adapter(): JSX.Element { moduleName: string; homepage: string; }>({ name: "", desc: "", projectLink: "", moduleName: "", homepage: "" }); + const [tags, setTags] = useState([]); + const [label, setLabel] = useState(""); + const [color, setColor] = useState("#ea5252"); const onSubmit = () => { - console.log(form); + setModalOpen(false); + const title = encodeURIComponent(`Plugin: ${form.name}`).replace( + /%2B/gi, + "+" + ); + const body = encodeURIComponent( + ` +**插件名称:** + +${form.name} + +**插件功能:** + +${form.desc} + +**PyPI 项目名:** + +${form.projectLink} + +**插件 import 包名:** + +${form.moduleName} + +**插件项目仓库/主页链接:** + +${form.homepage} + +**标签:** + +${JSON.stringify(tags)} +`.trim() + ).replace(/%2B/gi, "+"); + window.open( + `https://github.com/nonebot/nonebot2/issues/new?title=${title}&body=${body}&labels=Plugin` + ); }; const onChange = (event) => { const target = event.target; @@ -43,6 +82,27 @@ export default function Adapter(): JSX.Element { }); event.preventDefault(); }; + const onChangeLabel = (event) => { + setLabel(event.target.value); + }; + const onChangeColor = (color) => { + setColor(color.hex); + }; + const validateTag = () => { + return label.length >= 1 && label.length <= 10; + }; + const newTag = () => { + if (tags.length >= 3) { + return; + } + if (validateTag()) { + const tag = { label, color }; + setTags([...tags, tag]); + } + }; + const delTag = (index: number) => { + setTags(tags.filter((_, i) => i !== index)); + }; return ( <> @@ -128,9 +188,47 @@ export default function Adapter(): JSX.Element { +
+ +
+
+ + +
+ + +
+
-