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

# Tùy chỉnh giao diện

> Tùy chỉnh giao diện của tiện ích giọng nói ThunderPhone bằng CSS

Tiện ích hiển thị dưới dạng thanh hiệu ứng kính với giao diện sáng và tối tích hợp sẵn. Bạn có thể tùy chỉnh ở ba cấp độ: props cho các tùy chọn phổ biến, thuộc tính tùy chỉnh CSS để áp dụng giao diện, và ghi đè lớp CSS để kiểm soát toàn diện.

<Note>
  Các tùy chọn tạo kiểu này áp dụng cho tiện ích dựng sẵn được hiển thị bởi component React `ThunderPhoneWidget` và phương thức CDN `ThunderPhone.mount()`. Nếu bạn cần một giao diện hoàn toàn tùy chỉnh, hãy dùng [hook headless](/vi/widget/headless-hook).
</Note>

***

## Giao diện

Prop `theme` kiểm soát bảng màu của tiện ích. Prop này áp dụng lớp `tp--light` hoặc `tp--dark` vào phần tử gốc của tiện ích:

```tsx theme={null}
<ThunderPhoneWidget
  publishableKey="pk_live_your_publishable_key"
  theme="dark"
/>
```

| Giao diện | Lớp         | Mô tả                               |
| --------- | ----------- | ----------------------------------- |
| `'light'` | `tp--light` | Nền sáng với văn bản tối. Mặc định. |
| `'dark'`  | `tp--dark`  | Nền tối với văn bản sáng.           |

Cả hai giao diện đều sử dụng thiết kế thanh hiệu ứng kính với hiệu ứng làm mờ nền và độ trong suốt tinh tế.

***

## Thuộc tính tùy chỉnh CSS

Widget cung cấp các thuộc tính tùy chỉnh CSS (biến) mà bạn có thể ghi đè để thay đổi màu sắc mà không cần chỉnh sửa từng class. Chúng được xác định bởi class giao diện (`.tp--light` hoặc `.tp--dark`) áp dụng cho phần tử gốc `.tp-widget`:

| Thuộc tính           | Mặc định (sáng)                         | Mặc định (tối)                           | Mô tả                                                                                                                                     |
| -------------------- | --------------------------------------- | ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `--tp-accent`        | `#000`                                  | `#fff`                                   | Màu nhấn: nút bắt đầu, các thanh dạng sóng, chấm đang kết nối, văn bản trạng thái đã kết nối. Được đặt **inline** từ prop `primaryColor`. |
| `--tp-bg`            | `rgba(255, 255, 255, 0.82)`             | `rgba(15, 15, 15, 0.85)`                 | Nền thanh (trong mờ; được làm mờ bởi `--tp-glass`).                                                                                       |
| `--tp-surface`       | `rgba(0, 0, 0, 0.04)`                   | `rgba(255, 255, 255, 0.07)`              | Nền nút tắt tiếng.                                                                                                                        |
| `--tp-surface-hover` | `rgba(0, 0, 0, 0.07)`                   | `rgba(255, 255, 255, 0.12)`              | Nền khi di chuột qua nút tắt tiếng.                                                                                                       |
| `--tp-border`        | `rgba(0, 0, 0, 0.08)`                   | `rgba(255, 255, 255, 0.1)`               | Đường viền thanh và nút.                                                                                                                  |
| `--tp-border-hover`  | `rgba(0, 0, 0, 0.14)`                   | `rgba(255, 255, 255, 0.18)`              | Màu đường viền khi di chuột qua.                                                                                                          |
| `--tp-text`          | `rgba(0, 0, 0, 0.88)`                   | `rgba(255, 255, 255, 0.95)`              | Văn bản chính (tiêu đề, tên tác nhân AI).                                                                                                 |
| `--tp-text-2`        | `rgba(0, 0, 0, 0.5)`                    | `rgba(255, 255, 255, 0.55)`              | Văn bản phụ (phụ đề, dòng trạng thái, bộ đếm thời gian cuộc gọi).                                                                         |
| `--tp-glass`         | `blur(32px) saturate(180%)`             | `blur(32px) saturate(180%)`              | `backdrop-filter` tạo hiệu ứng kính trên thanh.                                                                                           |
| `--tp-shadow`        | chồng bóng ba lớp                       | chồng bóng ba lớp                        | `box-shadow` của thanh (các lớp viền + gần + xa).                                                                                         |
| `--tp-shadow-hover`  | chồng bóng ba lớp                       | chồng bóng ba lớp                        | Được khai báo để nâng lên khi di chuột qua; hiện không được áp dụng bởi bất kỳ quy tắc nào.                                               |
| `--tp-glow`          | `inset 0 1px 0 0 rgba(255,255,255,0.5)` | `inset 0 1px 0 0 rgba(255,255,255,0.06)` | Điểm sáng phía trên bên trong được xếp lớp lên bóng của thanh.                                                                            |
| `--tp-connected`     | `#059669`                               | `#34d399`                                | Màu chỉ báo trạng thái đã kết nối (chấm trạng thái).                                                                                      |
| `--tp-error`         | `#dc2626`                               | `#fb7185`                                | Màu văn bản trạng thái lỗi.                                                                                                               |
| `--tp-end-bg`        | `rgba(239, 68, 68, 0.08)`               | `rgba(251, 113, 133, 0.12)`              | Nền nút kết thúc cuộc gọi.                                                                                                                |
| `--tp-end-color`     | `#ef4444`                               | `#fb7185`                                | Màu biểu tượng nút kết thúc cuộc gọi.                                                                                                     |
| `--tp-end-border`    | `rgba(239, 68, 68, 0.12)`               | `rgba(251, 113, 133, 0.15)`              | Đường viền nút kết thúc cuộc gọi.                                                                                                         |
| `--tp-end-hover`     | `rgba(239, 68, 68, 0.14)`               | `rgba(251, 113, 133, 0.2)`               | Nền khi di chuột qua nút kết thúc cuộc gọi.                                                                                               |
| `--tp-idle-opacity`  | `0.4`                                   | `0.3`                                    | Được khai báo để làm mờ ở trạng thái nhàn rỗi; hiện không được áp dụng bởi bất kỳ quy tắc nào.                                            |

