Skip to content

Commit

Permalink
feat: display the source of detection
Browse files Browse the repository at this point in the history
  • Loading branch information
kawamataryo committed Nov 24, 2024
1 parent 9364cc3 commit be53d28
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 66 deletions.
6 changes: 5 additions & 1 deletion src/lib/components/UserCard.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,16 @@ const demoUser: Props["user"] = {
Twitter: twitter.com/KawamataRyo
GitHub: github.com/kawamataryo
Zenn: zenn.dev/ryo_kawamata`,
avatar: "https://avatar.iran.liara.run/public",
avatar: "https://i.pravatar.cc/150?u=123",
matchType: BSKY_USER_MATCH_TYPE.HANDLE,
isFollowing: false,
followingUri: "",
isBlocking: false,
blockingUri: "",
originalAvatar: "https://i.pravatar.cc/150?u=123",
originalHandle: "kawamataryo",
originalDisplayName: "KawamataRyo",
originalProfileLink: "https://x.com/kawamataryo",
};

const mockAction: Props["clickAction"] = async () => {
Expand Down
167 changes: 115 additions & 52 deletions src/lib/components/UserCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,74 @@ import type { BskyUser } from "~types";
import { ACTION_MODE, MATCH_TYPE_LABEL_AND_COLOR } from "../constants";
import AvatarFallbackSvg from "./Icons/AvatarFallbackSvg";

type UserProfileProps = {
avatar: string;
url: string;
};

const UserProfile = ({ avatar, url }: UserProfileProps) => (
<div className="avatar">
<div className="w-10 h-10 rounded-full border border-white">
<a href={url} target="_blank" rel="noreferrer">
{avatar ? <img src={avatar} alt="" /> : <AvatarFallbackSvg />}
</a>
</div>
</div>
);

type UserInfoProps = {
handle: string;
displayName: string;
url: string;
};

const UserInfo = ({ handle, displayName, url }: UserInfoProps) => (
<div>
<h2 className="card-title break-all text-[1.1rem] font-bold">
<a href={url} target="_blank" rel="noreferrer">
{displayName}
</a>
</h2>
<p className="w-fit break-all text-gray-500 dark:text-gray-400 text-sm">
<a href={url} target="_blank" rel="noreferrer" className="break-all">
@{handle}
</a>
</p>
</div>
);

type ActionButtonProps = {
loading: boolean;
actionBtnLabelAndClass: { label: string; class: string };
handleActionButtonClick: () => void;
setIsBtnHovered: (value: boolean) => void;
setIsJustClicked: (value: boolean) => void;
};

const ActionButton = ({
loading,
actionBtnLabelAndClass,
handleActionButtonClick,
setIsBtnHovered,
setIsJustClicked,
}: ActionButtonProps) => (
<button
type="button"
className={`btn btn-sm rounded-3xl ${
loading ? "" : actionBtnLabelAndClass.class
}`}
onClick={handleActionButtonClick}
onMouseEnter={() => setIsBtnHovered(true)}
onMouseLeave={() => {
setIsBtnHovered(false);
setIsJustClicked(false);
}}
disabled={loading}
>
{loading ? "Processing..." : actionBtnLabelAndClass.label}
</button>
);

export type Props = {
user: BskyUser;
actionMode: (typeof ACTION_MODE)[keyof typeof ACTION_MODE];
Expand Down Expand Up @@ -82,67 +150,62 @@ const UserCard = ({ user, actionMode, clickAction }: Props) => {
};

return (
<div className="bg-base-100 w-full relative">
<div className="bg-base-100 w-full relative grid grid-cols-[20%_5%_75%]">
<div
className={`border-l-8 border-${
MATCH_TYPE_LABEL_AND_COLOR[user.matchType].color
} card-body relative py-3 px-4 rounded-sm grid grid-cols-[70px_1fr]`}
} card-body relative py-3 pl-4 pr-1 rounded-sm grid grid-cols-[50px_1fr]`}
>
<div>
<div className="avatar">
<div className="w-14 rounded-full border border-white ">
<a
href={`https://bsky.app/profile/${user.handle}`}
target="_blank"
rel="noreferrer"
>
{user.avatar ? (
<img src={user.avatar} alt="" />
) : (
<AvatarFallbackSvg />
)}
</a>
</div>
<UserProfile
avatar={user.originalAvatar}
url={user.originalProfileLink}
/>
<div className="flex flex-col gap-2">
<div className="flex justify-between items-center gap-2">
<UserInfo
handle={user.originalHandle}
displayName={user.originalDisplayName}
url={user.originalProfileLink}
/>
</div>
</div>
</div>
<div className="flex items-center justify-center">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="h-7 w-7"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="m5.25 4.5 7.5 7.5-7.5 7.5m6-15 7.5 7.5-7.5 7.5"
/>
</svg>
</div>
<div className="card-body relative py-3 pl-0 pr-2 rounded-sm grid grid-cols-[50px_1fr]">
<UserProfile
avatar={user.avatar}
url={`https://bsky.app/profile/${user.handle}`}
/>
<div className="flex flex-col gap-2">
<div className="flex justify-between items-center gap-2">
<div>
<h2 className="card-title break-all">
<a
href={`https://bsky.app/profile/${user.handle}`}
target="_blank"
rel="noreferrer"
>
{user.displayName}
</a>
</h2>
<p className="whitespace-nowrap w-fit break-all text-gray-500 dark:text-gray-400 text-sm">
<a
href={`https://bsky.app/profile/${user.handle}`}
target="_blank"
rel="noreferrer"
>
@{user.handle}
</a>
</p>
</div>
<UserInfo
handle={user.handle}
displayName={user.displayName}
url={`https://bsky.app/profile/${user.handle}`}
/>
<div className="card-actions">
<button
type="button"
className={`btn btn-sm rounded-3xl ${
loading ? "" : actionBtnLabelAndClass.class
}`}
onClick={handleActionButtonClick}
onMouseEnter={() => setIsBtnHovered(true)}
onMouseLeave={() => {
setIsBtnHovered(false);
setIsJustClicked(false);
}}
disabled={loading}
>
{loading ? "Processing..." : actionBtnLabelAndClass.label}
</button>
<ActionButton
loading={loading}
actionBtnLabelAndClass={actionBtnLabelAndClass}
handleActionButtonClick={handleActionButtonClick}
setIsBtnHovered={setIsBtnHovered}
setIsJustClicked={setIsJustClicked}
/>
</div>
</div>
<p className="text-sm break-all">{user.description}</p>
Expand Down
4 changes: 4 additions & 0 deletions src/lib/hooks/useRetrieveBskyUsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ export const useRetrieveBskyUsers = () => {
followingUri: searchResult.bskyProfile.viewer?.following,
isBlocking: !!searchResult.bskyProfile.viewer?.blocking,
blockingUri: searchResult.bskyProfile.viewer?.blocking,
originalAvatar: userData.originalAvatar,
originalHandle: userData.accountName,
originalDisplayName: userData.displayName,
originalProfileLink: userData.originalProfileLink,
},
];
});
Expand Down
6 changes: 6 additions & 0 deletions src/lib/services/xService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,19 @@ export class XService extends AbstractService {
?.match(/bsky\.app\/profile\/([^/\s]+)…?/)?.[1]
?.replace("…", "") ??
"";
const originalAvatar = userCell
.querySelector('[data-testid^="UserAvatar-Container"]')
?.querySelector("img")
?.getAttribute("src");

return {
accountName,
displayName,
accountNameRemoveUnderscore,
accountNameReplaceUnderscore,
bskyHandle,
originalAvatar,
originalProfileLink: `https://x.com/${accountName}`,
};
}

