# Lovable UI 컴포넌트 정리

## 개요

Zellyy Finance 앱은 Flutter에서 React와 Tailwind CSS를 사용한 Capacitor 기반 웹 앱으로 전환되었으며, UI 디자인은 뉴모피즘 스타일의 Lovable UI 컴포넌트를 적용하여 차별화된 사용자 경험을 제공하고자 합니다. 이 문서는 Lovable UI 컴포넌트와 관련된 내용을 정리합니다.

## Lovable UI 컴포넌트 관련 문서

### 1. UI/UX 설계 문서에서의 Lovable UI

**위치**: `/01_기획_및_설계/02_UI_UX_설계.md`

**주요 내용**:
- **컴포넌트 라이브러리**: Lovable UI 컴포넌트 라이브러리 구축
- **뉴모피즘 스타일**: 입체적이고 부드러운 UI 디자인 적용
- **디자인 철학**: 웹 기반 기술과 Capacitor를 활용하여 다양한 플랫폼에서 일관된 사용자 경험을 제공하면서도, 뉴모피즘 스타일의 Lovable UI 컴포넌트를 통해 차별화된 디자인을 구현

### 2. 시스템 아키텍처 문서에서의 Lovable UI

**위치**: `/02_기술_문서/01_시스템_아키텍처.md`

**주요 내용**:
- **프레젠테이션 계층**: 뉴모피즘 스타일 UI 컴포넌트 적용

### 3. 개발 로드맵 문서에서의 Lovable UI

**위치**: `/03_개발_단계/01_개발_로드맵.md`

**주요 내용**:
- **개발 작업**: 뉴모피즘 스타일 UI 컴포넌트 개발 계획

### 4. README 문서에서의 Lovable UI

**위치**: `/README.md`

**주요 내용**:
- **변경 사항**: 2025-03-09: 개발 방법 변경 - Flutter에서 React, Tailwind CSS, Capacitor 기반 웹 앱으로 전환, Lovable UI 컴포넌트 스타일 적용

## 필요한 Lovable UI 컴포넌트 목록

Zellyy Finance 앱의 홈 화면을 Lovable UI 컴포넌트로 변경하는 작업을 진행 중입니다. 기존 홈 화면의 기능을 유지하면서 Lovable UI 디자인 시스템의 컴포넌트로 UI를 개선하려고 합니다.

### 주요 변경 사항
1. FloatingActionButton을 LovableAddTransactionButton으로 교체
2. 기존 Card를 LovableCard로 교체
3. 거래 내역 리스트 아이템을 LovableTransactionCard로 교체
4. 전체적인 UI 디자인을 뉴모피즘 스타일로 변경

### 필요한 컴포넌트
- **LovableButton**: 기본 버튼 컴포넌트
- **LovableCard**: 카드 컴포넌트
- **LovableTransactionCard**: 거래 내역 표시용 카드 컴포넌트
- **LovableAddTransactionButton**: 거래 추가용 플로팅 액션 버튼

### 홈 화면 파일 경로
`/Users/hansoo./Dev/Zellyy_Finance/neumofinance/src/pages/Home.tsx`

## 뉴모피즘 디자인 특징

뉴모피즘(Neumorphism)은 다음과 같은 특징을 가진 UI 디자인 스타일입니다:

1. **입체감**: 요소가 배경에서 살짝 튀어나온 것처럼 보이는 효과
2. **부드러운 그림자**: 요소의 위쪽과 왼쪽에는 밝은 그림자, 아래쪽과 오른쪽에는 어두운 그림자를 적용
3. **단일 색상 사용**: 배경과 요소가 비슷한 색상을 사용하여 미묘한 차이로 구분
4. **미니멀리즘**: 깔끔하고 단순한 디자인 요소 사용
5. **낮은 대비**: 강한 색상 대비보다는 미묘한 그림자와 하이라이트로 구분

## 구현 방향

1. **Tailwind CSS 활용**: 웹 기반 앱에서는 Tailwind CSS를 활용하여 뉴모피즘 효과 구현
2. **React 컴포넌트 모듈화**: 재사용 가능한 React 컴포넌트로 설계
3. **반응형 디자인**: 다양한 화면 크기에 대응하는 디자인 적용
4. **접근성 고려**: 시각적 효과가 접근성을 해치지 않도록 주의
5. **성능 최적화**: 그림자 효과 등이 성능에 영향을 미치지 않도록 최적화

## React 기반 Lovable UI 컴포넌트 구현

### 1. LovableButton 컴포넌트