### Ghi đè thuộc tính tùy chỉnh

Đặt màu nhấn qua prop `primaryColor`:

```tsx theme={null}
<ThunderPhoneWidget
  publishableKey="pk_live_your_publishable_key"
  primaryColor="#e11d48"
/>
```

<Warning>
  `--tp-accent` được đặt dưới dạng **kiểu inline** từ prop `primaryColor`, vì vậy việc ghi đè `--tp-accent` trong stylesheet sẽ không có tác dụng. Thay đổi màu nhấn bằng prop. Mọi thuộc tính tùy chỉnh khác đều có thể được ghi đè trong CSS.
</Warning>

Ghi đè các thuộc tính tùy chỉnh khác bằng CSS. Sử dụng bộ chọn hai class (`.tp-widget.tp--light` / `.tp-widget.tp--dark`) để quy tắc của bạn có độ ưu tiên cao hơn class giao diện xác định các giá trị mặc định, bất kể thứ tự stylesheet:

```css theme={null}
.tp-widget.tp--light {
  --tp-bg: rgba(0, 0, 0, 0.9);
  --tp-text: rgba(255, 255, 255, 0.95);
  --tp-text-2: rgba(255, 255, 255, 0.55);
  --tp-border: rgba(255, 255, 255, 0.15);
}
```

***

## Các lớp CSS

Tất cả lớp widget đều có tiền tố `tp-` để tránh xung đột với các style hiện có của bạn.