Expand Down
28 changes: 15 additions & 13 deletions src/options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,21 @@ const Option = () => {
matchTypeStats={matchTypeStats}
/>
</div>
<div className="flex-1 ml-80 p-6 overflow-y-auto">
<div className="flex flex-col gap-6">
<div className="flex flex-col gap-4">
<div className="divide-y divide-gray-500">
{filteredUsers.map((user) => (
<UserCard
key={user.handle}
user={user}
clickAction={handleClickAction}
actionMode={actionMode}
/>
))}
</div>
<div className="flex-1 ml-80 p-6 pt-0 overflow-y-auto">
<div className="grid grid-cols-[25%_75%] sticky top-0 z-10 bg-base-100 border-b-[1px] border-gray-500">
<h2 className="text-lg font-bold text-center py-2">Source</h2>
<h2 className="text-lg font-bold text-center py-2">Detected</h2>
</div>
<div className="flex flex-col gap-4">
<div className="divide-y divide-gray-500">
{filteredUsers.map((user) => (
<UserCard
key={user.handle}
user={user}
clickAction={handleClickAction}
actionMode={actionMode}
/>
))}
</div>
</div>
</div>
Expand Down
6 changes: 6 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ export type BskyUser = {
followingUri: string | null;
isBlocking: boolean;
blockingUri: string | null;
originalAvatar: string;
originalHandle: string;
originalDisplayName: string;
originalProfileLink: string;
};

export type MatchTypeFilterValue = {
Expand All @@ -31,4 +35,6 @@ export type CrawledUserInfo = {
accountNameRemoveUnderscore: string;
accountNameReplaceUnderscore: string;
bskyHandle: string;
originalAvatar: string;
originalProfileLink: string;
};

0 comments on commit be53d28

Please sign in to comment.