# Typst 템플릿용 양식

직접 만든 Typst 함수에 양식을 붙여, 보고서를 채우는 사람이 비주얼 모드에서 함수 호출 문법 대신 레이블이 붙은 필드를 보게 합니다.

Typst 템플릿에는 표지, 정보 상자, 서명란 같은 자체 함수가 들어 있는 경우가 많습니다. 보고서를 쓰는 사람은 `#info-box(title: "Supply risk", tone: "risk")[...]`처럼 그 함수를 호출합니다. 템플릿을 관리한다면 각 함수의 인수를 한 번만 설명해 두면 됩니다. 그러면 비주얼 모드가 그 함수의 모든 호출을 양식으로 보여 줍니다. 레이블이 붙은 필드, 고정된 선택지를 위한 목록, 예/아니요를 위한 스위치입니다. 필드를 수정하면 `.typ` 파일에서 그 인수 하나만 다시 쓰이므로, 보고서는 똑같이 컴파일되는 평범한 Typst 소스로 남습니다.

## 읽는 사람에게 보이는 모습

자기 줄에 따로 쓴 호출은 **카드**가 됩니다. 카드 머리글에는 양식의 이름이 나오고, 요약을 지정했다면 상자의 제목 같은 짧은 요약도 나옵니다. 인수마다 레이블과 컨트롤이 있는 행이 하나씩 생깁니다.

`#badge("review")`처럼 문장 안에 있는 호출은 글줄 안의 **칩**이 됩니다. 칩을 클릭하면 같은 필드가 작은 팝오버에 열립니다.

텍스트 필드와 마크업 필드는 Enter(여러 줄 필드에서는 ⌘ Enter 또는 Ctrl Enter)를 누르거나 필드를 벗어나면 저장됩니다. Esc는 이전 값으로 되돌립니다. 목록과 스위치는 바로 저장됩니다. 변경 하나가 실행 취소 한 단계입니다.

커서를 호출 안으로 옮기면 다른 비주얼 모드 요소처럼 소스가 나타납니다. 카드의 **소스에서 편집**도 같은 일을 합니다.

## 양식을 선언하는 곳

양식을 선언하는 곳은 두 군데이며 형식은 같습니다.

- **패키지 안.** 패키지의 `typst.toml`에 `[tool.oleafly]` 섹션을 추가합니다. Typst는 `[tool.*]` 섹션을 다른 도구용으로 남겨 두므로 패키지는 어디서나 그대로 설치되고 컴파일됩니다. `@local` 패키지와 Typst Universe의 `@preview` 패키지에서 쓸 수 있습니다.
- **프로젝트 안.** 프로젝트 안에 일반 `.typ` 파일로 둔 템플릿은 프로젝트 맨 위에 `oleafly-forms.toml`을 만드세요. 이때 각 양식은 함수를 정의한 파일도 `module`로 지정합니다.

패키지 양식:

```toml
[tool.oleafly]
schema = 1

[[tool.oleafly.forms]]
function = "info-box"
label = "Info box"
summary = "title"

  [[tool.oleafly.forms.fields]]
  arg = "title"
  kind = "text"
  label = "Heading"
  placeholder = "Short heading"
  required = true

  [[tool.oleafly.forms.fields]]
  arg = "tone"
  kind = "choice"
  label = "Tone"
  default = "note"
  options = [{ value = "note", label = "Note" }, { value = "risk", label = "Risk" }, "neutral"]

  [[tool.oleafly.forms.fields]]
  arg = 0
  kind = "content"
  label = "Text"
```

`oleafly-forms.toml`에 들어가는 프로젝트 양식:

```toml
[tool.oleafly]
schema = 1

[[tool.oleafly.forms]]
module = "template/memo.typ"
function = "memo-header"
label = "Memo header"
fields = [
  { arg = "to", kind = "text", label = "To" },
  { arg = "subject", kind = "text", label = "Subject" },
]
```

## 키

`schema = 1`은 필수입니다. 이것이 없거나 다른 숫자인 파일은 무시됩니다.

각 `[[tool.oleafly.forms]]` 항목에는 다음이 있습니다.

| 키 | 필수 | 의미 |
| --- | --- | --- |
| `function` | 예 | 함수의 이름으로, Typst 식별자 하나여야 합니다. 하이픈도 쓸 수 있습니다. |
| `module` | `oleafly-forms.toml`에서만 | 함수를 정의한 프로젝트 파일. 프로젝트 맨 위 폴더 기준이며 폴더 사이는 `/`로 구분합니다. |
| `label` | 아니요 | 카드와 칩에 표시되는 양식 이름. 기본값은 함수 이름입니다. |
| `summary` | 아니요 | 레이블 옆에 값이 표시되는 인수. 필드의 `arg`처럼 씁니다. |
| `fields` | 예 | 필드 하나 이상. |

각 필드에는 다음이 있습니다.

