> ## Documentation Index
> Fetch the complete documentation index at: https://docs.adrop.io/llms.txt
> Use this file to discover all available pages before exploring further.

# 팝업 광고

> iOS 앱에서 팝업 광고를 구현하는 방법을 안내합니다.

## 개요

팝업 광고(Popup Ad)는 특정 순간에 화면에 나타나는 광고 포맷입니다. 앱 실행 시, 콘텐츠 로드 완료 시, 특정 이벤트 발생 시 등 원하는 타이밍에 표시할 수 있으며, 사용자가 닫기 버튼을 누르거나 "오늘 하루 보지 않기"를 선택하여 종료할 수 있습니다.

### 특징

* 화면 중앙 또는 하단에 표시되는 팝업 형태
* 이미지 및 동영상 광고 지원
* 닫기, 딤(배경) 클릭, "오늘 하루 보지 않기" 옵션 제공
* 배경색, 텍스트 색상 등 커스터마이징 가능
* 사용자 경험을 해치지 않으면서도 효과적인 광고 경험

<Note>
  개발 환경에서는 테스트 유닛 ID를 사용하세요. [테스트 유닛 ID](#테스트-유닛-id) 섹션을 참고하세요.
</Note>

***

## 구현 단계

팝업 광고는 다음 4단계로 구현합니다:

1. **초기화** - AdropPopupAd 인스턴스 생성
2. **Delegate 설정** - 광고 및 닫기 이벤트 수신을 위한 Delegate 설정
3. **광고 로드** - 광고 요청 및 수신
4. **광고 표시** - 화면에 광고 표시

***

## UIKit 구현

### 기본 구현

<CodeGroup>
  ```swift Swift theme={null}
  import AdropAds

  class ViewController: UIViewController {
      private var popupAd: AdropPopupAd?

      override func viewDidLoad() {
          super.viewDidLoad()
          loadPopupAd()
      }

      // 1. 광고 초기화 및 로드
      private func loadPopupAd() {
          popupAd = AdropPopupAd(unitId: "YOUR_POPUP_UNIT_ID")
          popupAd?.delegate = self
          popupAd?.closeDelegate = self
          popupAd?.load()
      }

      // 2. 광고 표시
      private func showPopupAd() {
          guard let popupAd = popupAd,
                popupAd.isLoaded else { return }
          popupAd.show(fromRootViewController: self)
      }
  }
  ```

  ```objc Objective-C theme={null}
  @import AdropAds;

  @interface ViewController () <AdropPopupAdDelegate, AdropPopupAdCloseDelegate>
  @property (nonatomic, strong) AdropPopupAd *popupAd;
  @end

  @implementation ViewController

  - (void)viewDidLoad {
      [super viewDidLoad];
      [self loadPopupAd];
  }

  // 1. 광고 초기화 및 로드
  - (void)loadPopupAd {
      self.popupAd = [[AdropPopupAd alloc] initWithUnitId:@"YOUR_POPUP_UNIT_ID"];
      self.popupAd.delegate = self;
      self.popupAd.closeDelegate = self;
      [self.popupAd load];
  }

  // 2. 광고 표시
  - (void)showPopupAd {
      if (self.popupAd && self.popupAd.isLoaded) {
          [self.popupAd showFromRootViewController:self];
      }
  }

  @end
  ```
</CodeGroup>

### Delegate 구현

<CodeGroup>
  ```swift Swift theme={null}
  // 광고 Delegate 구현
  extension ViewController: AdropPopupAdDelegate {
      // 광고 수신 성공 (필수)
      func onAdReceived(_ ad: AdropPopupAd) {
          print("팝업 광고 수신 완료")
          // 광고가 준비되면 표시
          showPopupAd()
      }

      // 광고 수신 실패 (필수)
      func onAdFailedToReceive(_ ad: AdropPopupAd, _ errorCode: AdropErrorCode) {
          print("팝업 광고 수신 실패: \(errorCode)")
      }

      // 광고 노출 (선택)
      func onAdImpression(_ ad: AdropPopupAd) {
          print("팝업 광고 노출")
      }

      // 광고 클릭 (선택)
      func onAdClicked(_ ad: AdropPopupAd) {
          print("팝업 광고 클릭")
      }

      // 팝업 광고가 표시되기 직전 (선택)
      func onAdWillPresentFullScreen(_ ad: AdropPopupAd) {
          print("팝업 광고 표시 직전")
      }

      // 팝업 광고가 표시된 직후 (선택)
      func onAdDidPresentFullScreen(_ ad: AdropPopupAd) {
          print("팝업 광고 표시 완료")
      }

      // 팝업 광고가 닫히기 직전 (선택)
      func onAdWillDismissFullScreen(_ ad: AdropPopupAd) {
          print("팝업 광고 닫히기 직전")
      }

      // 팝업 광고가 닫힌 직후 (선택)
      func onAdDidDismissFullScreen(_ ad: AdropPopupAd) {
          print("팝업 광고 닫힘")
          // 다음 광고를 미리 로드
          loadPopupAd()
      }

      // 팝업 광고 표시 실패 (선택)
      func onAdFailedToShowFullScreen(_ ad: AdropPopupAd, _ errorCode: AdropErrorCode) {
          print("팝업 광고 표시 실패: \(errorCode)")
      }
  }

  // 닫기 Delegate 구현
  extension ViewController: AdropPopupAdCloseDelegate {
      // 닫기 버튼 클릭 (선택)
      func onClosed(_ ad: AdropPopupAd) {
          print("팝업 광고 닫기 버튼 클릭")
      }

      // 딤(배경) 클릭 (선택)
      func onDimClicked(_ ad: AdropPopupAd) {
          print("팝업 광고 딤 영역 클릭")
      }

      // "오늘 하루 보지 않기" 클릭 (선택)
      func onTodayOffClicked(_ ad: AdropPopupAd) {
          print("오늘 하루 보지 않기 선택")
          // SDK가 자동으로 오늘 하루 숨김 처리를 합니다.
          // 이 콜백은 분석 로깅이나 커스텀 UI 업데이트에 활용하세요.
      }
  }
  ```

  ```objc Objective-C theme={null}
  #pragma mark - AdropPopupAdDelegate

  // 광고 수신 성공 (필수)
  - (void)onAdReceived:(AdropPopupAd *)ad {
      NSLog(@"팝업 광고 수신 완료");
      // 광고가 준비되면 표시
      [self showPopupAd];
  }

  // 광고 수신 실패 (필수)
  - (void)onAdFailedToReceive:(AdropPopupAd *)ad :(AdropErrorCode)errorCode {
      NSLog(@"팝업 광고 수신 실패: %ld", (long)errorCode);
  }

  // 광고 노출 (선택)
  - (void)onAdImpression:(AdropPopupAd *)ad {
      NSLog(@"팝업 광고 노출");
  }

  // 광고 클릭 (선택)
  - (void)onAdClicked:(AdropPopupAd *)ad {
      NSLog(@"팝업 광고 클릭");
  }

  // 팝업 광고가 닫힌 직후 (선택)
  - (void)onAdDidDismissFullScreen:(AdropPopupAd *)ad {
      NSLog(@"팝업 광고 닫힘");
      // 다음 광고를 미리 로드
      [self loadPopupAd];
  }

  #pragma mark - AdropPopupAdCloseDelegate

  // 닫기 버튼 클릭 (선택)
  - (void)onClosed:(AdropPopupAd *)ad {
      NSLog(@"팝업 광고 닫기 버튼 클릭");
  }

  // 딤(배경) 클릭 (선택)
  - (void)onDimClicked:(AdropPopupAd *)ad {
      NSLog(@"팝업 광고 딤 영역 클릭");
  }

  // "오늘 하루 보지 않기" 클릭 (선택)
  - (void)onTodayOffClicked:(AdropPopupAd *)ad {
      NSLog(@"오늘 하루 보지 않기 선택");
      // SDK가 자동으로 오늘 하루 숨김 처리를 합니다.
      // 이 콜백은 분석 로깅이나 커스텀 UI 업데이트에 활용하세요.
  }
  ```
</CodeGroup>

***

## SwiftUI 구현

SwiftUI에서는 `UIViewControllerRepresentable`을 사용하거나, UIWindow에서 rootViewController를 가져와 표시할 수 있습니다.

### ViewModel 패턴

```swift theme={null}
import SwiftUI
import AdropAds

// ViewModel
class PopupAdViewModel: ObservableObject {
    @Published var isAdReady = false
    @Published var isAdShowing = false

    private var popupAd: AdropPopupAd?

    init() {
        loadAd()
    }

    func loadAd() {
        popupAd = AdropPopupAd(unitId: "YOUR_POPUP_UNIT_ID")
        popupAd?.delegate = self
        popupAd?.closeDelegate = self
        popupAd?.load()
    }

    func showAd() {
        guard let popupAd = popupAd,
              let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
              let rootViewController = windowScene.windows.first?.rootViewController else {
            return
        }

        popupAd.show(fromRootViewController: rootViewController)
    }

}

// 광고 Delegate
extension PopupAdViewModel: AdropPopupAdDelegate {
    func onAdReceived(_ ad: AdropPopupAd) {
        DispatchQueue.main.async {
            self.isAdReady = true
        }
    }

    func onAdFailedToReceive(_ ad: AdropPopupAd, _ errorCode: AdropErrorCode) {
        print("광고 수신 실패: \(errorCode)")
    }

    func onAdDidPresentFullScreen(_ ad: AdropPopupAd) {
        DispatchQueue.main.async {
            self.isAdShowing = true
        }
    }

    func onAdDidDismissFullScreen(_ ad: AdropPopupAd) {
        DispatchQueue.main.async {
            self.isAdShowing = false
            self.isAdReady = false
        }
        // 다음 광고 미리 로드
        loadAd()
    }
}

// 닫기 Delegate
extension PopupAdViewModel: AdropPopupAdCloseDelegate {
    func onClosed(_ ad: AdropPopupAd) {
        print("팝업 광고 닫기")
    }

    func onDimClicked(_ ad: AdropPopupAd) {
        print("팝업 광고 딤 클릭")
    }

    func onTodayOffClicked(_ ad: AdropPopupAd) {
        print("오늘 하루 보지 않기 선택")
        // SDK가 자동으로 오늘 하루 숨김 처리를 합니다.
        // 이 콜백은 분석 로깅이나 커스텀 UI 업데이트에 활용하세요.
    }
}

// View
struct ContentView: View {
    @StateObject private var adViewModel = PopupAdViewModel()

    var body: some View {
        VStack {
            Text("팝업 광고 예제")
                .font(.title)

            Button("팝업 광고 표시") {
                adViewModel.showAd()
            }
            .disabled(!adViewModel.isAdReady)
            .padding()
        }
        .onAppear {
            // 앱 시작 시 자동 표시
            if adViewModel.isAdReady {
                adViewModel.showAd()
            }
        }
    }
}
```

***

## 커스터마이징

팝업 광고의 외형을 커스터마이징할 수 있습니다.

### 배경색 및 텍스트 색상 설정

```swift theme={null}
private func loadPopupAd() {
    popupAd = AdropPopupAd(unitId: "YOUR_POPUP_UNIT_ID")
    popupAd?.delegate = self
    popupAd?.closeDelegate = self

    // 배경색 설정
    popupAd?.backgroundColor = UIColor.black.withAlphaComponent(0.8)

    // "오늘 하루 보지 않기" 텍스트 색상
    popupAd?.hideForTodayTextColor = UIColor.white

    // 닫기 버튼 텍스트 색상
    popupAd?.closeTextColor = UIColor.white

    // CTA 버튼 텍스트 색상
    popupAd?.ctaTextColor = UIColor.white

    popupAd?.load()
}
```

### 커스터마이징 옵션

| 속성                      | 타입         | 설명                            | 기본값   |
| ----------------------- | ---------- | ----------------------------- | ----- |
| `backgroundColor`       | `UIColor?` | 액션 바 배경색                      | `nil` |
| `hideForTodayTextColor` | `UIColor?` | "오늘 하루 보지 않기" 텍스트 색상          | 흰색    |
| `closeTextColor`        | `UIColor?` | 닫기 버튼 텍스트 색상                  | 흰색    |
| `ctaTextColor`          | `UIColor?` | CTA(Call to Action) 버튼 텍스트 색상 | 흰색    |

***

## Delegate 메서드

### AdropPopupAdDelegate (광고 이벤트)

#### 필수 메서드

<ParamField body="onAdReceived" type="(AdropPopupAd) -> Void">
  광고 수신 성공 시 호출됩니다. 이 시점에서 `show()`를 호출하여 광고를 표시할 수 있습니다.
</ParamField>

<ParamField body="onAdFailedToReceive" type="(AdropPopupAd, AdropErrorCode) -> Void">
  광고 수신 실패 시 호출됩니다. 에러 코드를 통해 실패 원인을 확인할 수 있습니다.
</ParamField>

#### 선택 메서드

<ParamField body="onAdImpression" type="(AdropPopupAd) -> Void">
  광고 노출이 기록되었을 때 호출됩니다.
</ParamField>

<ParamField body="onAdClicked" type="(AdropPopupAd) -> Void">
  사용자가 광고를 클릭했을 때 호출됩니다.
</ParamField>

<ParamField body="onAdWillPresentFullScreen" type="(AdropPopupAd) -> Void">
  팝업 광고가 표시되기 직전에 호출됩니다.
</ParamField>

<ParamField body="onAdDidPresentFullScreen" type="(AdropPopupAd) -> Void">
  팝업 광고가 화면에 표시된 직후 호출됩니다.
</ParamField>

<ParamField body="onAdWillDismissFullScreen" type="(AdropPopupAd) -> Void">
  팝업 광고가 닫히기 직전에 호출됩니다.
</ParamField>

<ParamField body="onAdDidDismissFullScreen" type="(AdropPopupAd) -> Void">
  팝업 광고가 닫힌 직후 호출됩니다. 다음 광고를 미리 로드하기 좋은 시점입니다.
</ParamField>

<ParamField body="onAdFailedToShowFullScreen" type="(AdropPopupAd, AdropErrorCode) -> Void">
  광고 표시 실패 시 호출됩니다. 에러 코드를 통해 실패 원인을 확인할 수 있습니다.
</ParamField>

<ParamField body="onAdVideoStart" type="(AdropPopupAd) -> Void">
  동영상 광고가 재생을 시작했을 때 호출됩니다.
</ParamField>

<ParamField body="onAdVideoEnd" type="(AdropPopupAd) -> Void">
  동영상 광고 재생이 완료되었을 때 호출됩니다.
</ParamField>

### AdropPopupAdCloseDelegate (닫기 이벤트)

모든 메서드가 선택사항입니다.

<ParamField body="onClosed" type="(AdropPopupAd) -> Void">
  사용자가 닫기 버튼을 클릭했을 때 호출됩니다.
</ParamField>

<ParamField body="onDimClicked" type="(AdropPopupAd) -> Void">
  사용자가 팝업 외부(딤 영역)를 클릭했을 때 호출됩니다.
</ParamField>

<ParamField body="onTodayOffClicked" type="(AdropPopupAd) -> Void">
  사용자가 "오늘 하루 보지 않기"를 선택했을 때 호출됩니다. 이 콜백에서 날짜를 저장하여 하루 동안 광고를 표시하지 않도록 구현할 수 있습니다.
</ParamField>

***

## 커스텀 클릭 처리

`useCustomClick`을 사용하여 광고 클릭 동작을 직접 제어할 수 있습니다. 활성화하면 SDK가 클릭 시 자동으로 URL을 열지 않으며, 직접 처리할 수 있습니다.

### useCustomClick

```swift theme={null}
popupAd = AdropPopupAd(unitId: "YOUR_POPUP_UNIT_ID")
popupAd?.useCustomClick = true
popupAd?.delegate = self
popupAd?.load()
```

`useCustomClick`이 `true`이면, SDK는 광고 클릭 시 자동으로 URL을 열지 않습니다. `onAdClicked` delegate 콜백은 계속 호출되며, `open()` 메서드를 사용하거나 직접 네비게이션을 처리할 수 있습니다.

### open()

광고의 목적지 URL을 엽니다. 커스텀 URL을 전달할 수도 있습니다.

```swift theme={null}
// 광고의 기본 목적지 URL 열기
popupAd?.open()

// 커스텀 URL 열기
popupAd?.open("https://example.com")

// 인앱 브라우저를 사용하여 열기
popupAd?.open(nil, useInAppBrowser: true)
```

### close()

프로그래밍 방식으로 팝업 광고를 닫습니다.

```swift theme={null}
popupAd?.close()
```

***

## 프로퍼티

| 프로퍼티             | 타입               | 설명                     |
| ---------------- | ---------------- | ---------------------- |
| `unitId`         | `String`         | 광고 유닛 ID               |
| `isLoaded`       | `Bool`           | 광고가 로드되었는지 여부          |
| `useCustomClick` | `Bool`           | 광고 클릭을 수동으로 처리할지 여부    |
| `destinationURL` | `String?`        | 현재 표시 중인 광고의 목적지 URL   |
| `creativeId`     | `String?`        | 현재 표시 중인 광고의 크리에이티브 ID |
| `txId`           | `String`         | 현재 표시 중인 광고의 트랜잭션 ID   |
| `txIds`          | `[String]`       | 로드된 모든 광고의 트랜잭션 ID     |
| `campaignId`     | `String`         | 현재 표시 중인 광고의 캠페인 ID    |
| `campaignIds`    | `[String]`       | 로드된 모든 광고의 캠페인 ID      |
| `creativeIds`    | `[String]`       | 로드된 모든 광고의 크리에이티브 ID   |
| `browserTarget`  | `BrowserTarget?` | 광고 클릭 시 URL 열기 방식      |

***

## 클로저 기반 콜백

Delegate 외에 클로저 기반 콜백도 사용할 수 있습니다. 전체 delegate 패턴을 구현하고 싶지 않을 때 편리합니다.

```swift theme={null}
let popupAd = AdropPopupAd(unitId: "YOUR_POPUP_UNIT_ID")

// 광고 이벤트
popupAd.onAdReceived = { ad in
    print("광고 수신 완료")
}
popupAd.onAdFailedToReceive = { ad, errorCode in
    print("광고 수신 실패: \(errorCode)")
}
popupAd.onAdClicked = { ad in
    print("광고 클릭, 목적지: \(ad.destinationURL ?? "")")
}
popupAd.onAdImpression = { ad in
    print("광고 노출")
}
popupAd.onAdWillPresentFullScreen = { ad in
    print("표시 직전")
}
popupAd.onAdDidPresentFullScreen = { ad in
    print("표시 완료")
}
popupAd.onAdWillDismissFullScreen = { ad in
    print("닫히기 직전")
}
popupAd.onAdDidDismissFullScreen = { ad in
    print("닫힘")
}
popupAd.onAdFailedToShowFullScreen = { ad, errorCode in
    print("표시 실패: \(errorCode)")
}
popupAd.onAdVideoStart = { ad in
    print("동영상 재생 시작")
}
popupAd.onAdVideoEnd = { ad in
    print("동영상 재생 완료")
}

// 닫기 이벤트
popupAd.onClosed = { ad in
    print("닫힘")
}
popupAd.onDimClicked = { ad in
    print("딤 클릭")
}
popupAd.onTodayOffClicked = { ad in
    print("오늘 하루 보지 않기")
}

popupAd.load()
```

<Note>
  Delegate 콜백과 클로저 기반 콜백은 동시에 사용할 수 있습니다. 둘 다 호출됩니다.
</Note>

***

## "오늘 하루 보지 않기" 구현

사용자가 "오늘 하루 보지 않기"를 선택했을 때 적절히 처리하는 방법입니다.

<Note>SDK가 "오늘 하루 보지 않기" 상태를 자동으로 관리합니다. 다음 예제는 기본 처리 외에 커스텀 동작을 추가하는 방법을 보여줍니다.</Note>

### 구현

SDK가 "오늘 하루 보지 않기"를 선택한 경우 `load()` 시 자동으로 로드를 건너뜁니다. 별도의 수동 체크 없이 `load()`만 호출하면 됩니다.

```swift theme={null}
class PopupAdManager {
    private var popupAd: AdropPopupAd?

    // 광고 로드 및 표시
    func loadAndShowAd(from viewController: UIViewController) {
        popupAd = AdropPopupAd(unitId: "YOUR_POPUP_UNIT_ID")
        popupAd?.delegate = self
        popupAd?.closeDelegate = self
        popupAd?.load()
    }
}

extension PopupAdManager: AdropPopupAdDelegate {
    func onAdReceived(_ ad: AdropPopupAd) {
        // 광고 수신 후 자동 표시
        if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
           let rootViewController = windowScene.windows.first?.rootViewController {
            ad.show(fromRootViewController: rootViewController)
        }
    }

    func onAdFailedToReceive(_ ad: AdropPopupAd, _ errorCode: AdropErrorCode) {
        print("광고 수신 실패: \(errorCode)")
    }
}

extension PopupAdManager: AdropPopupAdCloseDelegate {
    func onTodayOffClicked(_ ad: AdropPopupAd) {
        print("오늘 하루 보지 않기 선택")
        // SDK가 자동으로 오늘 하루 숨김 처리를 합니다.
        // 이 콜백은 분석 로깅이나 커스텀 UI 업데이트에 활용하세요.
    }
}
```

***

## 모범 사례

### 1. 적절한 표시 시점

팝업 광고는 다음 시점에 표시하는 것이 효과적입니다:

```swift theme={null}
// ✅ 좋은 예: 앱 시작 시
func applicationDidFinishLaunching() {
    loadAndShowPopupAd()
}

// ✅ 좋은 예: 콘텐츠 로드 완료 시
func onContentLoaded() {
    if shouldShowPopupAd() {
        showPopupAd()
    }
}

// ✅ 좋은 예: 특정 이벤트 완료 시
func onAchievementUnlocked() {
    showPopupAd()
}

// ❌ 나쁜 예: 사용자가 작업 중일 때
func onUserTyping() {
    showPopupAd() // 사용자 경험 저해
}
```

### 2. "오늘 하루 보지 않기" 존중

사용자가 "오늘 하루 보지 않기"를 선택했다면 반드시 준수하세요.

```swift theme={null}
func shouldShowPopupAd() -> Bool {
    // 오늘 하루 보지 않기 확인
    guard canShowAdToday() else {
        return false
    }

    // 다른 조건 확인
    return true
}
```

### 3. 빈도 제한

팝업 광고를 너무 자주 표시하지 마세요.

```swift theme={null}
class PopupAdFrequencyManager {
    private let lastShownKey = "popupAd_lastShown"
    private let minimumInterval: TimeInterval = 3600 // 1시간

    func canShowAd() -> Bool {
        // 오늘 하루 보지 않기 확인
        guard canShowAdToday() else {
            return false
        }

        // 최소 시간 간격 확인
        guard let lastShown = UserDefaults.standard.object(forKey: lastShownKey) as? Date else {
            return true
        }

        return Date().timeIntervalSince(lastShown) >= minimumInterval
    }

    func recordAdShown() {
        UserDefaults.standard.set(Date(), forKey: lastShownKey)
    }
}
```

***

## 테스트 유닛 ID

개발 및 테스트 시 다음 테스트 유닛 ID를 사용하세요.

| 광고 타입            | 테스트 유닛 ID                                     |
| ---------------- | --------------------------------------------- |
| 팝업 (하단 이미지)      | `PUBLIC_TEST_UNIT_ID_POPUP_BOTTOM`            |
| 팝업 (중앙 이미지)      | `PUBLIC_TEST_UNIT_ID_POPUP_CENTER`            |
| 팝업 비디오 (하단 16:9) | `PUBLIC_TEST_UNIT_ID_POPUP_BOTTOM_VIDEO_16_9` |
| 팝업 비디오 (하단 9:16) | `PUBLIC_TEST_UNIT_ID_POPUP_BOTTOM_VIDEO_9_16` |
| 팝업 비디오 (중앙 16:9) | `PUBLIC_TEST_UNIT_ID_POPUP_CENTER_VIDEO_16_9` |
| 팝업 비디오 (중앙 9:16) | `PUBLIC_TEST_UNIT_ID_POPUP_CENTER_VIDEO_9_16` |

<Warning>
  실제 배포 시에는 반드시 애드컨트롤 콘솔에서 생성한 실제 유닛 ID를 사용하세요.
</Warning>

***

## 관련 문서

<CardGroup cols={2}>
  <Card title="시작하기" href="/ko/sdk/ios">
    SDK 설치 및 초기화
  </Card>

  <Card title="전면 광고" href="/ko/sdk/ios/interstitial">
    전면 광고 구현하기
  </Card>

  <Card title="보상형 광고" href="/ko/sdk/ios/rewarded">
    보상형 광고 구현하기
  </Card>

  <Card title="배너 광고" href="/ko/sdk/ios/banner">
    배너 광고 구현하기
  </Card>
</CardGroup>
