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

# TnView와 VDP

> 썸네일만 가볍게 보여주고 가변 데이터를 주입하기

**TnView**는 저장된 프로젝트나 템플릿의 썸네일을 보여주기 위한 경량 모드입니다. 편집기보다 훨씬 작은 리소스로, 불필요한 UI 없이 썸네일 렌더링만 담당합니다.

**VDP**(Variable Data Printing)는 하나의 문서에 가변 데이터를 주입해 여러 출력물을 만드는 시스템입니다. 이름과 직함만 다른 명함 100장을 한 템플릿으로 뽑는 경우를 생각하시면 됩니다. TnView는 VDP의 한 행을 받아 화면에 반영합니다.

## TnView 띄우기

세 가지 방법이 있습니다. 셋 다 `TnViewSession`을 반환합니다.

| 메서드 | 필수 옵션 | 용도 |
| - | - | - |
| `openTnview(o)` | `project_id`, `token`, `parent_element` | 저장된 프로젝트의 썸네일을 보여줍니다. `ps_code`는 선택입니다 |
| `createTnview(o)` | `ps_code`, `template_uri`, `token`, `parent_element` | 템플릿으로 프로젝트를 새로 만들고 그 썸네일을 보여줍니다 |
| `showTnview(o)` | `ps_code`, `template_uri`, `token`, `parent_element` | 프로젝트를 만들지 않고 템플릿 미리보기만 보여줍니다 |

```ts theme={null}
const session = edicus.openTnview({
  parent_element: el,
  token,
  project_id,
  npage: 1,
})
```

## 공통 옵션

<ParamField path="div" type="string" default="host">
  division code입니다. 생략하면 SDK가 `'host'`를 채워 넣습니다.
</ParamField>

<ParamField path="lang" type="'ko' | 'en' | 'ja'" default="ko">
  언어 코드입니다. 생략하면 SDK가 `'ko'`를 채워 넣습니다.
</ParamField>

<ParamField path="npage" type="number | 'auto'" default="1">
  한 화면에 보여줄 페이지 수입니다.

  편집기의 `num_page`(포토북 내지 스프레드 장수)와는 **다른 개념입니다.** 이름이 비슷해 혼동하기 쉽습니다.
</ParamField>

<ParamField path="flow" type="'horizontal' | 'vertical' | `grid:${number}`" default="horizontal">
  페이지 배치 방향입니다. `grid:312`처럼 썸네일 크기를 함께 지정할 수 있습니다.
</ParamField>

<ParamField path="options" type="Record<string, unknown>">
  추가 설정입니다. 지연 파라미터입니다.
</ParamField>

<ParamField path="data_row" type="unknown">
  첫 렌더에 바로 반영할 VDP 행입니다. 지연 파라미터입니다.
</ParamField>

<ParamField path="zoom" type="{ method?: string; maxScale?: number }">
  줌 옵션입니다. 다른 필드도 더 받습니다. 지연 파라미터입니다.
</ParamField>