| Lớp                           | Phần tử                        | Mô tả                                                                                                                                                                                       |
| ----------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `.tp-widget`                  | Trình bao bọc gốc              | Vùng chứa có vị trí cố định (`position: fixed`, góc được thiết lập bởi prop `position`, `z-index: 9999`). Mang lớp chủ đề và các thiết lập font cơ bản; không có giao diện trực quan riêng. |
| `.tp--light` / `.tp--dark`    | Bổ nghĩa chủ đề                | Được áp dụng cho `.tp-widget` cùng với chủ đề; xác định tất cả thuộc tính tùy chỉnh `--tp-*`.                                                                                               |
| `.tp-bar`                     | Thanh                          | Chính pill hiệu ứng kính: nền, làm mờ hậu cảnh, viền, bán kính `99px`, bóng. Rộng `300px`.                                                                                                  |
| `.tp-meta`                    | Khối văn bản                   | Vùng chứa cho toàn bộ văn bản -- tiêu đề và phụ đề khi ở trạng thái chờ, tên tác nhân và trạng thái trong cuộc gọi.                                                                         |
| `.tp-name`                    | Nhãn chính                     | Hiển thị prop `title` khi ở trạng thái chờ, và tên của tác nhân đã kết nối (dùng `title` nếu không có) trong cuộc gọi.                                                                      |
| `.tp-sub`                     | Phụ đề                         | Dòng "Hiện đang khả dụng" hiển thị khi ở trạng thái chờ.                                                                                                                                    |
| `.tp-start`                   | Nút gọi ở trạng thái chờ       | Nút bắt đầu hình tròn màu nhấn (42px). Dùng `--tp-accent` làm nền.                                                                                                                          |
| `.tp-dot`                     | Chấm đang kết nối              | Chấm màu nhấn nhấp nháy hiển thị ở bên trái thanh trong khi kết nối.                                                                                                                        |
| `.tp-wave` / `.tp-wave--idle` | Dạng sóng                      | Dạng sóng năm thanh. `--idle` thêm hoạt ảnh nhịp thở chậm; trong cuộc gọi, các thanh phản hồi theo âm thanh.                                                                                |
| `.tp-button`                  | Nút trong cuộc gọi             | Style cơ bản cho các điều khiển trong cuộc gọi (42px, bo tròn 12px).                                                                                                                        |
| `.tp-button-group`            | Hàng nút                       | Bao bọc nút tắt tiếng và kết thúc trong cuộc gọi.                                                                                                                                           |
| `.tp-button--start`           | Biến thể nút kết nối           | Biến thể màu nhấn hiển thị khi cuộc gọi đang bắt đầu.                                                                                                                                       |
| `.tp-button--mute`            | Nút chuyển tắt tiếng           | Tắt/bật tiếng mic trong cuộc gọi. Dùng `--tp-surface`.                                                                                                                                      |
| `.tp-button--end`             | Nút kết thúc cuộc gọi          | Ngắt cuộc gọi. Dùng bảng màu `--tp-end-*`.                                                                                                                                                  |
| `.tp-button--loading`         | Bổ nghĩa đang tải              | Làm mờ nút trong khi kết nối.                                                                                                                                                               |
| `.tp-icon` / `.tp-spin`       | Biểu tượng                     | Kích thước biểu tượng nút; `tp-spin` tạo hoạt ảnh cho vòng xoay đang kết nối.                                                                                                               |
| `.tp-status`                  | Khối trạng thái trong cuộc gọi | Bao bọc dòng trạng thái trong các trạng thái đang kết nối/đã kết nối/lỗi.                                                                                                                   |
| `.tp-status__text`            | Dòng trạng thái                | Văn bản trạng thái kết nối (ví dụ: "Đang kết nối...") hoặc bộ đếm thời gian cuộc gọi. Nhận `.tp-status--connected` (màu nhấn) hoặc `.tp-status--error` (màu lỗi) theo trạng thái.           |
| `.tp-status__name`            | Vị trí tên tác nhân            | Là một phần của khối trạng thái, nhưng không được hiển thị trong bố cục thanh hiện tại -- tên tác nhân xuất hiện trong `.tp-name` thay vào đó.                                              |
| `.tp-status__dot`             | Chấm trạng thái                | Style chấm trạng thái đã kết nối nhấp nháy (dùng `--tp-connected`).                                                                                                                         |

***

## Ví dụ

### Màu nhấn tùy chỉnh qua Props

Cách đơn giản nhất để gắn thương hiệu cho widget:

```tsx theme={null}
<ThunderPhoneWidget
  publishableKey="pk_live_your_publishable_key"
  theme="light"
  primaryColor="#059669"
  title="Talk to support"
/>
```

### Màu tùy chỉnh qua CSS

Ghi đè các thuộc tính tùy chỉnh để kiểm soát hoàn toàn màu sắc. Lưu ý rằng màu nhấn đến từ prop `primaryColor`, không phải CSS:

```tsx theme={null}
<ThunderPhoneWidget
  publishableKey="pk_live_your_publishable_key"
  primaryColor="#059669"
/>
```