| 키 | 필수 | 의미 |
| --- | --- | --- |
| `arg` | 예 | 이름 있는 인수는 이름(`"title"`), 위치 인수는 숫자(`0`이 첫 번째)입니다. 뒤에 붙는 `[...]` 블록은 괄호 안의 인수들 다음의 위치 인수로 칩니다. |
| `kind` | 예 | `text`, `content`, `choice`, `number`, `toggle` 중 하나. |
| `label` | 예 | 필드의 레이블. |
| `help` | 아니요 | 필드 아래에 표시되는 짧은 안내. |
| `placeholder` | 아니요 | 빈 필드에 표시되는 회색 텍스트. |
| `required` | 아니요 | `true`이면 빈 필드를 누락으로 표시하고 **지우기** 버튼을 숨깁니다. Oleafly는 인수를 스스로 추가하지 않습니다. |
| `default` | 아니요 | 인수를 생략했을 때 함수가 사용하는 값. 표시만 되고 소스에 쓰이지는 않습니다. |

종류와 추가 키:

- `text`는 Typst 문자열을 씁니다. 더 큰 상자를 쓰려면 `multiline = true`를 추가하세요.
- `content`는 Typst 마크업을 편집하고 `[...]` 블록으로 씁니다. 문자열 인수는 문자열로 남습니다.
- `choice`에는 `options`가 필요합니다. 문자열 목록이거나, 레이블이 값과 다를 때는 `{ value, label }` 테이블입니다. 값은 문자열로 쓰입니다.
- `number`는 `integer`, `min`, `max`, `step`을 받습니다. 숫자에는 단위가 없습니다.
- `toggle`은 `true` 또는 `false`를 씁니다.

## 양식이 적용되는 호출

Oleafly는 보고서 파일 최상위에 있는 `#import`와 `#let` 줄을 따라갑니다.

- `#import "@local/acme-report:0.1.0" as acme`는 `#acme.info-box(...)`를 양식으로 만듭니다.
- `#import "@local/acme-report:0.1.0": info-box, status-badge as badge`는 `#info-box(...)`와 `#badge(...)`를 양식으로 만듭니다.
- `#import "@local/acme-report:0.1.0": *`는 패키지가 선언한 모든 함수를 양식으로 만듭니다.
- `#import "template/memo.typ": memo-header`는 `module`이 `template/memo.typ`인 프로젝트 양식과 일치합니다. 경로는 보고서가 있는 폴더 기준으로 읽고, `/`로 시작하면 프로젝트 맨 위 폴더 기준으로 읽습니다.

패키지 버전은 정확히 일치해야 합니다. 파일 뒤쪽에 같은 이름의 `#let`이 있으면 그 지점부터는 그것이 양식을 대체합니다. 패키지를 다시 import하는 다른 파일을 거쳐 닿는 호출은 소스 텍스트 그대로 남습니다.

`table`이나 `figure`처럼 비주얼 모드가 이미 그리는 Typst 요소와 이름이 같은 함수는 이름만으로 호출하면 내장 모양을 그대로 유지합니다. `#acme.table(...)`이나 이름을 바꾼 import에는 여전히 양식이 적용됩니다.

## 읽기 전용으로 표시되는 필드

일부 인수는 양식에서 안전하게 편집할 수 없습니다. 그 행에는 이유와 함께 소스가 표시되고, **소스에서 편집**을 누르면 소스로 이동합니다.

- **소스에서 계산됨:** 값이 `title: data.title` 같은 식입니다.
- **다른 종류의 값으로 작성됨:** 예를 들어 양식은 텍스트를 기대하는데 숫자가 들어 있는 경우입니다.
- **선택지에 없는 값:** `options`에 없는 값입니다.
- **전개 인수로 설정됨:** `..args`가 있는 호출은 양식에서 볼 수 없는 값을 넘기므로 모든 필드가 읽기 전용입니다.

필드를 들어갈 자리에 추가할 수 없을 때, 예를 들어 빠진 인수 뒤의 위치 인수라면 양식이 그렇게 알려 주고 **소스에서 추가**를 제안합니다.

## 정의의 실수

Oleafly에서 `oleafly-forms.toml`이나 프로젝트에 포함한 패키지의 `typst.toml`을 열면 문제마다 해당 줄에 표시가 나타납니다. 알 수 없는 종류, 빠진 레이블, 중복된 양식, 프로젝트 밖을 가리키는 `module` 등입니다. 잘못된 양식은 제외되고 나머지는 계속 작동합니다. 256 KB보다 큰 파일은 읽지 않습니다.

## 템플릿 공유

Oleafly는 컴파일러가 쓰는 것과 같은 폴더에서 패키지 양식을 읽습니다. `@local` 패키지가 없는 공동 저자에게는 평범한 소스만 보이고 오류는 나지 않습니다. 프로젝트의 모든 사람과 양식을 공유하려면 **Typst 패키지** 대화 상자를 열고 **프로젝트 폴더의 패키지 사용**을 켠 다음 **패키지를 프로젝트에 포함**을 선택하세요. 그러면 패키지와 그 양식이 프로젝트의 `typst-packages` 폴더에 담겨 함께 이동합니다([Typst 프로젝트](/docs/typst/) 참고).
