diff --git a/packages/frontend/src/components/shared/CustomIcon/InfoSquareIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/InfoSquareIcon.tsx
new file mode 100644
index 00000000..273131d6
--- /dev/null
+++ b/packages/frontend/src/components/shared/CustomIcon/InfoSquareIcon.tsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import { CustomIcon, CustomIconProps } from './CustomIcon';
+
+export const InfoSquareIcon = (props: CustomIconProps) => {
+ return (
+
+
+
+ );
+};
diff --git a/packages/frontend/src/components/shared/CustomIcon/index.ts b/packages/frontend/src/components/shared/CustomIcon/index.ts
index 6479a1dd..18dbf249 100644
--- a/packages/frontend/src/components/shared/CustomIcon/index.ts
+++ b/packages/frontend/src/components/shared/CustomIcon/index.ts
@@ -4,6 +4,7 @@ export * from './CheckIcon';
export * from './ChevronGrabberHorizontal';
export * from './ChevronLeft';
export * from './ChevronRight';
+export * from './InfoSquareIcon';
export * from './WarningIcon';
export * from './SearchIcon';
export * from './CrossIcon';
diff --git a/packages/frontend/src/components/shared/InlineNotification/InlineNotification.theme.ts b/packages/frontend/src/components/shared/InlineNotification/InlineNotification.theme.ts
new file mode 100644
index 00000000..43536b55
--- /dev/null
+++ b/packages/frontend/src/components/shared/InlineNotification/InlineNotification.theme.ts
@@ -0,0 +1,78 @@
+import { VariantProps, tv } from 'tailwind-variants';
+
+export const inlineNotificationTheme = tv({
+ slots: {
+ wrapper: ['rounded-xl', 'flex', 'gap-2', 'items-start', 'w-full', 'border'],
+ content: ['flex', 'flex-col', 'gap-1'],
+ title: [],
+ description: [],
+ icon: ['flex', 'items-start'],
+ },
+ variants: {
+ variant: {
+ info: {
+ wrapper: ['border-border-info-light', 'bg-base-bg-emphasized-info'],
+ title: ['text-elements-on-emphasized-info'],
+ description: ['text-elements-on-emphasized-info'],
+ icon: ['text-elements-info'],
+ },
+ danger: {
+ wrapper: ['border-border-danger-light', 'bg-base-bg-emphasized-danger'],
+ title: ['text-elements-on-emphasized-danger'],
+ description: ['text-elements-on-emphasized-danger'],
+ icon: ['text-elements-danger'],
+ },
+ warning: {
+ wrapper: [
+ 'border-border-warning-light',
+ 'bg-base-bg-emphasized-warning',
+ ],
+ title: ['text-elements-on-emphasized-warning'],
+ description: ['text-elements-on-emphasized-warning'],
+ icon: ['text-elements-warning'],
+ },
+ success: {
+ wrapper: [
+ 'border-border-success-light',
+ 'bg-base-bg-emphasized-success',
+ ],
+ title: ['text-elements-on-emphasized-success'],
+ description: ['text-elements-on-emphasized-success'],
+ icon: ['text-elements-success'],
+ },
+ generic: {
+ wrapper: ['border-border-separator', 'bg-base-bg-emphasized'],
+ title: ['text-elements-high-em'],
+ description: ['text-elements-on-emphasized-info'],
+ icon: ['text-elements-high-em'],
+ },
+ },
+ size: {
+ sm: {
+ wrapper: ['px-2', 'py-2'],
+ title: ['leading-4', 'text-xs'],
+ description: ['leading-4', 'text-xs'],
+ icon: ['h-4', 'w-4'],
+ },
+ md: {
+ wrapper: ['px-3', 'py-3'],
+ title: ['leading-5', 'tracking-[-0.006em]', 'text-sm'],
+ description: ['leading-5', 'tracking-[-0.006em]', 'text-sm'],
+ icon: ['h-5', 'w-5'],
+ },
+ },
+ hasDescription: {
+ true: {
+ title: ['font-medium'],
+ },
+ },
+ },
+ defaultVariants: {
+ variant: 'generic',
+ size: 'md',
+ },
+});
+
+export type InlineNotificationTheme = VariantProps<
+ typeof inlineNotificationTheme
+>;
diff --git a/packages/frontend/src/components/shared/InlineNotification/InlineNotification.tsx b/packages/frontend/src/components/shared/InlineNotification/InlineNotification.tsx
new file mode 100644
index 00000000..b3b2845c
--- /dev/null
+++ b/packages/frontend/src/components/shared/InlineNotification/InlineNotification.tsx
@@ -0,0 +1,68 @@
+import React, { ReactNode, useCallback } from 'react';
+import { ComponentPropsWithoutRef } from 'react';
+import {
+ InlineNotificationTheme,
+ inlineNotificationTheme,
+} from './InlineNotification.theme';
+import { InfoSquareIcon } from 'components/shared/CustomIcon';
+import { cloneIcon } from 'utils/cloneIcon';
+
+export interface InlineNotificationProps
+ extends ComponentPropsWithoutRef<'div'>,
+ InlineNotificationTheme {
+ /**
+ * The title of the notification
+ */
+ title: string;
+ /**
+ * The description of the notification
+ */
+ description?: string;
+ /**
+ * The icon to display in the notification
+ * @default
+ */
+ icon?: ReactNode;
+}
+
+/**
+ * A notification that is displayed inline with the content
+ *
+ * @example
+ * ```tsx
+ *
+ * ```
+ */
+export const InlineNotification = ({
+ className,
+ title,
+ description,
+ size,
+ variant,
+ icon,
+ ...props
+}: InlineNotificationProps) => {
+ const {
+ wrapper,
+ content,
+ title: titleClass,
+ description: descriptionClass,
+ icon: iconClass,
+ } = inlineNotificationTheme({ size, variant, hasDescription: !!description });
+
+ // Render custom icon or default icon
+ const renderIcon = useCallback(() => {
+ if (!icon) return ;
+ return cloneIcon(icon, { className: iconClass() });
+ }, [icon]);
+
+ return (
+
+ {renderIcon()}
+
+
{title}
+ {description &&
{description}
}
+
+
+ );
+};
diff --git a/packages/frontend/src/components/shared/InlineNotification/index.ts b/packages/frontend/src/components/shared/InlineNotification/index.ts
new file mode 100644
index 00000000..fbe7bbd4
--- /dev/null
+++ b/packages/frontend/src/components/shared/InlineNotification/index.ts
@@ -0,0 +1 @@
+export * from './InlineNotification';
diff --git a/packages/frontend/src/pages/components/index.tsx b/packages/frontend/src/pages/components/index.tsx
index 353f90a5..48c1930d 100644
--- a/packages/frontend/src/pages/components/index.tsx
+++ b/packages/frontend/src/pages/components/index.tsx
@@ -18,6 +18,10 @@ import {
renderVerticalTabs,
} from './renders/tabs';
import { Switch } from 'components/shared/Switch';
+import {
+ renderInlineNotificationWithDescriptions,
+ renderInlineNotifications,
+} from './renders/inlineNotifications';
import { renderInputs } from './renders/input';
const Page = () => {
@@ -27,7 +31,7 @@ const Page = () => {
return (
-
+
Manual Storybook
Get started by editing{' '}
@@ -149,6 +153,19 @@ const Page = () => {
+ {/* Inline notification */}
+
+
Inline Notification
+
+ {renderInlineNotifications()}
+
+
+ {renderInlineNotificationWithDescriptions()}
+
+
+
+
+
{/* Link */}
Link
diff --git a/packages/frontend/src/pages/components/renders/inlineNotifications.tsx b/packages/frontend/src/pages/components/renders/inlineNotifications.tsx
new file mode 100644
index 00000000..fc36b914
--- /dev/null
+++ b/packages/frontend/src/pages/components/renders/inlineNotifications.tsx
@@ -0,0 +1,43 @@
+import { InlineNotification } from 'components/shared/InlineNotification';
+import { InlineNotificationTheme } from 'components/shared/InlineNotification/InlineNotification.theme';
+import React from 'react';
+
+const inlineNotificationVariants = [
+ 'info',
+ 'danger',
+ 'warning',
+ 'success',
+ 'generic',
+];
+const inlineNotificationSizes = ['md', 'sm'];
+
+export const renderInlineNotifications = () => {
+ return inlineNotificationVariants.map((variant) => (
+
+ {inlineNotificationSizes.map((size) => (
+
+ ))}
+
+ ));
+};
+
+export const renderInlineNotificationWithDescriptions = () => {
+ return inlineNotificationVariants.map((variant) => (
+
+ {inlineNotificationSizes.map((size) => (
+
+ ))}
+
+ ));
+};