New clickable card that behaves like a button (#3248)
This commit is contained in:
parent
df6526311a
commit
573fb2ff03
5 changed files with 43 additions and 24 deletions
32
apps/admin-ui/src/components/keycloak-card/ClickableCard.tsx
Normal file
32
apps/admin-ui/src/components/keycloak-card/ClickableCard.tsx
Normal file
|
@ -0,0 +1,32 @@
|
|||
import { KeyboardEvent } from "react";
|
||||
import { Card, CardProps } from "@patternfly/react-core";
|
||||
|
||||
type ClickableCardProps = Omit<CardProps, "onClick"> & {
|
||||
onClick: () => void;
|
||||
};
|
||||
|
||||
export const ClickableCard = ({
|
||||
children,
|
||||
onClick,
|
||||
...rest
|
||||
}: ClickableCardProps) => {
|
||||
const onKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
|
||||
onClick();
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Card
|
||||
className="keycloak-empty-state-card"
|
||||
role="button"
|
||||
aria-pressed="false"
|
||||
tabIndex={0}
|
||||
isHoverable
|
||||
onKeyDown={onKeyDown}
|
||||
onClick={onClick}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</Card>
|
||||
);
|
||||
};
|
|
@ -1,6 +1,5 @@
|
|||
import { ReactElement, useState } from "react";
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardActions,
|
||||
CardTitle,
|
||||
|
@ -15,6 +14,7 @@ import {
|
|||
import "./keycloak-card.css";
|
||||
import { useRouteMatch } from "react-router-dom";
|
||||
import { useNavigate } from "react-router-dom-v5-compat";
|
||||
import { ClickableCard } from "./ClickableCard";
|
||||
|
||||
export type KeycloakCardProps = {
|
||||
id: string;
|
||||
|
@ -54,7 +54,7 @@ export const KeycloakCard = ({
|
|||
};
|
||||
|
||||
return (
|
||||
<Card role="button" isSelectable onClick={openSettings}>
|
||||
<ClickableCard isSelectable onClick={openSettings}>
|
||||
<CardHeader>
|
||||
<CardActions>
|
||||
{dropdownItems && (
|
||||
|
@ -84,6 +84,6 @@ export const KeycloakCard = ({
|
|||
</FlexItem>
|
||||
</Flex>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</ClickableCard>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -8,7 +8,6 @@ import {
|
|||
Badge,
|
||||
Button,
|
||||
ButtonVariant,
|
||||
Card,
|
||||
CardTitle,
|
||||
Dropdown,
|
||||
DropdownGroup,
|
||||
|
@ -39,6 +38,7 @@ import { ManageOrderDialog } from "./ManageOrderDialog";
|
|||
import { toIdentityProvider } from "./routes/IdentityProvider";
|
||||
import { toIdentityProviderCreate } from "./routes/IdentityProviderCreate";
|
||||
import helpUrls from "../help-urls";
|
||||
import { ClickableCard } from "../components/keycloak-card/ClickableCard";
|
||||
|
||||
export default function IdentityProvidersSection() {
|
||||
const { t } = useTranslation("identity-providers");
|
||||
|
@ -190,11 +190,8 @@ export default function IdentityProvidersSection() {
|
|||
<hr className="pf-u-mb-lg" />
|
||||
<Gallery hasGutter>
|
||||
{sortBy(identityProviders[group], "name").map((provider) => (
|
||||
<Card
|
||||
className="keycloak-empty-state-card"
|
||||
role="button"
|
||||
<ClickableCard
|
||||
key={provider.id}
|
||||
isHoverable
|
||||
data-testid={`${provider.id}-card`}
|
||||
onClick={() => navigateToCreate(provider.id)}
|
||||
>
|
||||
|
@ -206,7 +203,7 @@ export default function IdentityProvidersSection() {
|
|||
<SplitItem isFilled>{provider.name}</SplitItem>
|
||||
</Split>
|
||||
</CardTitle>
|
||||
</Card>
|
||||
</ClickableCard>
|
||||
))}
|
||||
</Gallery>
|
||||
</Fragment>
|
||||
|
|
|
@ -12,7 +12,6 @@ export const FontAwesomeIcon = ({ icon }: FontAwesomeIconProps) => {
|
|||
<img
|
||||
src={environment.resourceUrl + "/bitbucket-brands.svg"}
|
||||
{...styles}
|
||||
aria-label="bitbucket icon"
|
||||
/>
|
||||
);
|
||||
case "microsoft":
|
||||
|
@ -20,7 +19,6 @@ export const FontAwesomeIcon = ({ icon }: FontAwesomeIconProps) => {
|
|||
<img
|
||||
src={environment.resourceUrl + "/microsoft-brands.svg"}
|
||||
{...styles}
|
||||
aria-label="microsoft icon"
|
||||
/>
|
||||
);
|
||||
case "instagram":
|
||||
|
@ -28,16 +26,11 @@ export const FontAwesomeIcon = ({ icon }: FontAwesomeIconProps) => {
|
|||
<img
|
||||
src={environment.resourceUrl + "/instagram-brands.svg"}
|
||||
{...styles}
|
||||
aria-label="instagram icon"
|
||||
/>
|
||||
);
|
||||
case "paypal":
|
||||
return (
|
||||
<img
|
||||
src={environment.resourceUrl + "/paypal-brands.svg"}
|
||||
{...styles}
|
||||
aria-label="paypal icon"
|
||||
/>
|
||||
<img src={environment.resourceUrl + "/paypal-brands.svg"} {...styles} />
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import {
|
||||
AlertVariant,
|
||||
ButtonVariant,
|
||||
Card,
|
||||
CardTitle,
|
||||
DropdownItem,
|
||||
Gallery,
|
||||
|
@ -28,9 +27,10 @@ import { useRealm } from "../context/realm-context/RealmContext";
|
|||
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
||||
import { toUpperCase } from "../util";
|
||||
import { toProvider } from "./routes/NewProvider";
|
||||
import { ClickableCard } from "../components/keycloak-card/ClickableCard";
|
||||
import helpUrls from "../help-urls";
|
||||
|
||||
import "./user-federation.css";
|
||||
import helpUrls from "../help-urls";
|
||||
|
||||
export default function UserFederationSection() {
|
||||
const [userFederations, setUserFederations] =
|
||||
|
@ -193,11 +193,8 @@ export default function UserFederationSection() {
|
|||
<hr className="pf-u-mb-lg" />
|
||||
<Gallery hasGutter>
|
||||
{providers.map((p) => (
|
||||
<Card
|
||||
<ClickableCard
|
||||
key={p.id}
|
||||
className="keycloak-empty-state-card"
|
||||
role="button"
|
||||
isHoverable
|
||||
onClick={() =>
|
||||
navigate(toProvider({ realm, providerId: p.id! }))
|
||||
}
|
||||
|
@ -216,7 +213,7 @@ export default function UserFederationSection() {
|
|||
</SplitItem>
|
||||
</Split>
|
||||
</CardTitle>
|
||||
</Card>
|
||||
</ClickableCard>
|
||||
))}
|
||||
</Gallery>
|
||||
</>
|
||||
|
|
Loading…
Reference in a new issue