🚀 implement batch search feature

This commit is contained in:
kawamataryo
2024-01-19 10:18:19 +09:00
parent b9c51dd758
commit e7852bcc9a
31 changed files with 20418 additions and 546 deletions

129
src/contents/App.tsx Normal file
View File

@@ -0,0 +1,129 @@
import type { PlasmoCSConfig } from "plasmo";
import React from "react";
import AlertError from "~lib/components/AlertError";
import AlertSuccess from "~lib/components/AlertSuccess";
import MatchTypeFilter from "~lib/components/MatchTypeFilter";
import Modal from "~lib/components/Modal";
import UserCard from "~lib/components/UserCard";
import UserCardSkeleton from "~lib/components/UserCardSkeleton";
import { MESSAGE_NAMES } from "~lib/constants";
import { useRetrieveBskyUsers } from "~lib/hooks/useRetrieveBskyUsers";
import cssText from "data-text:~style.content.css";
export const config: PlasmoCSConfig = {
matches: ["https://twitter.com/*", "https://x.com/*"],
all_frames: true,
};
export const getStyle = () => {
const style = document.createElement("style");
// patch for shadow dom
style.textContent = cssText.replaceAll(":root", ":host");
return style;
};
const App = () => {
const {
initialize,
modalRef,
users,
loading,
handleClickAction,
actionMode,
errorMessage,
restart,
isRateLimitError,
isSucceeded,
matchTypeFilter,
changeMatchTypeFilter,
filteredUsers,
} = useRetrieveBskyUsers();
React.useEffect(() => {
const messageHandler = (
message: {
name: (typeof MESSAGE_NAMES)[keyof typeof MESSAGE_NAMES];
body: {
userId: string;
password: string;
};
},
_sender: chrome.runtime.MessageSender,
sendResponse: (response?: Record<string, unknown>) => void,
) => {
if (Object.values(MESSAGE_NAMES).includes(message.name)) {
initialize({
identifier: message.body.userId,
password: message.body.password,
messageName: message.name,
})
.then(() => {
sendResponse({ hasError: false });
})
.catch((e) => {
console.error(e);
sendResponse({ hasError: true, message: e.toString() });
});
return true;
}
return false;
};
chrome.runtime.onMessage.addListener(messageHandler);
return () => {
chrome.runtime.onMessage.removeListener(messageHandler);
};
}, [initialize]);
return (
<>
<Modal anchorRef={modalRef}>
<div className="flex flex-col gap-6">
<div className="flex justify-between">
<h1 className="text-2xl font-bold">Find Bluesky Users</h1>
<div className="flex gap-3 items-center">
{loading && (
<p className="loading loading-spinner loading-md text-primary" />
)}
<p className="text-sm">Detected:</p>
<p className="font-bold text-xl">{users.length}</p>
</div>
</div>
<MatchTypeFilter
value={matchTypeFilter}
onChange={changeMatchTypeFilter}
/>
{isSucceeded && (
<AlertSuccess>
<span className="font-bold">{users.length}</span> Bluesky accounts
detected.
</AlertSuccess>
)}
{errorMessage && (
<AlertError retryAction={isRateLimitError ? restart : undefined}>
{errorMessage}
</AlertError>
)}
<div className="flex flex-col gap-4 overflow-scroll max-h-[60vh]">
{filteredUsers.length > 0 ? (
<div className="">
{filteredUsers.map((user) => (
<UserCard
key={user.handle}
user={user}
clickAction={handleClickAction}
actionMode={actionMode}
/>
))}
</div>
) : (
loading && <UserCardSkeleton />
)}
</div>
</div>
</Modal>
</>
);
};
export default App;

90
src/contents/content.ts Normal file
View File

@@ -0,0 +1,90 @@
// TODO: Remove this file. This is for legacy code.
// import type { PlasmoCSConfig } from "plasmo";
// import { BskyServiceWorkerClient } from "~lib/bskyServiceWorkerClient";
// import { MESSAGE_NAMES, VIEWER_STATE } from "~lib/constants";
// import { searchAndInsertBskyUsers } from "~lib/searchAndInsertBskyUsers";
// import { type BskyLoginParams } from "../lib/bskyClient";
// import "../style.content.legacy.css";
// export const config: PlasmoCSConfig = {
// matches: ["https://twitter.com/*", "https://x.com/*"],
// all_frames: true,
// };
// const searchAndShowBskyUsers = async ({
// identifier,
// password,
// messageName,
// }: BskyLoginParams & { messageName: string }) => {
// const agent = await BskyServiceWorkerClient.createAgent({
// identifier,
// password,
// });
// switch (messageName) {
// case MESSAGE_NAMES.SEARCH_BSKY_USER_ON_FOLLOW_PAGE:
// await searchAndInsertBskyUsers({
// agent,
// btnLabel: {
// add: "Follow",
// remove: "Unfollow",
// progressive: "Following",
// },
// statusKey: VIEWER_STATE.FOLLOWING,
// userCellQueryParam:
// '[data-testid="primaryColumn"] [data-testid="UserCell"]',
// addQuery: async (arg: string) => await agent.follow(arg),
// removeQuery: async (arg: string) => await agent.unfollow(arg),
// });
// break;
// case MESSAGE_NAMES.SEARCH_BSKY_USER_ON_LIST_MEMBERS_PAGE:
// await searchAndInsertBskyUsers({
// agent,
// btnLabel: {
// add: "Follow",
// remove: "Unfollow",
// progressive: "Following",
// },
// statusKey: VIEWER_STATE.FOLLOWING,
// userCellQueryParam:
// '[data-testid="cellInnerDiv"] [data-testid="UserCell"]',
// addQuery: async (arg: string) => await agent.follow(arg),
// removeQuery: async (arg: string) => await agent.unfollow(arg),
// });
// break;
// case MESSAGE_NAMES.SEARCH_BSKY_USER_ON_BLOCK_PAGE:
// // TODO: If already blocked, don't show blocking state. because blocking user can't find.
// await searchAndInsertBskyUsers({
// agent,
// btnLabel: {
// add: "Block",
// remove: "Unblock",
// progressive: "Blocking",
// },
// statusKey: VIEWER_STATE.BLOCKING,
// userCellQueryParam: '[data-testid="UserCell"]',
// addQuery: async (arg: string) => await agent.block(arg),
// removeQuery: async (arg: string) => await agent.unblock(arg),
// });
// break;
// }
// };
// chrome.runtime.onMessage.addListener((message, _, sendResponse) => {
// if (Object.values(MESSAGE_NAMES).includes(message.name)) {
// searchAndShowBskyUsers({
// identifier: message.body.userId,
// password: message.body.password,
// messageName: message.name,
// })
// .then(() => {
// sendResponse({ hasError: false });
// })
// .catch((e) => {
// console.error(e);
// sendResponse({ hasError: true, message: e.toString() });
// });
// return true;
// }
// return false;
// });