Feature pack: Media, Gamification, Templates, Time Tracking, Kanban, AI Briefing, Webhooks, Icon UI
API features (separate files in /api/src/features/): - media-input: upload text/audio/photo/video, transcription - gamification: points, streaks, badges, leaderboard - templates: predefined task sets (sprint, study, moving) - time-tracking: start/stop timer, task/user reports - kanban: board view, drag-and-drop move - ai-briefing: daily AI summary with tasks/goals/reviews - webhooks-outgoing: notify external systems on events UI components (separate files in /components/features/): - IconButton: icon-only buttons with tooltip - CompactHeader, PageActionBar, InlineEditField - TaskDetailActions, GoalActionButtons, CollabActionButtons - DeleteIconButton, CollabBackButton All features modular — registry.js enables/disables each one. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
52
apps/tasks/components/features/IconButton.tsx
Normal file
52
apps/tasks/components/features/IconButton.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
'use client';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
interface Props {
|
||||
icon: ReactNode;
|
||||
label: string;
|
||||
onClick?: () => void;
|
||||
className?: string;
|
||||
variant?: 'default' | 'danger' | 'success' | 'primary' | 'warning' | 'purple';
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
disabled?: boolean;
|
||||
type?: 'button' | 'submit';
|
||||
}
|
||||
|
||||
const variants: Record<string, string> = {
|
||||
default: 'bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300',
|
||||
danger: 'bg-red-100 dark:bg-red-900/30 hover:bg-red-200 dark:hover:bg-red-800/40 text-red-600 dark:text-red-400',
|
||||
success: 'bg-green-100 dark:bg-green-900/30 hover:bg-green-200 dark:hover:bg-green-800/40 text-green-600 dark:text-green-400',
|
||||
primary: 'bg-blue-100 dark:bg-blue-900/30 hover:bg-blue-200 dark:hover:bg-blue-800/40 text-blue-600 dark:text-blue-400',
|
||||
warning: 'bg-yellow-100 dark:bg-yellow-900/30 hover:bg-yellow-200 dark:hover:bg-yellow-800/40 text-yellow-600 dark:text-yellow-400',
|
||||
purple: 'bg-purple-100 dark:bg-purple-900/30 hover:bg-purple-200 dark:hover:bg-purple-800/40 text-purple-600 dark:text-purple-400',
|
||||
};
|
||||
|
||||
const sizes: Record<string, string> = {
|
||||
sm: 'w-8 h-8 text-sm',
|
||||
md: 'w-10 h-10 text-base',
|
||||
lg: 'w-12 h-12 text-lg',
|
||||
};
|
||||
|
||||
export default function IconButton({
|
||||
icon,
|
||||
label,
|
||||
onClick,
|
||||
className,
|
||||
variant = 'default',
|
||||
size = 'md',
|
||||
disabled,
|
||||
type = 'button',
|
||||
}: Props) {
|
||||
return (
|
||||
<button
|
||||
type={type}
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
title={label}
|
||||
aria-label={label}
|
||||
className={`inline-flex items-center justify-center rounded-lg transition-colors cursor-pointer ${variants[variant] || variants.default} ${sizes[size] || sizes.md} ${className || ''} ${disabled ? 'opacity-50 cursor-not-allowed' : ''}`}
|
||||
>
|
||||
{icon}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user