지연 파라미터는 URL에 싣지 않고 SDK가 들고 있다가 TnView가 요청하면 답합니다. 대신 URL에는 `wait_options`, `wait_data_row`, `wait_zoom` 플래그가 붙습니다. 자세한 내용은 [띄우기 옵션](/docs/reference/launch-options#지연-파라미터)에 있습니다.

세 메서드 모두 `rotate?: boolean`과 `show3d?: boolean`을 추가로 받습니다. 둘 다 명시적으로 지정했을 때만 URL에 실리고, 기본값에서 유도되지 않습니다. `rotate`는 `false`일 때만, `show3d`는 `true`일 때만 URL에 들어갑니다.

<Note>
  TnView 옵션에는 `partner`가 없습니다. 편집기의 공통 옵션(`mobile`, `run_mode` 등)도 받지 않습니다.
</Note>

## 페이지 이동

```ts theme={null}
session.movePage('next') // 'prev' | 'next'
```

내부적으로 `session.post('move-page', { direction: 'next' })`와 같습니다.

## 가변 데이터 주입

`setVariableDataRow(row)`로 한 행을 반영합니다. 내부적으로 `session.post('set-data-row', row)`와 같습니다. 성공하면 조용히 화면이 갱신되고 별도 리포트가 없습니다. 문서가 아직 로드되기 전에 호출하면 `set-data-row-report` 이벤트로 실패가 옵니다.

```ts theme={null}
import type { VariableDataRow } from '@edicus/sdk/types'

session.on('set-data-row-report', (info) => {
  console.error('data row 반영 실패:', info.error) // 'project not loaded' 등
})

const row: VariableDataRow = {
  cols: [
    { id: 'name', value: { text: '전 지 현' }, shrink: true },
    { id: 'title-role', value: { text: '최강미모' } },
  ],
}
session.setVariableDataRow(row)
```

## VDP 타입

```ts theme={null}
interface VariableData {
  id: string
  value: { text: string }
  shrink?: boolean
  segment?: boolean
}
interface VariableDataRow { cols: VariableData[] }
interface VariableDataSet { rows: VariableDataRow[] }
```

<ParamField path="id" type="string" required>
  템플릿에 정의된 변수 id입니다.
</ParamField>

<ParamField path="shrink" type="boolean">
  `true`면 텍스트가 줄바꿈되지 않도록 편집기가 장평을 자동 계산합니다.

  이 옵션을 쓰는 텍스트박스는 InDesign 템플릿에서 **장평값이 단일해야 합니다.** 그렇지 않으면 자동 계산된 장평이 단일값으로 적용되어, 줄바꿈이 없는 경우에도 최초 레이아웃과 다른 결과가 나옵니다.
</ParamField>

<ParamField path="segment" type="boolean">
  템플릿을 data merge 방식으로 만든 경우에 `true`로 줍니다. 어노테이션 방식으로 만든 변수에는 필요 없습니다.
</ParamField>

`set-data-row` 커맨드 자체는 `VariableDataRow | VariableDataRow[]`를 받습니다. 헬퍼 `setVariableDataRow`는 한 행만 받으므로, 여러 행을 한 번에 보내려면 `post`를 직접 씁니다.

```ts theme={null}
session.post('set-data-row', [rowA, rowB])
```

여러 행을 받았을 때 TnView가 어떻게 보여주는지는 SDK 타입에 정의돼 있지 않습니다. 실제 편집기에서 확인하고 쓰세요.

전체 명단을 순회하려면 행 하나씩 넣고 렌더링합니다.

```ts theme={null}
import type { VariableDataSet } from '@edicus/sdk/types'

const dataset: VariableDataSet = { rows: [ /* ... */ ] }
for (const row of dataset.rows) {
  session.setVariableDataRow(row)
  await captureThumbnail()
}
```

## VDP 카탈로그

`doc-changed` 이벤트의 `vdp_catalog`는 **현재 문서에 어떤 VDP 변수가 정의돼 있는지**의 목록입니다. SDK는 이 필드의 타입을 `unknown`으로 둡니다. 개별 항목의 참고용 구조는 `@edicus/sdk/types`의 `VDPItem`과 `VDPItemSegment`에 있으니 필요하면 직접 좁혀 쓰세요.

<Warning>
  주입용 `VariableDataRow`와 정의 목록인 `VDPItem`은 별개 타입입니다. 혼동하지 마세요.
</Warning>

## 저장

```ts theme={null}
session.save() // session.post('save', undefined)와 같습니다
```

## 이벤트

`type`은 전부 `from-edicus-tnview`입니다. 편집기 이벤트와 이름이 같아도 채널이 다르므로 `TnViewSession`으로 받습니다.

| action | payload 타입 | 설명 |
| - | - | - |
| `ready-to-listen` | `undefined` | TnView가 메시지를 받을 준비를 마쳤습니다 |
| `open-report` | `{ status } & Record<string, unknown>` | `openTnview`의 로드 시작, 끝, 실패를 알립니다 |
| `create-report` | `{ status } & Record<string, unknown>` | `createTnview`의 로드 시작, 끝, 실패를 알립니다 |
| `show-report` | `{ status } & Record<string, unknown>` | `showTnview`의 로드 시작, 끝, 실패를 알립니다 |
| `project-id-created` | `{ project_id: string }` | 새 프로젝트가 만들어졌습니다. `createTnview`에서 옵니다 |
| `doc-changed` | `DocChanged` | 문서가 로드되거나 변경됐습니다 |
| `save-doc-report` | `SaveDocReport` | 저장 시작, 끝, 실패를 알립니다 |
| `render-data-row-report` | `unknown` | `render-data-row`의 결과입니다. 성공하면 `{ status: 'end', input, output }`이고 `output`에 `svgSize`와 `svg` 또는 `data_url`이 있습니다. 실패하면 `status`가 `'error'`입니다 |
| `set-data-row-report` | `SetDataRowReport` | 문서 로드 전에 `set-data-row`를 받았을 때만 오는 실패 리포트입니다 |
| `browse-photo-report` | `BrowsePhotoReport` | `status`가 `'start'`, `'end'`, `'error'` 중 하나입니다 |
| `zoom-scale-changed` | `{ scale: number }` | 줌 배율이 바뀌었습니다 |
| `close` | `undefined` | TnView를 닫아 달라는 요청입니다. `waitForExit()`가 이것을 기다립니다 |

`open-report`, `create-report`, `show-report`의 `status`는 `'start'`, `'end'`, `'error'` 중 하나입니다. 다른 문자열이 올 수도 있습니다.

## 커맨드

`type`은 전부 `to-edicus-tnview`입니다. `session.post(action, info)`로 보냅니다.

| action | info | 설명 |
| - | - | - |
| `set-data-row` | `VariableDataRow \| VariableDataRow[]` | 가변 데이터를 반영합니다. 한 행은 `setVariableDataRow`로도 보냅니다 |
| `render-data-row` | `{ page_index, renderSize, vdp_row, type? }` | `page_index` 페이지에 `vdp_row`를 넣어 `renderSize`(`{ width, height }`) 크기로 그립니다. 결과는 `render-data-row-report`의 `output`으로 옵니다. `type`이 `'data_url'`이면 PNG data URL(`output.data_url`), 아니면 SVG 문자열(`output.svg`)입니다 |
| `move-page` | `{ direction: 'prev' \| 'next' }` | 페이지를 옮깁니다. `movePage`와 같습니다 |
| `set-zoom-scale` | `{ scale: number }` | 줌 배율을 바꿉니다 |
| `save` | `undefined` | 문서를 저장합니다. `save()`와 같습니다 |
| `show-3d` | `{ show: boolean }` | 3D 미리보기를 켜고 끕니다 |
| `set-rotate` | `{ rotate: boolean }` | 띄우기 옵션 `rotate`를 띄운 뒤에 바꿉니다 |
| `browse-photo` | 임의의 객체 | 파일 선택 창을 열고 고른 사진을 올립니다. 보낸 `info`는 `browse-photo-report`에 그대로 돌아오고, 끝나면 `srcInfo`(올린 사진 정보)가 더해집니다 |

SDK 타입은 `set-data-row`, `move-page`, `save`를 뺀 커맨드의 `info`를 `unknown`으로 둡니다. 표의 형식은 TnView가 읽는 필드입니다.

## VDP로 주문하기

편집이 아니라 주문에 가변 데이터를 실으려면 Server API의 잠정 주문(VDP)을 씁니다. [VDP 주문](/docs/server/orders-vdp)을 보세요.

## 다음 단계

<Columns cols={2}>
  <Card title="Preview 모드" icon="eye" href="/docs/sdk/preview">
    읽기 전용 미리보기를 띄웁니다.
  </Card>

  <Card title="주문" icon="cart-shopping" href="/docs/server/orders">
    가변 데이터를 포함한 주문을 넣습니다.
  </Card>
</Columns>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.