Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions packages/widget/src/components/atoms/image/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { HTMLProps } from "react";
import { useMemo } from "react";
import { getBackgroundColor } from "../../../utils";
import type { BoxProps } from "../box";
import { Box } from "../box";

Expand Down Expand Up @@ -53,9 +52,8 @@ const createMonogramImageSrc = (name?: string) => {
if (!firstCharacter) return undefined;

const initial = escapeForSvg(firstCharacter.toUpperCase());
const backgroundColor = getBackgroundColor(name);

const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100"><circle cx="50" cy="50" r="50" fill="${backgroundColor}" /><text x="50" y="50" fill="#FFFFFF" font-family="Arial, sans-serif" font-size="48" font-weight="700" text-anchor="middle" dominant-baseline="central">${initial}</text></svg>`;
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100"><circle cx="50" cy="50" r="49" fill="#FFFFFF" stroke="rgba(0,0,0,0.08)" stroke-width="2" /><text x="50" y="50" fill="#000000" font-family="Arial, sans-serif" font-size="48" font-weight="700" text-anchor="middle" dominant-baseline="central">${initial}</text></svg>`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, with this we have white fallbacks on white background. why not color backgrounds?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's the shared monogram used standalone in token/provider/validator icons (no container behind them), so the white circle's needed there. The badge just reuses it now.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here is with this change - is this expected? @sandy-yield

Image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Yes, those are expected. If we don't have the image, it shows the initial letter of the coin.


return `data:image/svg+xml;charset=UTF-8,${encodeURIComponent(svg)}`;
};
Expand Down
1 change: 1 addition & 0 deletions packages/widget/src/components/atoms/token-icon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const TokenIcon = ({
{!hideNetwork && !hideNetworkLogo && (
<NetworkLogoImage
networkLogoUri={networkLogoUri}
networkName={token.network}
tokenNetworkLogoHw={tokenNetworkLogoHw}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@ import { logoContainer, logoImage } from "./style.css";

type NetworkLogoImageProps = {
networkLogoUri: string;
networkName?: string;
tokenNetworkLogoHw?: Atoms["hw"];
};

export const NetworkLogoImage = ({
networkLogoUri,
networkName,
tokenNetworkLogoHw = "3",
}: NetworkLogoImageProps) => (
<Box className={logoContainer} data-rk="token-network-logo">
<Image
src={networkLogoUri}
fallbackName={networkName}
wrapperProps={{ hw: tokenNetworkLogoHw }}
imgProps={{ hw: tokenNetworkLogoHw, className: logoImage }}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import { style } from "@vanilla-extract/css";

export const logoContainer = style({
const baseContainer = style({
position: "absolute",
bottom: -2,
right: -2,
borderRadius: "50%",
padding: "4px",
backgroundColor: "rgba(37,37,37, 0.95)",
padding: "3px",
display: "flex",
alignItems: "center",
justifyContent: "center",
});

export const logoContainer = style([
baseContainer,
{
backgroundColor: "#ffffff",
boxShadow: "0 0 0 1px rgba(0, 0, 0, 0.06)",
},
]);

export const logoImage = style({
maxWidth: "100%",
height: "auto",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const ProviderIcon = ({
{!hideNetwork && !hideNetworkLogo && (
<NetworkLogoImage
networkLogoUri={mainUrl || networkLogoUri}
networkName={token.network}
tokenNetworkLogoHw={tokenNetworkLogoHw}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { ComponentProps } from "react";
import { Trans } from "react-i18next";
import type { YieldPendingActionType } from "../../../domain/types/pending-action";
import type { useRewardTokenDetails } from "../../../hooks/use-reward-token-details";
import { humanizePendingActionType } from "../../../utils/formatters";
import { Box } from "../../atoms/box";
import { MorphoStarsIcon } from "../../atoms/icons/morpho-stars";
import { Image } from "../../atoms/image";
Expand Down Expand Up @@ -35,6 +36,11 @@ export const RewardTokenDetails = ({
return "unstake_review.unstake_from";
})();

const i18nDefaults =
rest.type === "pendingAction"
? humanizePendingActionType(rest.pendingAction)
: undefined;

return rewardToken
.map((rt) => {
return (
Expand Down Expand Up @@ -66,6 +72,7 @@ export const RewardTokenDetails = ({
<Text variant={{ weight: "semibold" }}>
<Trans
i18nKey={i18nKey}
defaults={i18nDefaults}
values={{ providerName: rt.providerName }}
components={{
symbols1: (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from "../../../pages/position-details/components/amount-block";
import { StaticActionBlock } from "../../../pages/position-details/components/static-action-block";
import { usePositionDetails } from "../../../pages/position-details/hooks/use-position-details";
import { humanizePendingActionType } from "../../../utils/formatters";
import { PositionDetailsActionTabs } from "./position-details-action-tabs";
import { container } from "./styles.css";

Expand Down Expand Up @@ -170,7 +171,12 @@ export const PositionDetailsActions = () => {
label={t(
`position_details.pending_action_button.${
val.pendingActionDto.type.toLowerCase() as Lowercase<YieldPendingActionType>
}`
}`,
{
defaultValue: humanizePendingActionType(
val.pendingActionDto.type
),
}
)}
onMaxClick={null}
formattedAmount={val.formattedAmount}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -419,13 +419,7 @@ const getStatusSummary = ({
pendingAction.pendingActionDto.type === "CLAIM_REWARDS"
? "claim"
: "action",
value: t(
`position_details.pending_action.${
pendingAction.pendingActionDto.type.toLowerCase() as Lowercase<
YieldPendingActionDto["type"]
>
}`
),
value: formatPendingActionLabel(pendingAction.pendingActionDto.type, t),
};
}

Expand Down Expand Up @@ -635,6 +629,17 @@ const balanceTypePriority: YieldBalanceType[] = [
const formatBalanceTypeLabel = (type: YieldBalanceType, t: TFunction) =>
t(`position_details.balance_type.${type}`);

// Pending action types come from the API and can outpace our translation map
// (e.g. RWA-specific actions). Fall back to a humanized version of the type so
// the card never renders a raw translation key.
const formatPendingActionLabel = (
type: YieldPendingActionDto["type"],
t: TFunction
) =>
t(`position_details.pending_action.${type.toLowerCase()}`, {
defaultValue: formatEnumValue(type),
});

const formatUsdSubValue = (
value: string | number | BigNumber | null | undefined
) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {
import type { YieldBalanceDto } from "../../../domain/types/positions";
import { isEthenaUsdeStaking, type Yield } from "../../../domain/types/yields";
import { defaultFormattedNumber } from "../../../utils";
import { humanizePendingActionType } from "../../../utils/formatters";
import type { usePositionDetails } from "../hooks/use-position-details";

type StaticActionBlockProps = {
Expand Down Expand Up @@ -60,6 +61,9 @@ export const StaticActionBlock = ({
context: isEthenaUsdeStaking(yieldId)
? "ethena_usde"
: undefined,
defaultValue: humanizePendingActionType(
pendingActionDto.type
),
}
),
}}
Expand Down Expand Up @@ -93,7 +97,10 @@ export const StaticActionBlock = ({
{t(
`position_details.pending_action_button.${
pendingActionDto.type.toLowerCase() as Lowercase<YieldPendingActionType>
}`
}`,
{
defaultValue: humanizePendingActionType(pendingActionDto.type),
}
)}
</Text>
</Button>
Expand Down
10 changes: 10 additions & 0 deletions packages/widget/src/utils/formatters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,16 @@ export const formatCompactUsd = (value: string | number | null | undefined) => {
return `$${compactUsdFormatter.format(amount.toNumber())}`;
};

// Pending action types come straight from the API and can outpace our
// translation maps (e.g. RWA-specific actions like WITHDRAWAL_REQUEST). Use this
// as the i18n `defaultValue`/`defaults` so we never render a raw translation key.
export const humanizePendingActionType = (type: string): string =>
type
.split("_")
.filter(Boolean)
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
.join(" ");

export const capitalizeFirstLetters = (text: string): string =>
Maybe.fromNullable(text)
.map((t) =>
Expand Down
10 changes: 5 additions & 5 deletions packages/widget/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ export const defaultFormattedNumber = (number: string | BigNumber | number) =>
export const APToPercentage = (ap: number) =>
formatNumber((ap * 100).toFixed(2));

const colorsTuple = ["#6B69D6", "#F1C40F", "#1ABC9C", "#E74C3C"];
// const colorsTuple = ["#6B69D6", "#F1C40F", "#1ABC9C", "#E74C3C"];

export const getBackgroundColor = (stringInput: string) => {
const char = stringInput.charCodeAt(0);
// export const getBackgroundColor = (stringInput: string) => {
// const char = stringInput.charCodeAt(0);

return colorsTuple[char % colorsTuple.length] ?? colorsTuple[0];
};
// return colorsTuple[char % colorsTuple.length] ?? colorsTuple[0];
// };

export const isIframe = () =>
MaybeWindow.map((w) => w.parent !== w).orDefault(false);
Expand Down