Remove duplicate node logic, UI Update, flatten build output (#586)
* refactor nodes to getNodes fn. ui updates * fixed several styling issues * fix: message specific styling/overflow * added footer, fixed tests. styling * fix: added theme support back to app component * fix: hide emojis/reactions * fix: added more padding to content element * fix: fixed padding in content element * updated color scheme * fix: more dark mode styling improvements * fix: padding and alignment fixes * fix: prevent left sidebar collapse, added battery component * fix: change scrollbars to "tiny" style, improved message scrolling, fixed bug with message input * message store fixes, ui fixes * fix: disabled message persistance until after release
This commit is contained in:
+77
-55
@@ -1,16 +1,16 @@
|
||||
import * as React from "react";
|
||||
import { cn } from "@core/utils/cn.ts";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { Check, Copy, Eye, EyeOff, type LucideIcon } from "lucide-react";
|
||||
import { Check, Copy, Eye, EyeOff, X, type LucideIcon } from "lucide-react";
|
||||
import { useCopyToClipboard } from "@core/hooks/useCopyToClipboard.ts";
|
||||
import { usePasswordVisibilityToggle } from "@core/hooks/usePasswordVisibilityToggle.ts";
|
||||
|
||||
const inputVariants = cva(
|
||||
"flex h-10 w-full rounded-md border border-slate-300 bg-transparent py-2 px-3 text-sm placeholder:text-slate-400 focus:outline-none focus:ring-1 focus:ring-slate-400 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-700 dark:text-slate-100 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-600",
|
||||
"flex h-10 w-full rounded-md border border-slate-300 bg-transparent py-2 px-3 text-sm placeholder:text-slate-400 focus:outline-none focus:ring-1 focus:ring-slate-400 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-500 dark:bg-transparet dark:text-slate-100 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-600",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "border-slate-300 dark:border-slate-700",
|
||||
default: "border-slate-300 dark:border-slate-500",
|
||||
invalid:
|
||||
"border-red-500 dark:border-red-500 focus:ring-red-500 dark:focus:ring-red-500",
|
||||
},
|
||||
@@ -26,7 +26,8 @@ type InputActionType = {
|
||||
icon: LucideIcon;
|
||||
onClick: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
||||
ariaLabel: string;
|
||||
tooltip?: string;
|
||||
tooltip?: string
|
||||
condition?: boolean;
|
||||
};
|
||||
|
||||
export interface InputProps
|
||||
@@ -36,6 +37,7 @@ export interface InputProps
|
||||
suffix?: React.ReactNode;
|
||||
showPasswordToggle?: boolean;
|
||||
showCopyButton?: boolean;
|
||||
showClearButton?: boolean;
|
||||
containerClassName?: string;
|
||||
}
|
||||
|
||||
@@ -50,7 +52,9 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
suffix,
|
||||
showPasswordToggle,
|
||||
showCopyButton,
|
||||
showClearButton,
|
||||
value,
|
||||
onChange,
|
||||
...props
|
||||
},
|
||||
ref
|
||||
@@ -58,10 +62,28 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
const { isVisible, toggleVisibility } = usePasswordVisibilityToggle();
|
||||
const { copy, isCopied } = useCopyToClipboard({ timeout: 1500 });
|
||||
|
||||
const actions: InputActionType[] = [];
|
||||
|
||||
if (showPasswordToggle && type === "password") {
|
||||
actions.push({
|
||||
const potentialActions: InputActionType[] = [
|
||||
{
|
||||
id: "clear-input",
|
||||
icon: X,
|
||||
onClick: (e) => {
|
||||
e.stopPropagation();
|
||||
if (onChange) {
|
||||
const event = {
|
||||
target: { value: "" },
|
||||
currentTarget: { value: "" },
|
||||
} as React.ChangeEvent<HTMLInputElement>;
|
||||
onChange(event);
|
||||
}
|
||||
if (ref && typeof ref !== "function" && ref.current) {
|
||||
ref.current.focus();
|
||||
}
|
||||
},
|
||||
ariaLabel: "Clear input",
|
||||
tooltip: "Clear input",
|
||||
condition: !!showClearButton && !!value,
|
||||
},
|
||||
{
|
||||
id: "toggle-visibility",
|
||||
icon: isVisible ? EyeOff : Eye,
|
||||
onClick: (e) => {
|
||||
@@ -70,10 +92,9 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
},
|
||||
ariaLabel: isVisible ? "Hide password" : "Show password",
|
||||
tooltip: isVisible ? "Hide password" : "Show password",
|
||||
});
|
||||
}
|
||||
if (showCopyButton) {
|
||||
actions.push({
|
||||
condition: !!showPasswordToggle && type === "password",
|
||||
},
|
||||
{
|
||||
id: "copy-value",
|
||||
icon: isCopied ? Check : Copy,
|
||||
onClick: (e) => {
|
||||
@@ -84,10 +105,14 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
},
|
||||
ariaLabel: isCopied ? "Copied!" : "Copy to clipboard",
|
||||
tooltip: isCopied ? "Copied!" : "Copy to clipboard",
|
||||
});
|
||||
}
|
||||
condition: !!showCopyButton,
|
||||
},
|
||||
];
|
||||
|
||||
const inputType = showPasswordToggle ? (isVisible ? "text" : "password") : type;
|
||||
const actions = potentialActions.filter(action => action.condition);
|
||||
|
||||
const inputType =
|
||||
showPasswordToggle ? (isVisible ? "text" : "password") : type;
|
||||
|
||||
const hasPrefix = !!prefix;
|
||||
const hasSuffix = !!suffix;
|
||||
@@ -95,16 +120,15 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
|
||||
const inputClassName = cn(
|
||||
inputVariants({ variant }),
|
||||
hasActions && !hasSuffix && "pr-10",
|
||||
hasPrefix && "rounded-l-none",
|
||||
(hasSuffix || hasActions) && "rounded-r-none border-r-0",
|
||||
className
|
||||
);
|
||||
|
||||
|
||||
return (
|
||||
<div className={cn("relative flex w-full items-stretch", containerClassName)}>
|
||||
{prefix && (
|
||||
<span className="inline-flex items-center rounded-l-md border border-slate-300 bg-slate-100/80 px-3 text-sm text-slate-600 dark:border-slate-700 dark:bg-slate-700 dark:text-slate-300">
|
||||
<span className="inline-flex items-center rounded-l-md border border-r-0 border-slate-300 bg-slate-100/80 px-3 text-sm text-slate-600 dark:border-slate-700 dark:bg-slate-200 dark:text-slate-700">
|
||||
{prefix}
|
||||
</span>
|
||||
)}
|
||||
@@ -114,46 +138,44 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
className={inputClassName}
|
||||
ref={ref}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
{...props}
|
||||
/>
|
||||
|
||||
{(hasSuffix || hasActions) && (
|
||||
<div className={cn(
|
||||
"flex items-stretch",
|
||||
!hasSuffix && hasActions && "border-y border-r border-slate-300 dark:border-slate-700 rounded-r-md"
|
||||
)}>
|
||||
{suffix && (
|
||||
<span className={cn(
|
||||
"inline-flex items-center border border-slate-300 bg-slate-100/80 px-3 text-sm text-slate-600 dark:border-slate-700 dark:bg-slate-700 dark:text-slate-300",
|
||||
!hasActions && "rounded-r-md"
|
||||
)}>
|
||||
{suffix}
|
||||
</span>
|
||||
)}
|
||||
{actions.length > 0 && (
|
||||
<div className={cn(
|
||||
"flex h-full items-center divide-x divide-slate-300 dark:divide-slate-700",
|
||||
!hasSuffix && "border-l border-slate-300 dark:border-slate-700"
|
||||
)}>
|
||||
{actions?.map((action) => (
|
||||
<button
|
||||
key={action.id}
|
||||
type="button"
|
||||
className={cn(
|
||||
"inline-flex h-full items-center justify-center px-2.5 text-slate-500 hover:bg-slate-100 hover:text-slate-700 focus:outline-none focus:ring-1 focus:ring-slate-400 focus:ring-offset-0 dark:text-slate-400 dark:hover:bg-slate-700 dark:hover:text-slate-200 dark:focus:ring-slate-500",
|
||||
action.id === 'copy-value' && isCopied && "text-green-600 dark:text-green-500"
|
||||
)}
|
||||
onClick={action.onClick}
|
||||
aria-label={action.ariaLabel}
|
||||
title={action.tooltip || action.ariaLabel}
|
||||
>
|
||||
<action.icon size={18} aria-hidden="true" />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="absolute right-0 top-0 flex h-full items-stretch">
|
||||
{suffix && (
|
||||
<span className={cn(
|
||||
"inline-flex items-center border border-l-0 border-slate-300 bg-slate-100/80 px-3 text-sm text-slate-600 dark:border-slate-700 dark:bg-slate-700 dark:text-slate-300",
|
||||
!hasActions && "rounded-r-md"
|
||||
)}>
|
||||
{suffix}
|
||||
</span>
|
||||
)}
|
||||
|
||||
{hasActions && (
|
||||
<div className={cn(
|
||||
"flex items-center divide-x divide-slate-300 border border-l-0 border-slate-300 dark:divide-slate-700 dark:border-slate-700",
|
||||
!hasSuffix && "rounded-r-md",
|
||||
"bg-white dark:bg-slate-800"
|
||||
)}>
|
||||
{actions.map((action) => (
|
||||
<button
|
||||
key={action.id}
|
||||
type="button"
|
||||
className={cn(
|
||||
"inline-flex h-full items-center justify-center px-2.5 text-slate-500 hover:bg-slate-100 hover:text-slate-700 focus:outline-none focus:ring-1 focus:ring-slate-400 focus:ring-offset-0 dark:text-slate-400 dark:hover:bg-slate-700 dark:hover:text-slate-200 dark:focus:ring-slate-500 hover:rounded-md dark:hover:rounded-md",
|
||||
action.id === 'copy-value' && isCopied && "text-green-600 dark:text-green-500"
|
||||
)}
|
||||
onClick={action.onClick}
|
||||
aria-label={action.ariaLabel}
|
||||
title={action.tooltip || action.ariaLabel}
|
||||
>
|
||||
<action.icon size={18} aria-hidden="true" />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user