Icon and banner to show workflow

This commit is contained in:
Viktor Egorov
2025-05-05 08:51:50 +02:00
parent 63a936d5e2
commit 554d2c7af6
8 changed files with 267 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
- type: added
description: Icon for displaying a status like success

View File

@@ -29,6 +29,7 @@ export const ButtonVariants = {
SECONDARY: "secondary",
TERTIARY: "tertiary",
SIGNAL: "signal",
DANGER: "danger",
INFO: "info",
} as const;
@@ -43,6 +44,7 @@ const createButtonClasses = (variant?: ButtonVariant, isLoading?: boolean) =>
"is-primary is-inverted": variant === "tertiary",
"is-warning": variant === "signal",
"is-info is-outlined": variant === "info",
"is-danger": variant === "danger",
"is-loading": isLoading,
});

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
import React, { ComponentProps } from "react";
import StoryRouter from "storybook-react-router";
import { StoryFn } from "@storybook/react";
import { StatusIcon } from "./index";
import { StatusIconSizeVariantList, StatusVariantList, StatusVariants } from "./StatusIcon";
// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
export default {
title: "Status",
component: null,
subcomponents: {
Button: StatusIcon,
},
argTypes: {
variant: {
options: StatusVariantList,
control: { type: "select" },
},
iconSize: {
options: StatusIconSizeVariantList,
control: { type: "select" },
},
},
decorators: [StoryRouter()],
parameters: {
storyshots: { disable: true },
},
};
// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
const StatusIconTemplate: StoryFn<ComponentProps<typeof StatusIcon>> = (args) => <StatusIcon {...args} />;
export const Icon = StatusIconTemplate.bind({});
Icon.args = {
variant: StatusVariants.SUCCESS,
invert: false,
iconSize: "lg",
};
export const IconWithTitle = StatusIconTemplate.bind({});
IconWithTitle.args = {
variant: StatusVariants.SUCCESS,
invert: false,
iconSize: "lg",
children: "Lorem Ipsum",
};

View File

