New clickable card that behaves like a button (#3248)

This commit is contained in:
Erik Jan de Wit 2022-09-05 23:32:02 +02:00 committed by GitHub
parent df6526311a
commit 573fb2ff03
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 43 additions and 24 deletions

View 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>
);
};

View file

@ -1,6 +1,5 @@
import { ReactElement, useState } from "react"; import { ReactElement, useState } from "react";
import { import {
Card,
CardHeader, CardHeader,
CardActions, CardActions,
CardTitle, CardTitle,
@ -15,6 +14,7 @@ import {
import "./keycloak-card.css"; import "./keycloak-card.css";
import { useRouteMatch } from "react-router-dom"; import { useRouteMatch } from "react-router-dom";
import { useNavigate } from "react-router-dom-v5-compat"; import { useNavigate } from "react-router-dom-v5-compat";
import { ClickableCard } from "./ClickableCard";
export type KeycloakCardProps = { export type KeycloakCardProps = {
id: string; id: string;
@ -54,7 +54,7 @@ export const KeycloakCard = ({
}; };
return ( return (
<Card role="button" isSelectable onClick={openSettings}> <ClickableCard isSelectable onClick={openSettings}>
<CardHeader> <CardHeader>
<CardActions> <CardActions>
{dropdownItems && ( {dropdownItems && (
@ -84,6 +84,6 @@ export const KeycloakCard = ({
</FlexItem> </FlexItem>
</Flex> </Flex>
</CardFooter> </CardFooter>
</Card> </ClickableCard>
); );
}; };

View file

@ -8,7 +8,6 @@ import {
Badge, Badge,
Button, Button,
ButtonVariant, ButtonVariant,
Card,
CardTitle, CardTitle,
Dropdown, Dropdown,
DropdownGroup, DropdownGroup,
@ -39,6 +38,7 @@ import { ManageOrderDialog } from "./ManageOrderDialog";
import { toIdentityProvider } from "./routes/IdentityProvider"; import { toIdentityProvider } from "./routes/IdentityProvider";
import { toIdentityProviderCreate } from "./routes/IdentityProviderCreate"; import { toIdentityProviderCreate } from "./routes/IdentityProviderCreate";
import helpUrls from "../help-urls"; import helpUrls from "../help-urls";
import { ClickableCard } from "../components/keycloak-card/ClickableCard";
export default function IdentityProvidersSection() { export default function IdentityProvidersSection() {
const { t } = useTranslation("identity-providers"); const { t } = useTranslation("identity-providers");
@ -190,11 +190,8 @@ export default function IdentityProvidersSection() {
<hr className="pf-u-mb-lg" /> <hr className="pf-u-mb-lg" />
<Gallery hasGutter> <Gallery hasGutter>
{sortBy(identityProviders[group], "name").map((provider) => ( {sortBy(identityProviders[group], "name").map((provider) => (
<Card <ClickableCard
className="keycloak-empty-state-card"
role="button"
key={provider.id} key={provider.id}
isHoverable
data-testid={`${provider.id}-card`} data-testid={`${provider.id}-card`}
onClick={() => navigateToCreate(provider.id)} onClick={() => navigateToCreate(provider.id)}
> >
@ -206,7 +203,7 @@ export default function IdentityProvidersSection() {
<SplitItem isFilled>{provider.name}</SplitItem> <SplitItem isFilled>{provider.name}</SplitItem>
</Split> </Split>
</CardTitle> </CardTitle>
</Card> </ClickableCard>
))} ))}
</Gallery> </Gallery>
</Fragment> </Fragment>

View file

@ -12,7 +12,6 @@ export const FontAwesomeIcon = ({ icon }: FontAwesomeIconProps) => {
<img <img
src={environment.resourceUrl + "/bitbucket-brands.svg"} src={environment.resourceUrl + "/bitbucket-brands.svg"}
{...styles} {...styles}
aria-label="bitbucket icon"
/> />
); );
case "microsoft": case "microsoft":
@ -20,7 +19,6 @@ export const FontAwesomeIcon = ({ icon }: FontAwesomeIconProps) => {
<img <img
src={environment.resourceUrl + "/microsoft-brands.svg"} src={environment.resourceUrl + "/microsoft-brands.svg"}
{...styles} {...styles}
aria-label="microsoft icon"
/> />
); );
case "instagram": case "instagram":
@ -28,16 +26,11 @@ export const FontAwesomeIcon = ({ icon }: FontAwesomeIconProps) => {
<img <img
src={environment.resourceUrl + "/instagram-brands.svg"} src={environment.resourceUrl + "/instagram-brands.svg"}
{...styles} {...styles}
aria-label="instagram icon"
/> />
); );
case "paypal": case "paypal":
return ( return (
<img <img src={environment.resourceUrl + "/paypal-brands.svg"} {...styles} />
src={environment.resourceUrl + "/paypal-brands.svg"}
{...styles}
aria-label="paypal icon"
/>
); );
default: default:
return null; return null;

View file

@ -1,7 +1,6 @@
import { import {
AlertVariant, AlertVariant,
ButtonVariant, ButtonVariant,
Card,
CardTitle, CardTitle,
DropdownItem, DropdownItem,
Gallery, Gallery,
@ -28,9 +27,10 @@ import { useRealm } from "../context/realm-context/RealmContext";
import { useServerInfo } from "../context/server-info/ServerInfoProvider"; import { useServerInfo } from "../context/server-info/ServerInfoProvider";
import { toUpperCase } from "../util"; import { toUpperCase } from "../util";
import { toProvider } from "./routes/NewProvider"; import { toProvider } from "./routes/NewProvider";
import { ClickableCard } from "../components/keycloak-card/ClickableCard";
import helpUrls from "../help-urls";
import "./user-federation.css"; import "./user-federation.css";
import helpUrls from "../help-urls";
export default function UserFederationSection() { export default function UserFederationSection() {
const [userFederations, setUserFederations] = const [userFederations, setUserFederations] =
@ -193,11 +193,8 @@ export default function UserFederationSection() {
<hr className="pf-u-mb-lg" /> <hr className="pf-u-mb-lg" />
<Gallery hasGutter> <Gallery hasGutter>
{providers.map((p) => ( {providers.map((p) => (
<Card <ClickableCard
key={p.id} key={p.id}
className="keycloak-empty-state-card"
role="button"
isHoverable
onClick={() => onClick={() =>
navigate(toProvider({ realm, providerId: p.id! })) navigate(toProvider({ realm, providerId: p.id! }))
} }
@ -216,7 +213,7 @@ export default function UserFederationSection() {
</SplitItem> </SplitItem>
</Split> </Split>
</CardTitle> </CardTitle>
</Card> </ClickableCard>
))} ))}
</Gallery> </Gallery>
</> </>