Skip to content

Commit

Permalink
Merge branch 'dev' into dj/mobile
Browse files Browse the repository at this point in the history
  • Loading branch information
daria-github authored Feb 28, 2024
2 parents 8a7f502 + 6c5543f commit 8b2bd3a
Show file tree
Hide file tree
Showing 6 changed files with 257 additions and 140 deletions.
56 changes: 33 additions & 23 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"@xmtp/content-type-remote-attachment": "^1.1.4",
"@xmtp/content-type-reply": "^1.1.5",
"@xmtp/experimental-content-type-screen-effect": "^1.0.2",
"@xmtp/frames-client": "0.3.2",
"@xmtp/frames-client": "0.4.2",
"@xmtp/react-sdk": "^5.0.1",
"buffer": "^6.0.3",
"date-fns": "^2.29.3",
Expand Down Expand Up @@ -77,6 +77,7 @@
},
"devDependencies": {
"@babel/core": "^7.20.12",
"@open-frames/proxy-client": "0.2.0",
"@storybook/addon-essentials": "^7.1.0-alpha.29",
"@storybook/addon-interactions": "^7.1.0-alpha.29",
"@storybook/addon-links": "^7.1.0-alpha.29",
Expand Down
151 changes: 130 additions & 21 deletions src/component-library/components/Frame/Frame.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,153 @@
import type { FrameButton } from "../../../helpers/getFrameInfo";
import { GhostButton } from "../GhostButton/GhostButton";
import { ArrowCircleRightIcon } from "@heroicons/react/outline";
import type { FrameButton } from "../../../helpers/frameInfo";
import { classNames } from "../../../helpers";
import { ButtonLoader } from "../Loaders/ButtonLoader";

type FrameProps = {
image: string;
title: string;
textInput?: string;
buttons: FrameButton[];
handleClick: (
buttonNumber: number,
action: FrameButton["action"],
action?: FrameButton["action"],
) => Promise<void>;
onTextInputChange: (value: string) => void;
frameButtonUpdating: number;
interactionsEnabled: boolean;
};

const FrameButtonContainer = ({
label,
isExternalLink,
isFullWidth,
isLoading,
isDisabled,
testId = "",
clickHandler,
}: {
testId?: string;
label: string;
isExternalLink: boolean;
isFullWidth: boolean;
isLoading: boolean;
isDisabled: boolean;
clickHandler: () => void;
}) => {
const columnWidth = isFullWidth ? "col-span-2" : "col-span-1";

const icon = isExternalLink ? <ArrowCircleRightIcon width={16} /> : null;
return (
<button
type="button"
onClick={clickHandler}
data-testid={testId}
disabled={isDisabled}
className={classNames(
columnWidth,
// Font color
"text-indigo-600 hover:text-indigo-800 focus:outline-none focus-visible:ring focus-visible:ring-indigo-800",
// Font size
"text-sm p-0",
// "font-bold",
// Min width
`min-w-[20%]`,
// Background
"white",
// Border settings
"border",
"box-border",
"border-b-100 hover:border-b-300",
"rounded-lg",
// Layout
"flex",
"items-center",
"justify-center",
"h-fit",
"p-2",
// Transition
"transition duration-150 ease-in-out", // Quick transition for hover state
)}
aria-label={label}>
<div className="flex justify-center items-center h-fit space-x-2">
<div>{label}</div>
{isLoading ? <ButtonLoader color="primary" size="small" /> : icon}
</div>
</button>
);
};

const ButtonsContainer = ({
frameButtonUpdating,
buttons,
handleClick,
}: Pick<FrameProps, "frameButtonUpdating" | "buttons" | "handleClick">) => {
if (buttons.length < 1 || buttons.length > 4) {
return null;
}
// If there is only one button make it full-width
const gridColumns = buttons.length === 1 ? "grid-cols-1" : "grid-cols-2";
return (
<div className={`grid ${gridColumns} gap-2 w-full pt-2`}>
{buttons.map((button, index) => {
const clickHandler = () => {
void handleClick(button.buttonIndex, button.action);
};
const isFullWidth = buttons.length === 3 && index === 2;
return (
<FrameButtonContainer
key={button.label}
isFullWidth={isFullWidth}
label={button.label}
isExternalLink={["post_redirect", "link"].includes(
button.action || "",
)}
isLoading={frameButtonUpdating === button.buttonIndex}
isDisabled={frameButtonUpdating > 0}
clickHandler={clickHandler}
/>
);
})}
</div>
);
};

export const Frame = ({
image,
title,
buttons,
textInput,
handleClick,
onTextInputChange,
frameButtonUpdating,
interactionsEnabled,
}: FrameProps) => (
<div className="px-4 md:px-8">
<div className="px-4 md:px-8 p-1">
<img src={image} className="max-h-80 rounded-lg" alt={title} />
<div className="flex flex-col items-center">
{buttons?.map((button, index) => {
if (!button) {
return null;
{!!textInput && interactionsEnabled && (
<input
type="text"
className="w-full mt-4 mb-4 h-10 px-3 border rounded-md"
spellCheck="false"
autoComplete="off"
autoCorrect="off"
autoCapitalize="off"
onChange={(e) =>
onTextInputChange((e.target as HTMLInputElement).value)
}
const handlePress = () => {
void handleClick(index + 1, button.action);
};
return (
<GhostButton
key={button.text}
label={button.text}
onClick={handlePress}
isLoading={frameButtonUpdating === index + 1}
isDisabled={frameButtonUpdating > 0}
/>
);
})}
placeholder={textInput}
/>
)}
<div className="flex flex-col items-center">
{interactionsEnabled && buttons.length ? (
<ButtonsContainer
frameButtonUpdating={frameButtonUpdating}
handleClick={handleClick}
buttons={buttons}
/>
) : (
<span>Frame interactions not supported</span>
)}
</div>
</div>
);
Loading

0 comments on commit 8b2bd3a

Please sign in to comment.