# 닉네임·메시지 꾸미기

> 기본 스킨에서 닉네임 색·이미지와 메시지 배경·줄 간격·닉네임 숨기기를 바꾸는 예제예요.

기본 스킨(basic-v2)은 CSS를 덮어쓰는 대신 정해진 방법(resolver)으로 닉네임과 메시지 모양을 바꿔요. 스킨이 바뀌어도 깨지지 않고, 다른 스크립트와 함께 써도 서로 덮어쓰지 않아요.

채팅방 전체 색·글자 크기·모양은 코드 없이 [관리 페이지](/manage)의 **스킨** 메뉴에서 바꿀 수 있어요.

## 코드 {#code}

아래 코드 하나에 이 문서의 꾸미기가 모두 들어 있어요. 이미지 주소는 내 이미지로 바꾸세요.

```html
<script>U=window.U=window.U||{},U.events=U.events||[],U.chat=function(n){return{on:function(e,t){U.events.push([n,e,t])},off:function(e){for(var t=U.events.length;t>0;)U.events[--t][0]==n&&U.events[t][1]==e&&U.events.splice(t,1)}}};</script>
<script async src="https://client.uchat.io/uchat.js"></script>
<u-chat room="my-room" style="display:inline-block;width:100%;max-width:400px;height:500px"></u-chat>

<script>
U.chat('my-room').on('after.create#decorate', function (room) {
	var ui = room.skin;

	// 1. 관리자 닉네임: 색과 굵기, 관리자는 닉네임 대신 이미지
	ui.nickname.resolver.add({
		id: 'decorate.admin',
		resolve: function (c) {
			var auth = c.user ? Number(c.user.auth) : 0;
			if (auth < 2) return null;
			var patch = { style: { color: auth >= 3 ? '#e11d48' : '#2563eb', fontWeight: 'bold' } };
			if (auth >= 3) patch.nickcon = { src: 'https://example.com/img/owner-name.png', alt: c.user.nick };
			return patch;
		},
	});

	// 2. 레벨 10 이상: 닉네임 앞에 배지 아이콘을 더한다(기존 아이콘 유지)
	ui.nickname.resolver.add({
		id: 'decorate.level',
		resolve: function (c) {
			if (!c.user || Number(c.user.level) < 10) return null;
			return {
				iconsBefore: c.current.iconsBefore.concat([
					{ src: 'https://example.com/img/badge.png', alt: '레벨 10' },
				]),
			};
		},
	});

	// 3. 내 이름이 들어간 메시지: 배경색과 넓은 줄 간격
	ui.message.resolver.add({
		id: 'decorate.mention',
		resolve: function (c) {
			var me = room.my.nick;
			if (!me || c.author.nick === me || c.message.content.indexOf(me) < 0) return null;
			return { style: { backgroundColor: '#fff4cc' }, row: { spacing: 'relaxed' } };
		},
	});

	// 4. 내가 보낸 일반 메시지: 닉네임을 숨기고 글자색만 바꾼다
	ui.message.resolver.add({
		id: 'decorate.mine',
		resolve: function (c) {
			if (!room.my.nick || c.author.nick !== room.my.nick) return null;
			return { style: { color: '#1d4ed8' }, row: { hideNickname: true } };
		},
	});

	// 5. 메시지 뒤에 보낸 시각(시:분)
	ui.message.extend({
		id: 'decorate.time',
		position: 'after',
		mount: function (host, c) {
			host.textContent = ' ' + String(c.message.created || '').slice(11, 16);
			host.style.color = '#9ca3af';
			host.style.fontSize = '11px';
		},
	});
});

// 내 닉네임을 쓰는 규칙(3, 4)은 입장하거나 닉네임이 바뀐 뒤 다시 계산한다
function refreshDecorate(room) {
	room.skin.message.resolver.refresh();
}
U.chat('my-room').on('after.join#decorate', refreshDecorate);
U.chat('my-room').on('after.user.modi#decorate', refreshDecorate);
</script>
```

## 닉네임 색과 이미지 {#nickname}

`nickname.resolver.add`의 `resolve(c)`는 닉네임이 그려질 때마다 불려요. 바꿀 것만 담은 객체를 돌려주고, 바꿀 것이 없으면 `null`을 돌려줘요.

