Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions frui/src/element/ProgressBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { CSSProperties } from 'react';
/**
* ProgressBar Props
*/
export type ProgressBarProps = {
value: number;
max?: number;
color?: string;
className?: string;
style?: CSSProperties;
};

/**
* ProgressBar Component
*/
export default function ProgressBar(props: ProgressBarProps) {
const {
value,
max = 100,
color,
className,
style
} = props;

const percent = Math.min(100, (value / max) * 100);

const progressClasses = ['frui-progress'];
const barClasses = ['frui-progress-bar'];

if (className) {
progressClasses.push(className);
barClasses.push(className);
}

const barStyle: CSSProperties = {
width: `${percent}%`,
backgroundColor: color || 'currentColor', // Still allow color prop
...style // Still allow custom inline styles
};

return (
<div className={progressClasses.join(' ')}>
<div className={barClasses.join(' ')} style={barStyle}></div>
</div>
);
}
107 changes: 107 additions & 0 deletions frui/src/element/Toast.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React, { useState, useEffect, ReactNode, CSSProperties } from 'react';

export type ToastProps = {
message: ReactNode;
type?: 'info' | 'warning' | 'success' | 'error' | 'muted';
color?: string;
duration?: number;
className?: string;
style?: CSSProperties;
closable?: boolean;
onClose?: () => void;
};

const defaultToastStyle: CSSProperties = {
position: 'relative',
padding: '10px 15px',
borderRadius: '5px',
boxShadow: '0 2px 5px rgba(0, 0, 0, 0.2)',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
opacity: 1,
transition: 'opacity 0.3s ease-in-out',
};

const typeStyles: Record<NonNullable<ToastProps['type']>, CSSProperties> = {
info: { backgroundColor: '#E7F5FF', color: '#0C5460', borderColor: '#B8DAFF' },
warning: { backgroundColor: '#FFF3CD', color: '#856404', borderColor: '#FFEEBA' },
success: { backgroundColor: '#D4EDDA', color: '#155724', borderColor: '#C3E6CB' },
error: { backgroundColor: '#F8D7DA', color: '#721C24', borderColor: '#F5C6CB' },
muted: { backgroundColor: '#E9ECEF', color: '#6C757D', borderColor: '#DEE2E6' },
};

const Toast: React.FC<ToastProps> = ({
message,
type = 'info',
color,
duration = 3000,
className,
style,
closable,
onClose,
}) => {
const [isVisible, setIsVisible] = useState(true);
const [isFadingOut, setIsFadingOut] = useState(false);

useEffect(() => {
if (duration > 0 && isVisible) {
const timer = setTimeout(() => {
setIsFadingOut(true);
setTimeout(() => {
setIsVisible(false);
if (onClose) {
onClose();
}
}, 300); // Match the CSS transition duration
}, duration);
return () => clearTimeout(timer);
}
}, [duration, isVisible, onClose]);

const handleClose = () => {
setIsFadingOut(true);
setTimeout(() => {
setIsVisible(false);
if (onClose) {
onClose();
}
}, 300); // Match the CSS transition duration
};

if (!isVisible && !isFadingOut) {
return null;
}

const toastStyle = {
...defaultToastStyle,
...typeStyles[type],
...(color && { backgroundColor: color, color: 'white' }), // Apply custom color if passed
...style,
opacity: isFadingOut ? 0 : 1, // Control opacity based on fading state
};

return (
<div className={`frui-toast ${className || ''}`} style={toastStyle}>
<span>{message}</span>
{closable && (
<button
onClick={handleClose}
style={{
marginLeft: '10px',
border: 'none',
background: 'transparent',
cursor: 'pointer',
color: toastStyle.color, // Inherits color, which might be a hex code
fontSize: '16px',
}}
aria-label="Close toast"
>
&times;
</button>
)}
</div>
);
};

export default Toast;
24 changes: 24 additions & 0 deletions frui/styles/progressbar.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.frui-progress {
background-color: #e0e0e0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

capital hex

border-radius: 4px;
display: block;
height: 8px;
overflow: hidden;
}

