mirror of
https://github.com/OpenHands/OpenHands.git
synced 2025-12-26 05:48:36 +08:00
refactor(frontend): replace Temp components with design system components (#12158)
This commit is contained in:
parent
a51b285021
commit
89a9e73c8a
@ -19,32 +19,14 @@ import { SettingsDropdownInput } from "../settings/settings-dropdown-input";
|
||||
import { I18nKey } from "#/i18n/declaration";
|
||||
import { useSettingsNavItems } from "#/hooks/use-settings-nav-items";
|
||||
import DocumentIcon from "#/icons/document.svg?react";
|
||||
import { Divider } from "#/ui/divider";
|
||||
import { ContextMenuListItem } from "../context-menu/context-menu-list-item";
|
||||
|
||||
interface TempButtonProps {
|
||||
start: React.ReactNode;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
function TempButton({
|
||||
start,
|
||||
children,
|
||||
onClick,
|
||||
}: React.PropsWithChildren<TempButtonProps>) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
className="flex items-center gap-1 cursor-pointer hover:text-white w-full text-left"
|
||||
>
|
||||
{start}
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
function TempDivider() {
|
||||
return <div className="h-[1px] w-full bg-[#5C5D62] my-1.5" />;
|
||||
}
|
||||
// Shared className for context menu list items in the user context menu
|
||||
// Removes default padding and hover background to match the simpler text-hover style
|
||||
const contextMenuListItemClassName = cn(
|
||||
"flex items-center p-0 h-auto hover:bg-transparent hover:text-white gap-1",
|
||||
);
|
||||
|
||||
interface UserContextMenuProps {
|
||||
type: OrganizationUserRole;
|
||||
@ -140,31 +122,34 @@ export function UserContextMenu({ type, onClose }: UserContextMenuProps) {
|
||||
|
||||
{!isUser && (
|
||||
<>
|
||||
<TempButton
|
||||
<ContextMenuListItem
|
||||
onClick={handleInviteMemberClick}
|
||||
start={<IoPersonAddOutline className="text-white" size={14} />}
|
||||
className={contextMenuListItemClassName}
|
||||
>
|
||||
<IoPersonAddOutline className="text-white" size={14} />
|
||||
{t(I18nKey.ORG$INVITE_ORGANIZATION_MEMBER)}
|
||||
</TempButton>
|
||||
</ContextMenuListItem>
|
||||
|
||||
<TempDivider />
|
||||
<Divider className="my-1.5" />
|
||||
|
||||
<TempButton
|
||||
<ContextMenuListItem
|
||||
onClick={handleManageAccountClick}
|
||||
start={<IoCardOutline className="text-white" size={14} />}
|
||||
className={contextMenuListItemClassName}
|
||||
>
|
||||
<IoCardOutline className="text-white" size={14} />
|
||||
{t(I18nKey.ORG$MANAGE_ACCOUNT)}
|
||||
</TempButton>
|
||||
<TempButton
|
||||
</ContextMenuListItem>
|
||||
<ContextMenuListItem
|
||||
onClick={handleManageOrganizationMembersClick}
|
||||
start={<IoPersonOutline className="text-white" size={14} />}
|
||||
className={contextMenuListItemClassName}
|
||||
>
|
||||
<IoPersonOutline className="text-white" size={14} />
|
||||
{t(I18nKey.ORG$MANAGE_ORGANIZATION_MEMBERS)}
|
||||
</TempButton>
|
||||
</ContextMenuListItem>
|
||||
</>
|
||||
)}
|
||||
|
||||
<TempDivider />
|
||||
<Divider className="my-1.5" />
|
||||
|
||||
{navItems.map((item) => (
|
||||
<Link
|
||||
@ -182,7 +167,7 @@ export function UserContextMenu({ type, onClose }: UserContextMenuProps) {
|
||||
</Link>
|
||||
))}
|
||||
|
||||
<TempDivider />
|
||||
<Divider className="my-1.5" />
|
||||
|
||||
<a
|
||||
href="https://docs.openhands.dev"
|
||||
@ -195,12 +180,13 @@ export function UserContextMenu({ type, onClose }: UserContextMenuProps) {
|
||||
{t(I18nKey.SIDEBAR$DOCS)}
|
||||
</a>
|
||||
|
||||
<TempButton
|
||||
<ContextMenuListItem
|
||||
onClick={handleLogout}
|
||||
start={<IoLogOutOutline className="text-white" size={14} />}
|
||||
className={contextMenuListItemClassName}
|
||||
>
|
||||
<IoLogOutOutline className="text-white" size={14} />
|
||||
{t(I18nKey.ACCOUNT_SETTINGS$LOGOUT)}
|
||||
</TempButton>
|
||||
</ContextMenuListItem>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -21,66 +21,8 @@ import { I18nKey } from "#/i18n/declaration";
|
||||
import { amountIsValid } from "#/utils/amount-is-valid";
|
||||
import { useUpdateOrganization } from "#/hooks/mutation/use-update-organization";
|
||||
import { useDeleteOrganization } from "#/hooks/mutation/use-delete-organization";
|
||||
|
||||
function TempChip({
|
||||
children,
|
||||
...props
|
||||
}: React.PropsWithChildren<{ "data-testid": string }>) {
|
||||
return (
|
||||
<div
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
{...props}
|
||||
style={{ minWidth: "100px" }}
|
||||
data-openhands-chip
|
||||
className="bg-[#FFE165] px-4 rounded-[100px] text-black text-lg text-center font-semibold"
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface TempInteractiveChipProps {
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
function TempInteractiveChip({
|
||||
children,
|
||||
onClick,
|
||||
}: React.PropsWithChildren<TempInteractiveChipProps>) {
|
||||
return (
|
||||
<div
|
||||
onClick={onClick}
|
||||
className="bg-[#E4E4E4] px-2 rounded-[100px] text-black text-sm text-center font-semibold cursor-pointer"
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TempButton({
|
||||
children,
|
||||
onClick,
|
||||
type,
|
||||
variant = "primary",
|
||||
}: React.PropsWithChildren<{
|
||||
onClick?: () => void;
|
||||
type: "button" | "submit";
|
||||
variant?: "primary" | "secondary";
|
||||
}>) {
|
||||
return (
|
||||
<button
|
||||
className={cn(
|
||||
"flex-1 py-3 rounded text-sm text-center font-semibold cursor-pointer",
|
||||
variant === "primary" && "bg-[#F3CE49] text-black",
|
||||
variant === "secondary" && "bg-[#737373] text-white",
|
||||
)}
|
||||
type={type === "submit" ? "submit" : "button"}
|
||||
onClick={onClick}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
import { CreditsChip } from "#/ui/credits-chip";
|
||||
import { InteractiveChip } from "#/ui/interactive-chip";
|
||||
|
||||
interface ChangeOrgNameModalProps {
|
||||
onClose: () => void;
|
||||
@ -252,10 +194,17 @@ function AddCreditsModal({ onClose }: AddCreditsModalProps) {
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<TempButton type="submit">{t(I18nKey.ORG$NEXT)}</TempButton>
|
||||
<TempButton type="button" onClick={onClose} variant="secondary">
|
||||
<BrandButton type="submit" variant="primary" className="flex-1 py-3">
|
||||
{t(I18nKey.ORG$NEXT)}
|
||||
</BrandButton>
|
||||
<BrandButton
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
variant="secondary"
|
||||
className="flex-1 py-3"
|
||||
>
|
||||
{t(I18nKey.BUTTON$CANCEL)}
|
||||
</TempButton>
|
||||
</BrandButton>
|
||||
</div>
|
||||
</form>
|
||||
</ModalBackdrop>
|
||||
@ -323,15 +272,13 @@ function ManageOrg() {
|
||||
{t(I18nKey.ORG$CREDITS)}
|
||||
</span>
|
||||
<div className="flex items-center gap-2">
|
||||
<TempChip data-testid="available-credits">
|
||||
<CreditsChip testId="available-credits">
|
||||
{organization?.credits}
|
||||
</TempChip>
|
||||
</CreditsChip>
|
||||
{canAddCredits && (
|
||||
<TempInteractiveChip
|
||||
onClick={() => setAddCreditsFormVisible(true)}
|
||||
>
|
||||
<InteractiveChip onClick={() => setAddCreditsFormVisible(true)}>
|
||||
{t(I18nKey.ORG$ADD)}
|
||||
</TempInteractiveChip>
|
||||
</InteractiveChip>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
30
frontend/src/ui/credits-chip.tsx
Normal file
30
frontend/src/ui/credits-chip.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
import { cn } from "#/utils/utils";
|
||||
|
||||
interface CreditsChipProps {
|
||||
testId?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chip component for displaying credits amount
|
||||
* Uses yellow background with black text for visibility
|
||||
*/
|
||||
export function CreditsChip({
|
||||
children,
|
||||
testId,
|
||||
className,
|
||||
}: React.PropsWithChildren<CreditsChipProps>) {
|
||||
return (
|
||||
<div
|
||||
data-testid={testId}
|
||||
data-openhands-chip
|
||||
style={{ minWidth: "100px" }}
|
||||
className={cn(
|
||||
"bg-[#FFE165] px-4 rounded-[100px] text-black text-lg text-center font-semibold",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
33
frontend/src/ui/interactive-chip.tsx
Normal file
33
frontend/src/ui/interactive-chip.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import { cn } from "#/utils/utils";
|
||||
|
||||
interface InteractiveChipProps {
|
||||
onClick: () => void;
|
||||
testId?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Small clickable chip component for actions like "Add"
|
||||
* Uses gray background with black text
|
||||
*/
|
||||
export function InteractiveChip({
|
||||
children,
|
||||
onClick,
|
||||
testId,
|
||||
className,
|
||||
}: React.PropsWithChildren<InteractiveChipProps>) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
data-testid={testId}
|
||||
onClick={onClick}
|
||||
className={cn(
|
||||
"bg-[#E4E4E4] px-2 rounded-[100px] text-black text-sm text-center font-semibold cursor-pointer",
|
||||
"hover:bg-[#D4D4D4] transition-colors",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user