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:
Dan Ditomaso
2025-05-02 09:00:24 -04:00
committed by GitHub
parent 3eafad7261
commit 99711fc44e
78 changed files with 2764 additions and 2028 deletions
+77 -55
View File
@@ -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>
);
}