@@ -0,0 +1,133 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
import React from "react";
import classNames from "classnames";
import { Icon } from "../buttons";
export const StatusVariants = {
IN_PROGRESS: "in progress",
SUCCESS: "success",
WARNING: "warning",
DANGER: "danger",
UNDEFINED: "undefined",
};
export const StatusVariantList = Object.values(StatusVariants);
export type StatusVariant = typeof StatusVariants[keyof typeof StatusVariants];
export const StatusIconSizeVariants = {
SMALL: "xs",
MEDIUM: "lg",
LARGE: "2x",
};
export const StatusIconSizeVariantList = Object.values(StatusIconSizeVariants);
export type StatusIconSizeVariant = typeof StatusIconSizeVariants[keyof typeof StatusIconSizeVariants];
type IconProps = React.HTMLProps<HTMLElement> & {
variant: StatusVariant;
color?: string;
iconSize?: StatusIconSizeVariant;
invert?: boolean;
};
/**
*
* @beta
* @since 3.9.0
*/
const StatusIcon = React.forwardRef<HTMLElement, IconProps>(
({ color, className, iconSize = StatusIconSizeVariants.MEDIUM, variant, invert = false, children }, ref) => {
const icon = classNames({
"exclamation-triangle": variant === StatusVariants.DANGER,
"check-circle": variant === StatusVariants.SUCCESS,
"hourglass-start": variant === StatusVariants.IN_PROGRESS,
"circle-notch": variant === StatusVariants.UNDEFINED,
});
if (!color) {
if (invert) {
color = classNames({
"icon-color-inverted": variant === StatusVariants.DANGER || StatusVariants.SUCCESS,
"icon-warning-inverted": variant === StatusVariants.WARNING,
"icon-color-inverted-secondary":
variant === StatusVariants.IN_PROGRESS || variant === StatusVariants.UNDEFINED,
});
} else {
color = classNames({
"has-text-danger": variant === StatusVariants.DANGER,
"has-text-success": variant === StatusVariants.SUCCESS,
"has-text-warning": variant === StatusVariants.WARNING,
"icon-color-secondary": variant === StatusVariants.IN_PROGRESS || variant === StatusVariants.UNDEFINED,
});
}
}
return (
<div className="is-flex is-align-items-center">
{variant === "warning" ? (
<WarningIcon color={color} iconSize={iconSize} className={className}>{`${icon}`}</WarningIcon>
) : (
<Icon className={className}>{`${icon} ${color} fa-${iconSize}`}</Icon>
)}
{children && <span className="ml-2">{children}</span>}
</div>
);
}
);
type WarningIconProps = React.HTMLProps<HTMLElement> & {
color?: string;
iconSize?: string;
};
const WarningIcon = React.forwardRef<HTMLElement, WarningIconProps>(({ color, className, iconSize }, ref) => {
return (
<span className={classNames(className, "icon", color)} aria-hidden="true" ref={ref}>
<svg
xmlns="http://www.w3.org/2000/svg"
id="Ebene_1"
data-name="Ebene 1"
height="1em"
width="1em"
viewBox="0 0 140 140"
fill="currentColor"
className={classNames("fas fa-fw fa-custom-icon", `fa-${iconSize}`)}
>
<defs>
<mask id="cutoutMask">
<rect x="0" y="0" width="140" height="140" fill="white" />
<path
className="cls-2"
d="M79.93,109.67c-2.75,2.75-6.06,4.13-9.93,4.13s-7.18-1.38-9.93-4.13-4.13-6.06-4.13-9.93,1.38-7.18,4.13-9.93,6.06-4.13,9.93-4.13,7.18,1.38,9.93,4.13,4.13,6.06,4.13,9.93-1.38,7.18-4.13,9.93ZM59.98,76.01c0,1.17.41,2.14,1.23,2.9s1.82,1.14,2.99,1.14h11.6c1.17,0,2.17-.38,2.99-1.14s1.23-1.73,1.23-2.9l2.46-47.81c0-1.17-.41-2.2-1.23-3.08s-1.82-1.32-2.99-1.32h-16.52c-1.17,0-2.17.44-2.99,1.32s-1.23,1.9-1.23,3.08l2.46,47.81Z"
fill="black"
/>
</mask>
</defs>
<path
className="cls-1"
d="M125,0c4.17,0,7.71,1.46,10.62,4.38s4.38,6.46,4.38,10.62v110c0,4.17-1.46,7.71-4.38,10.63-2.92,2.92-6.46,4.38-10.62,4.38H15c-4.17,0-7.71-1.46-10.62-4.38-2.92-2.92-4.38-6.46-4.38-10.63V15c0-4.17,1.46-7.71,4.38-10.62S10.83,0,15,0h110Z"
mask="url(#cutoutMask)"
fill="currentColor"
/>
</svg>
</span>
);
});
export default StatusIcon;

View File

@@ -0,0 +1,17 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
export { default as StatusIcon, StatusVariant, StatusIconSizeVariant } from "./StatusIcon";

View File

@@ -314,3 +314,21 @@ input[type="date"].input::-webkit-calendar-picker-indicator {
.popover-close:focus {
background: $grey-darker !important;
}
.icon-color-inverted {
color: $white;
}
.icon-color-inverted-secondary {
color: $white;
}
.icon-warning-inverted {
color: #583708;
}
.icon-color-secondary {
color: $grey;
}

View File

@@ -337,3 +337,19 @@ input[type="date"].input::-webkit-calendar-picker-indicator {
.popover-close:focus {
background: $grey-light !important;
}
.icon-color-inverted {
color: $scheme-main;
}
.icon-color-inverted-secondary {
color: $white;
}
.icon-warning-inverted {
color: $scheme-main;
}
.icon-color-secondary {
color: $white;
}

View File

@@ -90,3 +90,19 @@ footer.footer {
.has-hover-visible:hover {
color: $grey-darker !important;
}
.icon-color-inverted {
color: $scheme-main;
}
.icon-color-inverted-secondary {
color: $white;
}
.icon-warning-inverted {
color: $scheme-main;
}
.icon-color-secondary {
color: $dark;
}