```css theme={null}
/* Emerald theme for everything else */
.tp-widget.tp--light {
  --tp-bg: rgba(236, 253, 245, 0.85);
  --tp-text: rgba(6, 78, 59, 0.95);
  --tp-text-2: rgba(4, 120, 87, 0.8);
  --tp-border: rgba(5, 150, 105, 0.2);
}
```

### Kích thước tùy chỉnh

Phóng to hoặc thu nhỏ widget bằng cách điều chỉnh kích thước thanh, nút và văn bản:

```css theme={null}
/* Wider bar */
.tp-bar {
  width: 340px;
}

/* Larger buttons (42px by default) */
.tp-start,
.tp-button {
  width: 56px;
  height: 56px;
}

/* Larger text */
.tp-name {
  font-size: 16px;
}

.tp-sub,
.tp-status__text {
  font-size: 14px;
}
```

### Ẩn nhãn văn bản

Toàn bộ văn bản của widget nằm trong `.tp-meta`. Ẩn hoàn toàn phần này để chỉ giữ lại dạng sóng và các nút:

```css theme={null}
.tp-meta {
  display: none;
}
```

Hoặc ẩn từng phần riêng lẻ:

```css theme={null}
/* Hide only the idle "Available now" subtitle */
.tp-sub {
  display: none;
}

/* Hide only the in-call status line (connection state / timer) */
.tp-status {
  display: none;
}
```

<Note>
  Nhãn khi rảnh nằm trong `.tp-name`/`.tp-sub`, không phải `.tp-status` -- chỉ ẩn `.tp-status` vẫn hiển thị tiêu đề khi widget đang rảnh.
</Note>

### Ghi đè theo chủ đề

Nhắm đến một chủ đề cụ thể bằng lớp chủ đề:

```css theme={null}
/* Only affect dark theme */
.tp--dark .tp-start {
  box-shadow: 0 0 20px rgba(255, 255, 255, 0.25);
}

/* Only affect light theme */
.tp-widget.tp--light {
  --tp-bg: rgba(255, 255, 255, 0.95);
}
```

***

## Phạm vi với className

Khi sử dụng thành phần React, truyền prop `className` để giới hạn các ghi đè của bạn cho một phiên bản widget cụ thể:

```tsx theme={null}
<ThunderPhoneWidget
  publishableKey="pk_live_your_publishable_key"
  theme="dark"
  className="support-widget"
/>
```

Sau đó nhắm đến lớp đó trong CSS:

```css theme={null}
.support-widget.tp--dark {
  --tp-bg: rgba(30, 30, 46, 0.9);
}

.support-widget .tp-name {
  font-weight: 700;
}
```

Điều này cho phép bạn có nhiều phiên bản widget trên cùng một trang với các kiểu khác nhau. Đặt màu nhấn riêng cho từng phiên bản thông qua prop `primaryColor` của nó (CSS không thể ghi đè `--tp-accent` -- thuộc tính này được đặt inline).

***

## Giao diện người dùng hoàn toàn tùy chỉnh

Nếu ghi đè CSS là chưa đủ, [headless hook](/vi/widget/headless-hook) cho phép bạn toàn quyền kiểm soát. Bạn cung cấp toàn bộ HTML và kiểu dáng, trong khi `useThunderPhone` xử lý phiên thoại. Hook này cũng cung cấp `audioLevelRef` để xây dựng các hình ảnh trực quan phản hồi theo âm thanh như dạng sóng.

```tsx theme={null}
import { useThunderPhone } from '@thunderphone/widget'

function MyWidget() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })

  return (
    <div className="my-totally-custom-widget">
      {/* Your own buttons, animations, layouts -- anything */}
      <button onClick={phone.state === 'connected' ? phone.disconnect : phone.connect}>
        {phone.state === 'connected' ? 'Hang up' : 'Call us'}
      </button>
      {phone.audio}
    </div>
  )
}
```

<Tip>
  Headless hook là lựa chọn phù hợp khi bạn cần hiệu ứng động phản hồi theo âm thanh, bố cục tùy chỉnh hoặc tích hợp vào thư viện thành phần hiện có. Ghi đè CSS và các thuộc tính tùy chỉnh phù hợp hơn cho các điều chỉnh chủ đề nhanh.
</Tip>