```tsx
import React from 'react';
import { twMerge } from 'tailwind-merge';

interface LovableButtonProps {
  children: React.ReactNode;
  onClick?: () => void;
  className?: string;
  variant?: 'primary' | 'secondary' | 'outline';
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
}

const LovableButton: React.FC<LovableButtonProps> = ({
  children,
  onClick,
  className = '',
  variant = 'primary',
  size = 'md',
  disabled = false,
}) => {
  const baseStyles = 'rounded-xl font-medium transition-all duration-200 focus:outline-none';
  
  const variantStyles = {
    primary: 'bg-primary-100 text-primary-900 shadow-neumo hover:shadow-neumo-pressed active:shadow-neumo-pressed',
    secondary: 'bg-secondary-100 text-secondary-900 shadow-neumo hover:shadow-neumo-pressed active:shadow-neumo-pressed',
    outline: 'bg-transparent border-2 border-primary-200 text-primary-900 hover:bg-primary-50 active:bg-primary-100',
  };
  
  const sizeStyles = {
    sm: 'px-3 py-1 text-sm',
    md: 'px-4 py-2',
    lg: 'px-6 py-3 text-lg',
  };
  
  const disabledStyles = disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer';
  
  return (
    <button
      onClick={onClick}
      disabled={disabled}
      className={twMerge(
        baseStyles,
        variantStyles[variant],
        sizeStyles[size],
        disabledStyles,
        className
      )}
    >
      {children}
    </button>
  );
};

export default LovableButton;
```

### 2. LovableCard 컴포넌트

```tsx
import React from 'react';
import { twMerge } from 'tailwind-merge';

interface LovableCardProps {
  children: React.ReactNode;
  className?: string;
  onClick?: () => void;
  elevated?: boolean;
  pressed?: boolean;
}

const LovableCard: React.FC<LovableCardProps> = ({
  children,
  className = '',
  onClick,
  elevated = false,
  pressed = false,
}) => {
  const baseStyles = 'bg-primary-50 rounded-2xl p-4 transition-all duration-200';
  
  const shadowStyles = {
    default: 'shadow-neumo',
    elevated: 'shadow-neumo-elevated',
    pressed: 'shadow-neumo-pressed',
  };
  
  const selectedShadow = pressed ? shadowStyles.pressed : (elevated ? shadowStyles.elevated : shadowStyles.default);
  
  return (
    <div
      className={twMerge(
        baseStyles,
        selectedShadow,
        onClick ? 'cursor-pointer' : '',
        className
      )}
      onClick={onClick}
    >
      {children}
    </div>
  );
};

export default LovableCard;
```

### 3. LovableTransactionCard 컴포넌트

```tsx
import React from 'react';
import { twMerge } from 'tailwind-merge';
import LovableCard from './LovableCard';
import { formatCurrency } from '../utils/formatters';

interface TransactionType {
  id: string;
  title: string;
  amount: number;
  date: string;
  category: string;
  type: 'income' | 'expense';
}

interface LovableTransactionCardProps {
  transaction: TransactionType;
  className?: string;
  onClick?: () => void;
}

const LovableTransactionCard: React.FC<LovableTransactionCardProps> = ({
  transaction,
  className = '',
  onClick,
}) => {
  const { title, amount, date, category, type } = transaction;
  
  // 카테고리에 따른 아이콘 선택
  const getCategoryIcon = (category: string) => {
    switch (category.toLowerCase()) {
      case '식비':
        return '🍴';
      case '교통':
        return '🚗';
      case '쇼핑':
        return '🛍️';
      case '여가':
        return '⛲️';
      case '금융':
        return '💰';
      case '급여':
        return '💸';
      default:
        return '📃';
    }
  };
  
  const formattedDate = new Date(date).toLocaleDateString('ko-KR', {
    year: 'numeric',
    month: 'long',
    day: 'numeric',
  });
  
  return (
    <LovableCard
      className={twMerge('flex items-center justify-between', className)}
      onClick={onClick}
    >
      <div className="flex items-center">
        <div className="w-10 h-10 rounded-full bg-primary-100 flex items-center justify-center mr-3 shadow-neumo-sm">
          <span className="text-xl">{getCategoryIcon(category)}</span>
        </div>
        <div>
          <h3 className="font-medium text-primary-900">{title}</h3>
          <p className="text-sm text-primary-600">{formattedDate}</p>
        </div>
      </div>
      <div className={`font-bold ${type === 'income' ? 'text-green-600' : 'text-red-600'}`}>
        {type === 'income' ? '+' : '-'}{formatCurrency(amount)}
      </div>
    </LovableCard>
  );
};

export default LovableTransactionCard;
```

### 4. LovableAddTransactionButton 컴포넌트

