mirror of
https://github.com/Novattz/creamlinux-installer.git
synced 2026-01-29 14:52:51 -05:00
Initial changes
This commit is contained in:
59
src/components/buttons/ActionButton.tsx
Normal file
59
src/components/buttons/ActionButton.tsx
Normal file
@@ -0,0 +1,59 @@
|
||||
import { FC } from 'react'
|
||||
import Button, { ButtonVariant } from '../buttons/Button'
|
||||
|
||||
// Define available action types
|
||||
export type ActionType = 'install_cream' | 'uninstall_cream' | 'install_smoke' | 'uninstall_smoke'
|
||||
|
||||
interface ActionButtonProps {
|
||||
action: ActionType
|
||||
isInstalled: boolean
|
||||
isWorking: boolean
|
||||
onClick: () => void
|
||||
disabled?: boolean
|
||||
className?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized button for game installation actions
|
||||
*/
|
||||
const ActionButton: FC<ActionButtonProps> = ({
|
||||
action,
|
||||
isInstalled,
|
||||
isWorking,
|
||||
onClick,
|
||||
disabled = false,
|
||||
className = '',
|
||||
}) => {
|
||||
// Determine button text based on state
|
||||
const getButtonText = () => {
|
||||
if (isWorking) return 'Working...'
|
||||
|
||||
const isCream = action.includes('cream')
|
||||
const product = isCream ? 'CreamLinux' : 'SmokeAPI'
|
||||
|
||||
return isInstalled ? `Uninstall ${product}` : `Install ${product}`
|
||||
}
|
||||
|
||||
// Map to our button variant
|
||||
const getButtonVariant = (): ButtonVariant => {
|
||||
// For uninstall actions, use danger variant
|
||||
if (isInstalled) return 'danger'
|
||||
// For install actions, use success variant
|
||||
return 'success'
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant={getButtonVariant()}
|
||||
isLoading={isWorking}
|
||||
onClick={onClick}
|
||||
disabled={disabled || isWorking}
|
||||
fullWidth
|
||||
className={`action-button ${className}`}
|
||||
>
|
||||
{getButtonText()}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
export default ActionButton
|
||||
52
src/components/buttons/AnimatedCheckbox.tsx
Normal file
52
src/components/buttons/AnimatedCheckbox.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
interface AnimatedCheckboxProps {
|
||||
checked: boolean;
|
||||
onChange: () => void;
|
||||
label?: string;
|
||||
sublabel?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Animated checkbox component with optional label and sublabel
|
||||
*/
|
||||
const AnimatedCheckbox = ({
|
||||
checked,
|
||||
onChange,
|
||||
label,
|
||||
sublabel,
|
||||
className = '',
|
||||
}: AnimatedCheckboxProps) => {
|
||||
return (
|
||||
<label className={`animated-checkbox ${className}`}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={checked}
|
||||
onChange={onChange}
|
||||
className="checkbox-original"
|
||||
/>
|
||||
|
||||
<span className={`checkbox-custom ${checked ? 'checked' : ''}`}>
|
||||
<svg viewBox="0 0 24 24" className="checkmark-icon" aria-hidden="true">
|
||||
<path
|
||||
className={`checkmark ${checked ? 'checked' : ''}`}
|
||||
d="M5 12l5 5L20 7"
|
||||
stroke="#fff"
|
||||
strokeWidth="2.5"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
{(label || sublabel) && (
|
||||
<div className="checkbox-content">
|
||||
{label && <span className="checkbox-label">{label}</span>}
|
||||
{sublabel && <span className="checkbox-sublabel">{sublabel}</span>}
|
||||
</div>
|
||||
)}
|
||||
</label>
|
||||
)
|
||||
}
|
||||
|
||||
export default AnimatedCheckbox
|
||||
67
src/components/buttons/Button.tsx
Normal file
67
src/components/buttons/Button.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import { FC, ButtonHTMLAttributes } from 'react';
|
||||
|
||||
export type ButtonVariant = 'primary' | 'secondary' | 'danger' | 'success' | 'warning';
|
||||
export type ButtonSize = 'small' | 'medium' | 'large';
|
||||
|
||||
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
variant?: ButtonVariant;
|
||||
size?: ButtonSize;
|
||||
isLoading?: boolean;
|
||||
leftIcon?: React.ReactNode;
|
||||
rightIcon?: React.ReactNode;
|
||||
fullWidth?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Button component with different variants, sizes and states
|
||||
*/
|
||||
const Button: FC<ButtonProps> = ({
|
||||
children,
|
||||
variant = 'primary',
|
||||
size = 'medium',
|
||||
isLoading = false,
|
||||
leftIcon,
|
||||
rightIcon,
|
||||
fullWidth = false,
|
||||
className = '',
|
||||
disabled,
|
||||
...props
|
||||
}) => {
|
||||
// Size class mapping
|
||||
const sizeClass = {
|
||||
small: 'btn-sm',
|
||||
medium: 'btn-md',
|
||||
large: 'btn-lg',
|
||||
}[size];
|
||||
|
||||
// Variant class mapping
|
||||
const variantClass = {
|
||||
primary: 'btn-primary',
|
||||
secondary: 'btn-secondary',
|
||||
danger: 'btn-danger',
|
||||
success: 'btn-success',
|
||||
warning: 'btn-warning',
|
||||
}[variant];
|
||||
|
||||
return (
|
||||
<button
|
||||
className={`btn ${variantClass} ${sizeClass} ${fullWidth ? 'btn-full' : ''} ${
|
||||
isLoading ? 'btn-loading' : ''
|
||||
} ${className}`}
|
||||
disabled={disabled || isLoading}
|
||||
{...props}
|
||||
>
|
||||
{isLoading && (
|
||||
<span className="btn-spinner">
|
||||
<span className="spinner"></span>
|
||||
</span>
|
||||
)}
|
||||
|
||||
{leftIcon && !isLoading && <span className="btn-icon btn-icon-left">{leftIcon}</span>}
|
||||
<span className="btn-text">{children}</span>
|
||||
{rightIcon && !isLoading && <span className="btn-icon btn-icon-right">{rightIcon}</span>}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default Button;
|
||||
8
src/components/buttons/index.ts
Normal file
8
src/components/buttons/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
// Export all button components
|
||||
export { default as Button } from './Button';
|
||||
export { default as ActionButton } from './ActionButton';
|
||||
export { default as AnimatedCheckbox } from './AnimatedCheckbox';
|
||||
|
||||
// Export types
|
||||
export type { ButtonVariant, ButtonSize } from './Button';
|
||||
export type { ActionType } from './ActionButton';
|
||||
Reference in New Issue
Block a user