.frui-progress-bar {
background-color: currentColor;
border-radius: 4px;
height: 100%;
transition: width 0.2s ease-in-out;
}

/*example*/
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove.

.frui-progress.h-4 {
height: 16px;
}

.frui-progress.rounded-full,
.frui-progress-bar.rounded-full {
border-radius: 9999px;
}
62 changes: 62 additions & 0 deletions frui/styles/toast.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
.frui-toast {
align-items: center;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
display: flex;
justify-content: space-between;
opacity: 1;
padding: 10px 15px;
transition: opacity 0.3s ease-in-out;
}

.toast-stack-container {
align-items: flex-end;
bottom: 20px;
display: flex;
flex-direction: column-reverse;
gap: 10px;
max-width: 400px;
position: fixed;
right: 20px;
width: fit-content;
z-index: 1050;
}

.frui-toast-info {
background-color: #e7f5ff;
border-color: #b8daff;
color: #0c5460;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

capital hex

}

.frui-toast-warning {
background-color: #fff3cd;
border-color: #ffeeba;
color: #856404;
}

.frui-toast-success {
background-color: #d4edda;
border-color: #c3e6cb;
color: #155724;
}

.frui-toast-error {
background-color: #f8d7da;
border-color: #f5c6cb;
color: #721c24;
}

.frui-toast-muted {
background-color: #e9ecef;
border-color: #dee2e6;
color: #6c757d;
}

