mirror of
https://github.com/snachodog/tok-to-insta-follower-bridge.git
synced 2025-04-10 14:11:22 -06:00
feat: add delete button
chore: fix design
This commit is contained in:
parent
dd8ce838b6
commit
5efee32eea
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sky-follower-bridge",
|
"name": "sky-follower-bridge",
|
||||||
"displayName": "__MSG_extension_name__",
|
"displayName": "Sky Follower Bridge",
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"description": "__MSG_extension_description__",
|
"description": "__MSG_extension_description__",
|
||||||
"author": "kawamataryou",
|
"author": "kawamataryou",
|
||||||
|
@ -14,6 +14,7 @@ export type Props = {
|
|||||||
accountName: string;
|
accountName: string;
|
||||||
displayName: string;
|
displayName: string;
|
||||||
}) => Promise<void>;
|
}) => Promise<void>;
|
||||||
|
deleteUser: (did: string) => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DetectedUserListItem = ({
|
const DetectedUserListItem = ({
|
||||||
@ -21,6 +22,7 @@ const DetectedUserListItem = ({
|
|||||||
actionMode,
|
actionMode,
|
||||||
clickAction,
|
clickAction,
|
||||||
reSearch,
|
reSearch,
|
||||||
|
deleteUser,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const [isBtnHovered, setIsBtnHovered] = React.useState(false);
|
const [isBtnHovered, setIsBtnHovered] = React.useState(false);
|
||||||
const [isJustClicked, setIsJustClicked] = React.useState(false);
|
const [isJustClicked, setIsJustClicked] = React.useState(false);
|
||||||
@ -100,6 +102,10 @@ const DetectedUserListItem = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDeleteClick = () => {
|
||||||
|
deleteUser(user.did);
|
||||||
|
};
|
||||||
|
|
||||||
const matchTypeColor = MATCH_TYPE_LABEL_AND_COLOR[user.matchType].color;
|
const matchTypeColor = MATCH_TYPE_LABEL_AND_COLOR[user.matchType].color;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -123,6 +129,7 @@ const DetectedUserListItem = ({
|
|||||||
setIsBtnHovered={setIsBtnHovered}
|
setIsBtnHovered={setIsBtnHovered}
|
||||||
setIsJustClicked={setIsJustClicked}
|
setIsJustClicked={setIsJustClicked}
|
||||||
handleReSearchClick={handleReSearchClick}
|
handleReSearchClick={handleReSearchClick}
|
||||||
|
handleDeleteClick={handleDeleteClick}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,14 +4,33 @@ import ActionButton from "./ActionButton";
|
|||||||
import UserInfo from "./UserInfo";
|
import UserInfo from "./UserInfo";
|
||||||
import UserProfile from "./UserProfile";
|
import UserProfile from "./UserProfile";
|
||||||
|
|
||||||
export type UserCardProps = {
|
const DeleteButton = ({
|
||||||
user: Pick<BskyUser, "avatar" | "handle" | "displayName" | "description">;
|
onClick,
|
||||||
loading: boolean;
|
}: {
|
||||||
actionBtnLabelAndClass: { label: string; class: string };
|
onClick: () => void;
|
||||||
handleActionButtonClick: () => void;
|
}) => {
|
||||||
setIsBtnHovered: (value: boolean) => void;
|
return (
|
||||||
setIsJustClicked: (value: boolean) => void;
|
<button
|
||||||
handleReSearchClick: () => void;
|
type="button"
|
||||||
|
className="btn-outline w-7 h-7 border rounded-full flex items-center justify-center"
|
||||||
|
onClick={onClick}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
strokeWidth={1.5}
|
||||||
|
stroke="currentColor"
|
||||||
|
className="h-4 w-4"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
d="M6 18L18 6M6 6l12 12"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const ReSearchButton = ({
|
const ReSearchButton = ({
|
||||||
@ -43,6 +62,17 @@ const ReSearchButton = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type UserCardProps = {
|
||||||
|
user: Pick<BskyUser, "avatar" | "handle" | "displayName" | "description">;
|
||||||
|
loading: boolean;
|
||||||
|
actionBtnLabelAndClass: { label: string; class: string };
|
||||||
|
handleActionButtonClick: () => void;
|
||||||
|
setIsBtnHovered: (value: boolean) => void;
|
||||||
|
setIsJustClicked: (value: boolean) => void;
|
||||||
|
handleReSearchClick: () => void;
|
||||||
|
handleDeleteClick: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
const UserCard = ({
|
const UserCard = ({
|
||||||
user,
|
user,
|
||||||
loading,
|
loading,
|
||||||
@ -51,6 +81,7 @@ const UserCard = ({
|
|||||||
setIsBtnHovered,
|
setIsBtnHovered,
|
||||||
setIsJustClicked,
|
setIsJustClicked,
|
||||||
handleReSearchClick,
|
handleReSearchClick,
|
||||||
|
handleDeleteClick = () => {},
|
||||||
}: UserCardProps) => {
|
}: UserCardProps) => {
|
||||||
return (
|
return (
|
||||||
<div className="relative py-3 pt-1 pl-0 pr-2 grid grid-cols-[50px_1fr]">
|
<div className="relative py-3 pt-1 pl-0 pr-2 grid grid-cols-[50px_1fr]">
|
||||||
@ -59,23 +90,28 @@ const UserCard = ({
|
|||||||
url={`https://bsky.app/profile/${user.handle}`}
|
url={`https://bsky.app/profile/${user.handle}`}
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<div className="flex justify-between items-center gap-2">
|
<div className="flex justify-between items-start gap-2">
|
||||||
<div className="flex items-start gap-4">
|
<div className="flex items-start gap-4">
|
||||||
<UserInfo
|
<UserInfo
|
||||||
handle={user.handle}
|
handle={user.handle}
|
||||||
displayName={user.displayName}
|
displayName={user.displayName}
|
||||||
url={`https://bsky.app/profile/${user.handle}`}
|
url={`https://bsky.app/profile/${user.handle}`}
|
||||||
/>
|
/>
|
||||||
<ReSearchButton onClick={handleReSearchClick} />
|
|
||||||
</div>
|
</div>
|
||||||
<div className="card-actions flex items-center gap-4">
|
<div className="card-actions flex items-center gap-6">
|
||||||
<ActionButton
|
<div className="flex items-center gap-2">
|
||||||
loading={loading}
|
<ReSearchButton onClick={handleReSearchClick} />
|
||||||
actionBtnLabelAndClass={actionBtnLabelAndClass}
|
<DeleteButton onClick={handleDeleteClick} />
|
||||||
handleActionButtonClick={handleActionButtonClick}
|
</div>
|
||||||
setIsBtnHovered={setIsBtnHovered}
|
<div className="w-[170px]">
|
||||||
setIsJustClicked={setIsJustClicked}
|
<ActionButton
|
||||||
/>
|
loading={loading}
|
||||||
|
actionBtnLabelAndClass={actionBtnLabelAndClass}
|
||||||
|
handleActionButtonClick={handleActionButtonClick}
|
||||||
|
setIsBtnHovered={setIsBtnHovered}
|
||||||
|
setIsJustClicked={setIsJustClicked}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm break-all">{user.description}</p>
|
<p className="text-sm break-all">{user.description}</p>
|
||||||
|
@ -271,6 +271,13 @@ export const useBskyUserManager = () => {
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const deleteUser = React.useCallback(
|
||||||
|
async (did: string) => {
|
||||||
|
await setUsers((prev) => prev.filter((user) => user.did !== did));
|
||||||
|
},
|
||||||
|
[setUsers],
|
||||||
|
);
|
||||||
|
|
||||||
const changeDetectedUser = React.useCallback(
|
const changeDetectedUser = React.useCallback(
|
||||||
(fromDid: string, toUser: ProfileView) => {
|
(fromDid: string, toUser: ProfileView) => {
|
||||||
setUsers((prev) =>
|
setUsers((prev) =>
|
||||||
@ -305,5 +312,6 @@ export const useBskyUserManager = () => {
|
|||||||
reSearchResults,
|
reSearchResults,
|
||||||
changeDetectedUser,
|
changeDetectedUser,
|
||||||
clearReSearchResults,
|
clearReSearchResults,
|
||||||
|
deleteUser,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -5,6 +5,7 @@ import useConfirm from "~lib/components/ConfirmDialog";
|
|||||||
import Sidebar from "~lib/components/Sidebar";
|
import Sidebar from "~lib/components/Sidebar";
|
||||||
import "react-toastify/dist/ReactToastify.css";
|
import "react-toastify/dist/ReactToastify.css";
|
||||||
import type { ProfileView } from "@atproto/api/dist/client/types/app/bsky/actor/defs";
|
import type { ProfileView } from "@atproto/api/dist/client/types/app/bsky/actor/defs";
|
||||||
|
import { AnimatePresence, motion } from "framer-motion";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ReSearchModal from "~components/ReSearchModal";
|
import ReSearchModal from "~components/ReSearchModal";
|
||||||
import DetectedUserListItem from "~lib/components/DetectedUserListItem";
|
import DetectedUserListItem from "~lib/components/DetectedUserListItem";
|
||||||
@ -26,6 +27,7 @@ const Option = () => {
|
|||||||
reSearchResults,
|
reSearchResults,
|
||||||
changeDetectedUser,
|
changeDetectedUser,
|
||||||
clearReSearchResults,
|
clearReSearchResults,
|
||||||
|
deleteUser,
|
||||||
} = useBskyUserManager();
|
} = useBskyUserManager();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -175,15 +177,27 @@ const Option = () => {
|
|||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col border-b-[1px] border-gray-500">
|
<div className="flex flex-col border-b-[1px] border-gray-500">
|
||||||
{filteredUsers.map((user) => (
|
<AnimatePresence>
|
||||||
<DetectedUserListItem
|
{filteredUsers.map((user) => (
|
||||||
key={user.handle}
|
<motion.div
|
||||||
user={user}
|
key={user.did}
|
||||||
clickAction={handleClickAction}
|
layout
|
||||||
actionMode={actionMode}
|
initial={{ opacity: 0 }}
|
||||||
reSearch={handleReSearch}
|
animate={{ opacity: 1 }}
|
||||||
/>
|
exit={{ opacity: 0 }}
|
||||||
))}
|
transition={{ duration: 0.3 }}
|
||||||
|
>
|
||||||
|
<DetectedUserListItem
|
||||||
|
key={user.handle}
|
||||||
|
user={user}
|
||||||
|
clickAction={handleClickAction}
|
||||||
|
actionMode={actionMode}
|
||||||
|
reSearch={handleReSearch}
|
||||||
|
deleteUser={deleteUser}
|
||||||
|
/>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</AnimatePresence>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="fixed bottom-5 right-5">
|
<div className="fixed bottom-5 right-5">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user