nonebot2/website/src/components/Adapter.tsx

271 lines
8.3 KiB
TypeScript
Raw Normal View History

2021-12-31 23:58:59 +08:00
import clsx from "clsx";
import React, { useRef, useState } from "react";
import { ChromePicker } from "react-color";
import { usePagination } from "react-use-pagination";
2021-12-29 13:33:36 +08:00
import adapters from "../../static/adapters.json";
2021-12-31 23:58:59 +08:00
import { Tag, useFilteredObjs } from "../libs/store";
2021-12-30 22:46:15 +08:00
import Card from "./Card";
2021-12-31 23:58:59 +08:00
import Modal from "./Modal";
import ModalAction from "./ModalAction";
import ModalContent from "./ModalContent";
import ModalTitle from "./ModalTitle";
import Paginate from "./Paginate";
2021-12-31 23:58:59 +08:00
import TagComponent from "./Tag";
export default function Adapter(): JSX.Element {
2021-12-31 23:58:59 +08:00
const [modalOpen, setModalOpen] = useState<boolean>(false);
const {
filter,
setFilter,
filteredObjs: filteredAdapters,
} = useFilteredObjs(adapters);
const props = usePagination({
totalItems: filteredAdapters.length,
initialPageSize: 10,
});
const { startIndex, endIndex } = props;
const currentAdapters = filteredAdapters.slice(startIndex, endIndex + 1);
2021-12-31 23:58:59 +08:00
const [form, setForm] = useState<{
name: string;
desc: string;
projectLink: string;
moduleName: string;
homepage: string;
}>({ name: "", desc: "", projectLink: "", moduleName: "", homepage: "" });
const ref = useRef<HTMLInputElement>(null);
const [tags, setTags] = useState<Tag[]>([]);
const [label, setLabel] = useState<string>("");
const [color, setColor] = useState<string>("#ea5252");
const onSubmit = () => {
setModalOpen(false);
const title = encodeURIComponent(`Adapter: ${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=Adapter`
);
};
const onChange = (event) => {
const target = event.target;
const value = target.type === "checkbox" ? target.checked : target.value;
const name = target.name;
setForm({
...form,
[name]: value,
});
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));
};
const insertTagType = (text: string) => {
setLabel(text + label);
ref.current.value = text + label;
};
return (
<>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mt-4 px-4">
<input
className="w-full px-4 py-2 border rounded-full bg-light-nonepress-100 dark:bg-dark-nonepress-100"
value={filter}
placeholder="搜索适配器"
onChange={(event) => setFilter(event.target.value)}
/>
2021-12-31 23:58:59 +08:00
<button
className="w-full rounded-lg bg-hero text-white"
onClick={() => setModalOpen(true)}
>
</button>
</div>
<div className="grid grid-cols-1 p-4">
<Paginate {...props} />
</div>
2021-12-30 22:46:15 +08:00
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 px-4">
{currentAdapters.map((adapter, index) => (
<Card key={index} {...adapter} />
))}
</div>
<div className="grid grid-cols-1 p-4">
<Paginate {...props} />
</div>
2021-12-31 23:58:59 +08:00
<Modal active={modalOpen} setActive={setModalOpen}>
<ModalTitle title={"适配器信息"} />
<ModalContent>
<form onSubmit={onSubmit}>
<div className="grid grid-cols-1 gap-4 p-4">
<label className="flex flex-wrap">
<span className="mr-2">:</span>
<input
type="text"
name="name"
maxLength={20}
className="px-2 flex-grow rounded bg-light-nonepress-200 dark:bg-dark-nonepress-200"
onChange={onChange}
/>
</label>
<label className="flex flex-wrap">
<span className="mr-2">:</span>
<input
type="text"
name="desc"
className="px-2 flex-grow rounded bg-light-nonepress-200 dark:bg-dark-nonepress-200"
onChange={onChange}
/>
</label>
<label className="flex flex-wrap">
<span className="mr-2">PyPI :</span>
<input
type="text"
name="projectLink"
className="px-2 flex-grow rounded bg-light-nonepress-200 dark:bg-dark-nonepress-200"
onChange={onChange}
/>
</label>
<label className="flex flex-wrap">
<span className="mr-2">import :</span>
<input
type="text"
name="moduleName"
className="px-2 flex-grow rounded bg-light-nonepress-200 dark:bg-dark-nonepress-200"
onChange={onChange}
/>
</label>
<label className="flex flex-wrap">
<span className="mr-2">/:</span>
<input
type="text"
name="homepage"
className="px-2 flex-grow rounded bg-light-nonepress-200 dark:bg-dark-nonepress-200"
onChange={onChange}
/>
</label>
</div>
</form>
<div className="px-4">
<label className="flex flex-wrap">
<span className="mr-2">:</span>
{tags.map((tag, index) => (
<TagComponent
key={index}
{...tag}
className="cursor-pointer"
onClick={() => delTag(index)}
/>
))}
</label>
</div>
<div className="px-4 pt-4">
<input
ref={ref}
type="text"
className="px-2 flex-grow rounded bg-light-nonepress-200 dark:bg-dark-nonepress-200"
onChange={onChangeLabel}
/>
<ChromePicker
className="mt-2"
color={color}
disableAlpha={true}
onChangeComplete={onChangeColor}
/>
<div className="flex flex-wrap mt-2 items-center">
<span className="mr-2">Type:</span>
<button
className="px-2 h-9 min-w-[64px] rounded text-hero hover:bg-hero hover:bg-opacity-[.08]"
onClick={() => insertTagType("a:")}
>
Adapter
</button>
<button
className="px-2 h-9 min-w-[64px] rounded text-hero hover:bg-hero hover:bg-opacity-[.08]"
onClick={() => insertTagType("t:")}
>
Topic
</button>
</div>
<div className="flex mt-2">
<TagComponent label={label} color={color} />
<button
className={clsx(
"px-2 h-9 min-w-[64px] rounded text-hero hover:bg-hero hover:bg-opacity-[.08]",
{ "pointer-events-none opacity-60": !validateTag() }
)}
onClick={newTag}
>
</button>
</div>
</div>
</ModalContent>
<ModalAction>
<button
className="px-2 h-9 min-w-[64px] rounded text-hero hover:bg-hero hover:bg-opacity-[.08]"
onClick={() => setModalOpen(false)}
>
</button>
<button
className="ml-2 px-2 h-9 min-w-[64px] rounded text-hero hover:bg-hero hover:bg-opacity-[.08]"
onClick={onSubmit}
>
</button>
</ModalAction>
</Modal>
</>
);
2021-12-29 13:33:36 +08:00
}