```tsx
import React, { useState } from 'react';
import { twMerge } from 'tailwind-merge';

interface LovableAddTransactionButtonProps {
  onAddIncome?: () => void;
  onAddExpense?: () => void;
  className?: string;
}

const LovableAddTransactionButton: React.FC<LovableAddTransactionButtonProps> = ({
  onAddIncome,
  onAddExpense,
  className = '',
}) => {
  const [isOpen, setIsOpen] = useState(false);
  
  const toggleOpen = () => {
    setIsOpen(!isOpen);
  };
  
  const handleAddIncome = () => {
    if (onAddIncome) {
      onAddIncome();
    }
    setIsOpen(false);
  };
  
  const handleAddExpense = () => {
    if (onAddExpense) {
      onAddExpense();
    }
    setIsOpen(false);
  };
  
  return (
    <div className={twMerge('fixed bottom-6 right-6 z-50', className)}>
      {isOpen && (
        <div className="flex flex-col items-end mb-4 space-y-3">
          <button
            onClick={handleAddIncome}
            className="flex items-center bg-primary-50 text-green-600 px-4 py-2 rounded-xl shadow-neumo hover:shadow-neumo-pressed transition-all duration-200"
          >
            <span className="mr-2">💸</span>
            <span>수입 추가</span>
          </button>
          <button
            onClick={handleAddExpense}
            className="flex items-center bg-primary-50 text-red-600 px-4 py-2 rounded-xl shadow-neumo hover:shadow-neumo-pressed transition-all duration-200"
          >
            <span className="mr-2">💳</span>
            <span>지출 추가</span>
          </button>
        </div>
      )}
      <button
        onClick={toggleOpen}
        className={`w-14 h-14 rounded-full bg-primary-100 text-primary-900 flex items-center justify-center shadow-neumo-elevated hover:shadow-neumo transition-all duration-300 ${isOpen ? 'rotate-45' : ''}`}
      >
        <span className="text-2xl font-bold">+</span>
      </button>
    </div>
  );
};

export default LovableAddTransactionButton;
```

### 5. Tailwind CSS 구성

```ts
// tailwind.config.ts
import type { Config } from 'tailwindcss';

const config: Config = {
  content: [
    './src/pages/**/*.{js,ts,jsx,tsx,mdx}',
    './src/components/**/*.{js,ts,jsx,tsx,mdx}',
    './src/app/**/*.{js,ts,jsx,tsx,mdx}',
  ],
  theme: {
    extend: {
      colors: {
        primary: {
          50: '#f5f7fa',
          100: '#e4e7eb',
          200: '#cbd2d9',
          300: '#9aa5b1',
          400: '#7b8794',
          500: '#616e7c',
          600: '#52606d',
          700: '#3e4c59',
          800: '#323f4b',
          900: '#1f2933',
        },
        secondary: {
          50: '#e3f8ff',
          100: '#b3ecff',
          200: '#81defd',
          300: '#5ed0fa',
          400: '#40c3f7',
          500: '#2bb0ed',
          600: '#1992d4',
          700: '#127fbf',
          800: '#0b69a3',
          900: '#035388',
        },
      },
      boxShadow: {
        'neumo': '5px 5px 10px #d1d9e6, -5px -5px 10px #ffffff',
        'neumo-sm': '3px 3px 6px #d1d9e6, -3px -3px 6px #ffffff',
        'neumo-pressed': 'inset 5px 5px 10px #d1d9e6, inset -5px -5px 10px #ffffff',
        'neumo-elevated': '10px 10px 20px #d1d9e6, -10px -10px 20px #ffffff',
      },
    },
  },
  plugins: [],
};

export default config;
```

## 결론

Lovable UI 컴포넌트는 Zellyy Finance 앱의 차별화된 사용자 경험을 제공하기 위한 핵심 요소입니다. Flutter에서 React와 Tailwind CSS를 사용한 웹 기반 앱으로 전환하면서, 뉴모피즘 스타일을 적용하여 입체적이고 부드러운 디자인을 구현하였습니다.

React의 컴포넌트 기반 아키텍처와 Tailwind CSS의 유틸리티 클래스를 활용하여 재사용 가능한 컴포넌트를 구축함으로써, 개발 효율성을 높이고 일관된 사용자 경험을 제공할 수 있습니다. 특히 커스텀 그림자 효과를 활용한 뉴모피즘 스타일은 사용자에게 매력적인 인터페이스를 제공합니다.

이러한 Lovable UI 컴포넌트 라이브러리는 앞으로도 지속적으로 개선되고 확장될 예정이며, 사용자 피드백을 반영하여 더욱 향상된 경험을 제공할 계획입니다. 이를 통해 Zellyy Finance 앱은 사용자에게 차별화된 가치를 제공하고, 재무 관리에 도움이 되는 유용한 도구로 자리매김할 것입니다.
