Skip to content

Commit

Permalink
feat: connect button wip
Browse files Browse the repository at this point in the history
  • Loading branch information
martonlederer committed Jan 8, 2023
1 parent dd2da96 commit 547fb99
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 30 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ With the `theme` field, you can define a custom theme configuration for the ArCo
| ---- | ---- | - |
| `displayTheme` | `"dark"`, `"light"` | UI display theme to use |
| `accent` | `RGBObject` | RGB accent color for the UI |
| `titleHighlight` | `RGBObject` | RGB accent color for the subscreen titles (like the connection screen) |
| `radius` | `"default"`, `"minimal"`, `"none"` | Border radius level used throughout the Kit UI |

## Terminology of ArConnect Kit
Expand Down
111 changes: 111 additions & 0 deletions src/components/ConnectButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { ChevronDownIcon } from "@iconicicons/react";
import useAddress from "../hooks/active_address";
import useConnection from "../hooks/connection";
import useBalance from "../hooks/balance";
import { formatAddress } from "../utils";
import type { Radius } from "./Provider";
import type { HTMLProps } from "react";
import styled from "styled-components";
import { Button } from "./Button";

export default function ConnectButton({ accent, onClick, ...props }: HTMLProps<HTMLButtonElement> & Props) {
// connection
const {
connected,
connect,
disconnect
} = useConnection();

// active address
const address = useAddress();

// balance
const balance = useBalance();

return (
<Wrapper
accent={accent}
onClick={async (e) => {
if (!connected) await connect();
else await disconnect();

if (onClick) return onClick(e);
}}
{...props as any}
>
{(connected && (
<>
<Balance>
{balance.toLocaleString(undefined, { maximumFractionDigits: 2 }) + " AR"}
</Balance>
<ProfileSection>
<Avatar src="https://arweave.net/mzv2LMPSpoYcCPNtfq-IvB5pgnfk2k4_5XCCBefkZ_A" />
{formatAddress(address || "", 5)}
<ExpandIcon />
</ProfileSection>
</>
)) || (
<ConnectText>
Connect Wallet
</ConnectText>
)}
</Wrapper>
);
}

const radius: Record<Radius, number> = {
default: 18,
minimal: 10,
none: 0
};

const Wrapper = styled(Button)<{ accent?: string; }>`
border-radius: ${props => radius[props.theme.themeConfig.radius] + "px"};
text-transform: none;
padding: 0.3rem;
background-color: ${(props) => props.accent || `rgb(${props.theme.theme})`};
`;

const ConnectText = styled.span`
line-height: 2.6rem;
padding: 0 .9rem;
`;

const ProfileSection = styled.div`
display: flex;
align-items: center;
background-color: rgb(${props => props.theme.background}, .2);
height: 2.6rem;
border-radius: ${props => radius[props.theme.themeConfig.radius] - 3 + "px"};
padding: 0 .3rem 0 .6rem;
gap: .25rem;
`;

const Balance = styled.span`
padding: 0 .5rem;
`;

const ExpandIcon = styled(ChevronDownIcon)`
font-size: 1.5rem !important;
`;

const avatarRadius: Record<Radius, string> = {
default: "100%",
minimal: "5px",
none: "0px"
};

const Avatar = styled.img.attrs({
draggable: false
})`
user-select: none;
border-radius: ${props => avatarRadius[props.theme.themeConfig.radius]};
object-fit: cover;
width: 1.7rem;
height: 1.7rem;
margin-right: .4rem;
`;

interface Props {
accent?: string;
}
21 changes: 15 additions & 6 deletions src/components/Provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { ProfileModal } from "../modals/Profile";
import type { DisplayTheme } from "../vite-env";
import type { Config } from "../context/faces";
import globalReducer from "../context/reducer";
import { rgbToString } from "../utils";
import { Helmet } from "react-helmet";