.frui-toast-close-button {
background: transparent;
border: none;
cursor: pointer;
font-size: 1em;
line-height: 1;
margin-left: 10px;
}
9 changes: 9 additions & 0 deletions web/modules/theme/layouts/components/MainMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,18 @@ const MainMenu: React.FC<{
<Link href="/component/modal" className={`${pathname.indexOf('/component/modal') === 0 ? 'text-white' : ''} block pl-7 pr-3 py-2 cursor-pointer`}>
<span className="inline-block pl-2">{_('Modal')}</span>
</Link>
<Link href="/component/progressbar" className={`${pathname.indexOf('/component/progressbar') === 0 ? 'text-white' : ''} block pl-7 pr-3 py-2 cursor-pointer`}>
<span className="inline-block pl-2">{_('Progress Bar')}</span>
</Link>
<Link href="/component/table" className={`${pathname.indexOf('/component/table') === 0 ? 'text-white' : ''} block pl-7 pr-3 py-2 cursor-pointer`}>
<span className="inline-block pl-2">{_('Table')}</span>
</Link>
<Link href="/component/tabs" className={`${pathname.indexOf('/component/tabs') === 0 ? 'text-white' : ''} block pl-7 pr-3 py-2 cursor-pointer`}>
<span className="inline-block pl-2">{_('Tabs')}</span>
</Link>
<Link href="/component/toast" className={`${pathname.indexOf('/component/toast') === 0 ? 'text-white' : ''} block pl-7 pr-3 py-2 cursor-pointer`}>
<span className="inline-block pl-2">{_('Toast')}</span>
</Link>
<Link href="/component/tooltip" className={`${pathname.indexOf('/component/tooltip') === 0 ? 'text-white' : ''} block pl-7 pr-3 py-2 cursor-pointer`}>
<span className="inline-block pl-2">{_('Tooltip')}</span>
</Link>
Expand Down Expand Up @@ -130,6 +136,9 @@ const MainMenu: React.FC<{
<Link href="/field/radio" className={`${pathname.indexOf('/field/radio') === 0 ? 'text-white' : ''} block pl-7 pr-3 py-2 cursor-pointer`}>
<span className="inline-block pl-2">{_('Radio')}</span>
</Link>
<Link href="/field/radio" className={`${pathname.indexOf('/field/rangeslider') === 0 ? 'text-white' : ''} block pl-7 pr-3 py-2 cursor-pointer`}>
<span className="inline-block pl-2">{_('Range Slider')}</span>
</Link>
<Link href="/field/select" className={`${pathname.indexOf('/field/select') === 0 ? 'text-white' : ''} block pl-7 pr-3 py-2 cursor-pointer`}>
<span className="inline-block pl-2">{_('Select')}</span>
</Link>
Expand Down
56 changes: 52 additions & 4 deletions web/pages/component/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Badge from 'frui/element/Badge';
import Button from 'frui/form/Button';
import Loader from 'frui/element/Loader';
import Table, { Thead, Trow, Tcol } from 'frui/element/Table';
import ProgressBar from 'frui/element/ProgressBar';
import Tabs from 'frui/element/Tabs';
import Tooltip from 'frui/element/Tooltip';

Expand Down Expand Up @@ -116,6 +117,23 @@ export default function Home() {
</h2>
</div>
</div>
<div
className="block basis-1/2 md:basis-1/3 text-center cursor-pointer"
onClick={() => router.push('/component/progressbar')}
>
<div className="m-2 border border-b2 rounded overflow-hidden">
<div className="flex items-center justify-center h-[100px] w-full bg-b1">
<div className="w-full px-3">
<div className="relative w-full h-4 bg-gray-300 rounded">
<ProgressBar value={60} max={100} color="blue" className="h-4 rounded" />
</div>
</div>
</div>
<h2 className="my-2 font-semibold text-center uppercase">
{_('Progress Bar')}
</h2>
</div>
</div>
<div
className="block basis-1/2 md:basis-1/3 text-center cursor-pointer"
onClick={() => router.push('/component/table')}
Expand All @@ -138,7 +156,7 @@ export default function Home() {
</h2>
</div>
</div>
<div
<div
className="block basis-1/2 md:basis-1/3 text-center cursor-pointer"
onClick={() => router.push('/component/tabs')}
>
Expand Down Expand Up @@ -181,6 +199,31 @@ export default function Home() {
</h2>
</div>
</div>
<div
className="block basis-1/2 md:basis-1/3 text-center cursor-pointer"
onClick={() => router.push('/component/toast')}
>
<div className="m-2 border border-b2 rounded overflow-hidden">
<div className="flex items-center justify-center h-[100px] w-full bg-b1 relative p-3">
<div
className="inline-flex items-center justify-between w-auto max-w-full p-[10px_15px] rounded-[5px] shadow-[0_2px_5px_rgba(0,0,0,0.2)] bg-[#d4edda] text-[#155724] border border-[#c3e6cb]"
>
<span className="truncate">
{_('Successful! Your action was completed.')}
</span>
<span
className="ml-2 text-[16px] leading-none"
aria-hidden="true"
>
&times;
</span>
</div>
</div>
<h2 className="my-2 font-semibold text-center uppercase">
{_('Toast')}
</h2>
</div>
</div>
</div>
<h2 className="px-3 flex items-center uppercase font-bold text-xl mt-4">
<i className="fas fa-lock mr-2" />
Expand Down Expand Up @@ -214,11 +257,12 @@ export default function Home() {
<div className="block basis-1/2 md:basis-1/3 text-center cursor-pointer">
<div className="m-2 border border-b2 rounded overflow-hidden">
<div className="flex items-center justify-center h-[100px] w-full bg-b1 px-3">
Unlocks at 6,000 downloads
Unlocks at 8,000 downloads
</div>
<h2 className="my-2 font-semibold text-center uppercase">
{_('Progress Bar')}
</h2>
{_('Tabs')}
Unlocks at 6,000 downloads
</div>
</div>
</div>
<div className="block basis-1/2 md:basis-1/3 text-center cursor-pointer">
Expand All @@ -234,6 +278,10 @@ export default function Home() {
<div className="block basis-1/2 md:basis-1/3 text-center cursor-pointer">
<div className="m-2 border border-b2 rounded overflow-hidden">
<div className="flex items-center justify-center h-[100px] w-full bg-b1 px-3">
Unlocks at 12,000 downloads
</div>
<h2 className="my-2 font-semibold text-center uppercase">
{_('Tooltip')}
Unlocks at 14,000 downloads
</div>
<h2 className="my-2 font-semibold text-center uppercase">
Expand Down
Loading