| `c`의 값 | 설명 |
| --- | --- |
| `c.user` | 닉네임 주인(`nick`, `auth`, `level`, `icons`, `nickcon` 등) |
| `c.location` | 그리는 자리. 메시지는 `message`, 사용자 목록은 `user-list` |
| `c.current` | 앞의 resolver까지 적용된 결과(`style`, `nickcon`, `iconsBefore`, `iconsAfter`) |
| `c.base` | resolver를 적용하기 전의 기본값 |

- `nickcon`은 닉네임 글자 대신 보여 줄 이미지예요(높이 16px 안). 이미지를 불러오지 못하면 닉네임 글자가 나와요. `nickcon: null`이면 회원 연동으로 받은 닉콘도 지워요.
- `iconsBefore`, `iconsAfter`는 배열 전체를 바꿔요. 기존 아이콘을 남기려면 위 코드처럼 `c.current.iconsBefore`에 이어 붙여요.
- 이미지 주소는 `https://`, `http://`, `//`, `/`로 시작하는 주소를 써요. 형식이 맞지 않는 주소는 무시돼요.

## 메시지 배경과 줄 간격 {#message-style}

`message.resolver.add`의 `resolve(c)`는 일반 메시지와 귓속말을 그릴 때 불려요. `c.message`(`content`, `created`, `kind` 등)와 보낸 사람 `c.author`를 읽을 수 있어요.

`row: { spacing: 'relaxed' }`를 돌려주면 그 줄의 안쪽 여백이 넓어져 눈에 잘 띄어요. 기본값은 `normal`이에요.

## 내 메시지 닉네임 숨기기 {#hide-nickname}

`row: { hideNickname: true }`를 돌려주면 그 줄에서 닉네임을 그리지 않아요. 일반 메시지에만 적용되고 귓속말은 누가 보냈는지 알아야 하므로 항상 닉네임이 보여요.

입장 전에는 `room.my.nick`이 비어 있으므로 내 닉네임을 쓰는 규칙은 `after.join`에서 `message.resolver.refresh()`로 다시 계산해요. 닉네임 규칙에서 같은 일이 필요하면 `nickname.resolver.refresh()`를 불러요.

## 메시지 옆에 시간 {#timestamps}

`message.extend`는 각 메시지의 앞(`before`), 안(`inline`), 뒤(`after`)에 작은 영역을 붙이고 `mount(host, c)`로 직접 그리게 해요. `c.message.created`는 `YYYY-MM-DD HH:MM:SS` 형식이에요. `match(c)`를 함께 주면 `true`를 돌려준 메시지에만 붙어요.

## 쓸 수 있는 값 {#values}

| 대상 | 키 | 값 |
| --- | --- | --- |
| 닉네임·메시지 `style` | `color`, `backgroundColor` | `#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`, `rgb()`, `rgba()`, `hsl()`, `hsla()` |
|  | `fontWeight` | `normal`, `bold`, `100`~`900` |
|  | `fontStyle` | `normal`, `italic`, `oblique` |
|  | `textDecoration` | `none`, `underline`, `overline`, `line-through` |
| 닉네임 | `nickcon` | `{ src, alt }` 또는 `null` |
|  | `iconsBefore`, `iconsAfter` | `[{ src, alt }]` |
| 메시지 | `row.spacing` | `normal`, `relaxed` |
|  | `row.hideNickname` | `true`, `false` |

이 밖의 CSS 속성이나 값, HTML은 조용히 무시돼요. 더 자유로운 모양이 필요하면 `message.extend`나 `mount.*`로 받은 영역 안에서 직접 그리세요.

## 짚어 볼 점 {#notes}

- `resolve`, `match`는 동기 함수여야 해요. Promise를 돌려주면 오류로 처리되고 그 규칙은 무시돼요.
- resolver가 여러 개면 `order` 값 순서(같으면 등록 순서)로 차례로 겹쳐 적용돼요. 뒤의 규칙이 같은 키를 덮어써요.
- `add`는 해제 함수를 돌려줘요. 꾸미기를 끄려면 그 함수를 부르거나 `remove(id)`를 불러요. 전체 목록은 [스킨 UI API](/doc/3.4)를 보세요.
- 이 API는 기본 스킨(basic-v2)에만 있어요.