export function ArConnectKit({
Expand Down Expand Up @@ -43,7 +44,7 @@ export function ArConnectKit({
theme={{
...(themeConfig.displayTheme === "light" ? lightTheme : darkTheme),
displayTheme: themeConfig.displayTheme || "light",
theme: `${themeConfig.accent.r}, ${themeConfig.accent.g}, ${themeConfig.accent.b}`,
theme: rgbToString(themeConfig.accent),
themeConfig
}}
>
Expand Down Expand Up @@ -83,6 +84,11 @@ const defaultTheme: ThemeConfig = {
g: 0,
b: 0
},
titleHighlight: {
r: 0,
g: 122,
b: 255
},
radius: "default"
};

Expand Down Expand Up @@ -112,12 +118,15 @@ interface Props {

export interface ThemeConfig {
displayTheme: "dark" | "light";
accent: {
r: number;
g: number;
b: number;
};
accent: RGBObject;
titleHighlight: RGBObject;
radius: Radius;
}

export interface RGBObject {
r: number;
g: number;
b: number;
}

export type Radius = "default" | "minimal" | "none";
9 changes: 8 additions & 1 deletion src/components/Title.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { rgbToString } from "../utils";
import styled from "styled-components";

export const Title = styled.h1<{ small?: boolean; themed?: boolean }>`
Expand All @@ -6,7 +7,13 @@ export const Title = styled.h1<{ small?: boolean; themed?: boolean }>`
font-size: ${(props) => (props.small ? "1.05rem" : "1.2rem")};
font-weight: 600;
color: rgb(
${(props) => (props.themed ? "0, 122, 255" : props.theme.primaryText)}
${props => {
if (!props.themed) {
return props.theme.primaryText;
}
return rgbToString(props.theme.themeConfig.titleHighlight);
}}
);
cursor: ${(props) => (props.themed ? "pointer" : "text")};
align-items: center;
Expand Down
33 changes: 33 additions & 0 deletions src/hooks/balance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useEffect, useState } from "react";
import Arweave from "arweave/node/common";
import useGlobalState from "./global";

/**
* Balance hook
*/
export default function useBalance() {
const [balance, setBalance] = useState(0);
const { state } = useGlobalState();

useEffect(() => {
(async () => {
if (!state.activeAddress) return;

const arweave = new Arweave(
state?.config?.gatewayConfig || {
host: "arweave.net",
port: 443,
protocol: "https"
}
);

const bal = arweave.ar.winstonToAr(
await arweave.wallets.getBalance(state.activeAddress)
);

setBalance(Number(bal));
})();
}, [state?.activeAddress]);

return balance;
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { default as useAddresses, useWalletNames } from "./hooks/addresses";
export { default as ConnectButton } from "./components/ConnectButton";
export { default as usePermissions } from "./hooks/permissions";
export { default as useConnection } from "./hooks/connection";
export { default as useProfileModal } from "./hooks/profile";
Expand Down
26 changes: 3 additions & 23 deletions src/modals/Profile.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { CopyIcon, LogOutIcon, UserIcon } from "@iconicicons/react";
import type { Radius } from "../components/Provider";
import { Paragraph } from "../components/Paragraph";
import { Modal } from "../components/Modal/Modal";
import useConnection from "../hooks/connection";
Expand All @@ -8,11 +9,10 @@ import useGlobalState from "../hooks/global";
import useGatewayURL from "../hooks/gateway";
import { useEffect, useState } from "react";
import { Title } from "../components/Title";
import useBalance from "../hooks/balance";
import { formatAddress } from "../utils";
import styled from "styled-components";
import useModal from "../hooks/modal";
import Arweave from "arweave";
import type { Radius } from "../components/Provider"

export function ProfileModal() {
// modal controlls and statuses
Expand All @@ -33,27 +33,7 @@ export function ProfileModal() {
}

// load balance
const [balance, setBalance] = useState(0);

useEffect(() => {
(async () => {
if (!state.activeAddress) return;

const arweave = new Arweave(
state?.config?.gatewayConfig || {
host: "arweave.net",
port: 443,
protocol: "https"
}
);

const bal = arweave.ar.winstonToAr(
await arweave.wallets.getBalance(state.activeAddress)
);

setBalance(Number(bal));
})();
}, [state?.activeAddress]);
const balance = useBalance();

// load ans profile
const [ans, setAns] = useState<AnsProfile>();
Expand Down
16 changes: 16 additions & 0 deletions src/stories/ConnectButton.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import ConnectButton from "../components/ConnectButton";
import { ArConnectKit } from "../components/Provider";
import { rgbToString } from "../utils";

export default {
name: "ConnectButton",
component: ConnectButton
};

export const Basic = () => (
<ArConnectKit>
<ConnectButton
accent={"rgb(0, 122, 255)"}
/>
</ArConnectKit>
);
3 changes: 3 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { RGBObject } from "./components/Provider";
import type { PermissionType } from "arconnect";

/**
Expand Down Expand Up @@ -31,3 +32,5 @@ export function formatAddress(address: string, count = 13) {
address.substring(address.length - count, address.length)
);
}

export const rgbToString = (rgb: RGBObject) => `${rgb.r}, ${rgb.g}, ${rgb.b}`;

0 comments on commit 547fb99

Please sign in to comment.