Skip to content

KernButtons shared components #39

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 28, 2025
Merged
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
61 changes: 61 additions & 0 deletions components/kern-button/ButtonAsText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { combineClassNames } from "@/submodules/javascript-functions/general";
import { useMemo } from "react";

export type ButtonAsTextProps = {
text: string;
color?: string;
onClick?: () => void;
disabled?: boolean;
iconLeft?: (props: any) => React.ReactNode;
iconRight?: (props: any) => React.ReactNode;
iconColor?: string;
size?: 'small' | 'medium' | 'large';
className?: string;
}

export default function ButtonAsText(props: ButtonAsTextProps) {
const classCombined = useMemo(() => combineClassNames(
'disabled:text-gray-400 disabled:cursor-not-allowed flex items-center space-x-1',
props.className,
props.color ? (
`text-${props.color}-600 hover:text-${props.color}-900`
) : (
'text-gray-600 hover:text-gray-900'
)
), [props.color]);

return (
<button
className={classCombined}
disabled={props.disabled}
onClick={props.onClick}>
{props.iconLeft && <props.iconLeft className={combineClassNames(
`text-${props.iconColor}-500 group-hover:text-${props.iconColor}-600`,
props.size == 'small' ? (
'w-4 h-4'
) : (
props.size == 'large' ? (
'w-6 h-6'
) : (
'w-5 h-5'
)
)
)} />}
<span>
{props.text}
</span>
<span className="sr-only">,{props.text}</span>
{props.iconRight && <props.iconRight className={combineClassNames(
`text-${props.iconColor}-500 group-hover:text-${props.iconColor}-600`,
props.size == 'small' ? (
'w-4 h-4'
) : (
props.size == 'large' ? (
'w-6 h-6'
) : (
'w-5 h-5'
)
)
)} />}
</button >)
}
103 changes: 103 additions & 0 deletions components/kern-button/IconButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { combineClassNames } from "@/submodules/javascript-functions/general";
import { Tooltip } from '@nextui-org/react'
import { IconCheck } from "@tabler/icons-react";
import { useState } from "react";

interface IconButtonProps {
icon: (props: any) => React.ReactNode;
iconColor?: string;
onClick?: (e?: any) => void;
buttonColor?: string;
disabled?: boolean;
keepOpacity?: boolean;
size?: 'small' | 'medium' | 'large';
tooltip?: string;
tooltipPlacement?: 'top' | 'bottom' | 'left' | 'right';
confirm?: boolean;
onMouseDown?: (e?: any) => void;
className?: string;
}

function InnerButton(props: IconButtonProps) {
const [confirmed, setConfirmed] = useState<boolean>(false);

return (
<button
onClick={(e?: any) => {
if (props.onClick) props.onClick(e);
if (props.confirm) {
setConfirmed(true);
setTimeout(() => {
setConfirmed(false);
}, 3000);
}
}}
onMouseDown={props.onMouseDown ? props.onMouseDown : undefined}
className={
combineClassNames(
'text-sm group flex items-center justify-center rounded-md h-fit hover:shadow-sm transition duration-200 ease-in-out disabled:cursor-not-allowed',
props.className,
props.keepOpacity ? '' : (
'disabled:opacity-50 '
),
props.buttonColor ? (
`border border-${props.buttonColor}-300 bg-${props.buttonColor}-50 hover:bg-${props.buttonColor}-100 hover:border-${props.buttonColor}-400 active:bg-${props.buttonColor}-200 active:border-${props.buttonColor}-500`
) : (
'border bg-white border-gray-200 hover:bg-gray-50 hover:border-gray-300 active:bg-gray-100 active:border-gray-400'
),
props.size == 'small' ? (
'p-1'
) : (
props.size == 'large' ? (
'p-2'
) : (
'p-1.5'
)
)
)
}
disabled={props.disabled}
>
{confirmed ? (
<IconCheck
className={combineClassNames(
`text-green-500 group-hover:text-green-600`,
props.size == 'small' ? (
'w-4 h-4'
) : (
props.size == 'large' ? (
'w-6 h-6'
) : (
'w-5 h-5'
)
)
)}
/>
) : (
<props.icon className={combineClassNames(
`text-${props.iconColor}-500 group-hover:text-${props.iconColor}-600`,
props.size == 'small' ? (
'w-4 h-4'
) : (
props.size == 'large' ? (
'w-6 h-6'
) : (
'w-5 h-5'
)
)
)} />
)}

</button>
)
}

export default function IconButton(props: IconButtonProps) {
return props.disabled ? (
<InnerButton {...props} />
) : (
<Tooltip color="invert" content={props.tooltip} placement={props.tooltipPlacement || "bottom"} >
<InnerButton {...props} />
</Tooltip>
)
}
2 changes: 2 additions & 0 deletions components/kern-button/KernButton.tsx
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@ interface KernButtonProps {
tooltip?: string;
tooltipPlacement?: 'top' | 'bottom' | 'left' | 'right';
confirm?: boolean;
className?: string;
}

export default function KernButton(props: KernButtonProps) {
@@ -44,6 +45,7 @@ export default function KernButton(props: KernButtonProps) {
className={
combineClassNames(
'text-sm group flex gap-x-2 items-center rounded-md hover:shadow-sm transition duration-200 ease-in-out disabled:opacity-50 disabled:cursor-not-allowed',
props.className,
props.buttonColor ? (
props.solidTheme ? (
`border border-${props.buttonColor}-600 bg-${props.buttonColor}-600 hover:bg-${props.buttonColor}-600 active:bg-${props.buttonColor}-600 active:border-${props.buttonColor}-600`
5 changes: 3 additions & 2 deletions components/kern-button/SaveButton.tsx
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ type SaveButtonProps = {
tooltipPlacement?: 'top' | 'bottom' | 'left' | 'right';
confirm?: boolean;
warningCue?: any
className?: string;
}

export default function SaveButton(props: SaveButtonProps) {
@@ -47,8 +48,8 @@ export default function SaveButton(props: SaveButtonProps) {

const sizeClasses: string = useMemo(() => getSizeClasses(props.size), [props.size]);

const buttonClasses = useMemo(() => combineClassNames("flex gap-x-1 items-center hover:shadow-sm rounded-lg px-2 py-1", disabledClasses, buttonColorClasses, widthClasses, heightClasses, props.warningCue && buttonWarningColorClasses),
[disabledClasses, buttonColorClasses, widthClasses, heightClasses, props.warningCue]);
const buttonClasses = useMemo(() => combineClassNames("flex gap-x-1 items-center hover:shadow-sm rounded-lg px-2 py-1", disabledClasses, buttonColorClasses, widthClasses, heightClasses, props.warningCue && buttonWarningColorClasses, props.className),
[disabledClasses, buttonColorClasses, widthClasses, heightClasses, props.warningCue, props.className]);

return (
<div className='text-sm group flex items-center rounded-md transition duration-200 ease-in-out' >