Layout (Giao diện)

Phía trên chính là Components v2 của Discord - một layout (giao diện) tin nhắn rất mới có tính linh hoạt và mạnh mẽ hơn embed truyền thống, cho phép bố trí nội dung và các hành động tương tác ngay trong cùng khung tin nhắn.
Tất cả các components (thành phần) này có thể tùy chỉnh và kết hợp với nhau, giúp bạn tạo ra tin nhắn bắt mắt, rõ ràng, và có thể tương tác trực tiếp.
Như thường lệ, Layout của GlitchBucket sẽ sử dụng bộ phận xử lí tin nhắn BucketScript. Tài liệu dưới đây sẽ miêu tả về các thành phần (components), cách sử dụng trong GlitchBucket, cũng như 1 phần hỗ trợ các Developer về layout (giao diện) mới này. Nếu bạn muốn đọc tài liệu từ chính Discord, thì bạn có thể xem tại đây.
Các thành phần của giao diện
Text (Ô chữ)
Text Display là một thành phần nội dung (content component) cho phép bạn thêm văn bản có định dạng.
Cách hoạt động của thành phần này rất giống với nội dung tin nhắn bình thường, nhưng nó cho phép bạn thêm nhiều khối văn bản riêng biệt, giúp kiểm soát bố cục hiển thị của tin nhắn linh hoạt hơn.
Bạn cần tạo, hoặc sửa 1 giao diện có sẵn qua lệnh /layout edit
.
Sau khi đã chọn cho mình được giao diện cần chỉnh sửa, hãy bấm ➕ Thêm
, chọn lựa chọn Text Display, và nhập nội dung bạn muốn (như ở đây là Hello World!)
Đối với developer, chúng ta có thể dựa vào đây để gửi 1 TextDisplay đi:
from discord.ui import LayoutView, TextDisplay
layout = LayoutView(timeout=300)text = TextDisplay('Hello World!')
layout.add_item(text)
await channel.send(view=layout)

Button (Nút bấm)
Button là một thành phần tương tác (interactive component).
Nó tạo ra các nút có thể nhấn, cho phép người dùng tương tác trực tiếp, và khi được bấm thì bot sẽ nhận sự kiện tương tác (interaction), để bot phản hồi.
Bạn cần tạo, hoặc sửa 1 nút có sẵn qua lệnh /buttons
. Bạn cần tạo, hoặc sửa 1 giao diện có sẵn qua lệnh /layout edit
.
Sau khi đã làm nút cần gửi đi & chọn cho mình được giao diện cần chỉnh sửa, hãy bấm ➕ Thêm
, chọn lựa chọn Button, và chọn 1 nút đã có sẵn từ /buttons
.
Các nút (button) phải được đặt bên trong một Action Row hoặc trong accessory của Section thì mới được phép gửi đi.
Button đều có thể được sử dụng trong cả component cũ lẫn component mới. Chúng ta có thể dựa vào đây để gửi 1 Button (trong layout mới) bằng cách subclass ui.Button
và thêm callback
:
from discord import ButtonStyle, Interactionfrom discord.ui import ActionRow, LayoutView, Button
class MyButton(Button): async def callback(self, interaction: Interaction): await interaction.response.send_message('Bạn vừa bấm vào nút!', ephemeral=True)
layout = LayoutView(timeout=300)row = ActionRow( MyButton(emoji='💖', label='Nhãn của nút', style=ButtonStyle.gray))
layout.add_item(row)
await channel.send(view=layout)
Select (Trình chọn)
Select (Trình chọn) là một thành phần tương tác (interactive component) cho phép người dùng chọn tùy chọn được cung cấp sẵn.
Khi người dùng hoàn tất việc chọn, bot sẽ nhận được một sự kiện tương tác (interaction).
Bạn cần tạo, hoặc sửa 1 trình chọn có sẵn qua lệnh /selects
. Bạn cần tạo, hoặc sửa 1 giao diện có sẵn qua lệnh /layout edit
.
Sau khi đã làm trình chọn cần gửi đi & chọn cho mình được giao diện cần chỉnh sửa, hãy bấm ➕ Thêm
, chọn lựa chọn Select, và chọn 1 trình chọn đã có sẵn từ /selects
.
Thành phần này có thể được cấu hình ở hai chế độ:
- Chọn đơn (Single-select): chỉ chọn một mục.
- Chọn nhiều (Multi-select): chọn nhiều mục cùng lúc. (GlitchBucket không hỗ trợ chế độ này khi dựng layout)
Select có thể được sử dụng trong tin nhắn (messages) và hộp thoại (modals).
Trong tin nhắn, Select phải được đặt bên trong một Action Row, còn trong hộp thoại thì đặt trong một Label.
Select đều có thể được sử dụng trong cả component cũ lẫn component mới. Chúng ta có thể dựa vào đây để gửi 1 Select (trong layout mới) bằng cách subclass ui.Select
và thêm callback
:
from discord import Interaction, PartialEmoji, SelectOptionfrom discord.ui import ActionRow, LayoutView, Select
class MySelect(Select): async def callback(self, interaction: Interaction): await interaction.response.send_message(f'Bạn vừa chọn lựa chọn số {self.values[0]}!', ephemeral=True)
layout = LayoutView(timeout=300)
options = [ SelectOption(emoji='💖', value='1', label='Số 1', description='Lựa chọn số 1'), SelectOption(emoji=PartialEmoji.from_str('<a:gura_bounce:1311328344008032388>'), value='2', label='Số 2', description='Lựa chọn số 2'),]
row = ActionRow( MySelect(placeholder='Chọn 1 lựa chọn', options=options))
layout.add_item(row)
await channel.send(view=layout)
Separator (Ngăn cách)
Separator (Ngăn cách) là một thành phần bố cục cấp cao (top-level layout component) dùng để thêm khoảng đệm ngang (horizontal padding) và tạo sự phân chia trực quan giữa các thành phần khác trong tin nhắn.
Bạn cần tạo, hoặc sửa 1 giao diện có sẵn qua lệnh /layout edit
.
Sau khi đã chọn cho mình được giao diện cần chỉnh sửa, hãy bấm ➕ Thêm
, chọn lựa chọn Separator. Bot sẽ tự thêm ngăn cách cho bạn mà không phải nhập gì thêm.
Separator không có lưu ý đặc biệt nào. Chúng ta có thể dựa vào đây để gửi 1 Separator (trong layout mới):
from discord import SeparatorSpacingfrom discord.ui import LayoutView, Separator, TextDisplay
layout = LayoutView(timeout=300)
top = TextDisplay('Bắc Triều Tiên')separator = Separator(visible=True, spacing=SeparatorSpacing.small)bottom = TextDisplay('Nam Triều Tiên')
for item in (top, separator, bottom): layout.add_item(item)
await channel.send(view=layout)

Section (Nội dung đa phương tiện)
Section (Nội dung đa phương tiện) là một thành phần bố cục cấp cao (top-level layout component) cho phép bạn liên kết nội dung chính (text) với một thành phần phụ đi kèm (accessory component) theo ngữ cảnh.
Trường hợp sử dụng phổ biến nhất là kết hợp nội dung văn bản với một thành phần phụ, ví dụ như nút, hoặc hình ảnh.
Bạn cần tạo, hoặc sửa 1 giao diện có sẵn qua lệnh /layout edit
.
Sau khi đã chọn cho mình được giao diện cần chỉnh sửa, hãy bấm ➕ Thêm
, sau đó:
- Chọn Section - Button, nếu bạn muốn thêm 1 Nội dung có chứa Nút
- Chọn Section - Image, nếu bạn muốn thêm 1 Nội dung có chứa ảnh thumbnail
Sau đó, bạn nhập những phần như bot yêu cầu.
Chúng ta có thể dựa vào đây để gửi 1 Section:
from discord import SeparatorSpacingfrom discord.ui import LayoutView, Section, Container, Button, TextDisplay, Thumbnail, Separator
layout = LayoutView(timeout=300)
items = [ # Section đầu tiên, sử dụng Thumbnail Section( TextDisplay( f'Chào mừng **{user.name}** đã đến với server!\n\n' '- 🧯 Để yêu cầu support, gửi tin nhắn tại <#1246856105074626634>\n' '- 💬 Tham gia chat với mọi người tại <#1145547639618801736>' ), accessory=Thumbnail(media=user.avatar.url, spoiler=False) ),
# Separator để phân chia 2 Section Separator(visible=True, spacing=SeparatorSpacing.large),
# Section thứ 2, sử dụng Button Section( TextDisplay('Để xem các module của bot, bạn có thể đọc thêm \ntại đây nhé!!'), accessory=Button(emoji='📖', label='Tài liệu', url='https://bot.tudubucket.dev/getting-started/') )]
for item in items: layout.add_item(item)
await channel.send(view=layout)

Media Gallery (Sưu tập ảnh)
Media Gallery (Bộ sưu tập phương tiện) là một thành phần nội dung cấp cao (top-level content component) cho phép bạn hiển thị từ 1 đến 10 tệp phương tiện (hình ảnh, video, v.v.) trong dạng bố cục dạng thư viện (gallery) gọn gàng và có tổ chức.
Mỗi mục trong bộ sưu tập có thể kèm mô tả tùy chọn và được đánh dấu là nội dung tiết lộ (spoiler) để làm mờ nếu cần.
Bạn cần tạo, hoặc sửa 1 giao diện có sẵn qua lệnh /layout edit
.
Sau khi đã chọn cho mình được giao diện cần chỉnh sửa, hãy bấm ➕ Thêm
, sau đó chọn Media Gallery, rồi nhập các đường dẫn (URL) hình ảnh mà bạn muốn hiển thị, mỗi ảnh 1 dòng.
Dựa theo BucketScript, Bạn cũng có thể sử dụng các placeholder như {user_avatar}
hoặc {server_icon}
thay cho 1 URL để hiển thị avatar của người dùng hoặc icon của server.
Chúng ta có thể dựa vào đây để gửi 1 Media Gallery:
from discord import MediaGalleryItemfrom discord.ui import LayoutView, MediaGallery
layout = LayoutView(timeout=300)
gallery = MediaGallery( MediaGalleryItem('https://cdn.tudubucket.dev/widebucket.png'), MediaGalleryItem('https://cdn.tudubucket.dev/gura_bounce.gif'), MediaGalleryItem('https://cdn.tudubucket.dev/gura_bounce.gif'), MediaGalleryItem('https://cdn.tudubucket.dev/gura_bounce.gif'),)
layout.add_item(gallery)
await channel.send(view=layout)

Container (Vùng chứa)
Container (Vùng chứa) là một thành phần bố cục cấp cao (top-level layout component).
Thành phần này cho phép bạn gom nhóm và bao bọc trực quan nhiều thành phần khác vào cùng một khối, đồng thời có thể tùy chỉnh thêm thanh màu (accent color bar) giống như Embed để tạo điểm nhấn.
Nói 1 cách đơn giản, vùng chứa này có giao diện giống Embed, nhưng để chứa các thành phần mới, giúp thông tin hiển thị trực quan hơn.
Bạn cần tạo, hoặc sửa 1 giao diện có sẵn qua lệnh /layout edit
.
Sau khi đã chọn cho mình được giao diện cần chỉnh sửa, hãy bấm ➕ Thêm
, sau đó chọn Container, nhập các thông tin như màu hoặc spoiler
Bot sẽ hiện cho bạn vùng chứa lên để chỉnh sửa (thêm/xóa) các thành phần khác được miêu tả trước đó.
Chúng ta có thể dựa vào đây để gửi 1 Container:
from discord import SeparatorSpacing, MediaGalleryItemfrom discord.ui import LayoutView, Container, TextDisplay, MediaGallery, Button, Section, Separator
ATTACHMENT_CDN = 'https://cdn.discordapp.com/attachments/697138785317814292'
layout = LayoutView(timeout=None)container = Container( MediaGallery(MediaGalleryItem(f'{ATTACHMENT_CDN}/1364347504702914602/docs-header.png')),
TextDisplay('### Giới thiệu các thành phần mới cho tin nhắn!'),
TextDisplay( 'Trước đây, hệ thống thành phần cũ dù **hoạt động ổn định**, nhưng vẫn có **nhiều hạn chế**. \n' 'Nội dung, tệp đính kèm, embed và các thành phần khác **phải tuân theo vị trí cố định**.\n\n'),
MediaGallery(MediaGalleryItem(f'{ATTACHMENT_CDN}/1364347505642569850/components-hero.png')),
TextDisplay( 'Hệ thống thành phần mới trên đây **đã khắc phục hoàn toàn các giới hạn đó**, ' 'với **các thành phần có thể kết hợp tự do (fully composable)** - bạn có thể **sắp xếp, bố trí** ' 'theo bất kỳ thứ tự nào, tạo nên **thiết kế linh hoạt và hấp dẫn hơn về mặt trực quan**.' ),
Separator(visible=True, spacing=SeparatorSpacing.small),
Section( TextDisplay('Tài liệu liên quan về các thành phần mới:'), accessory=Button(label='Overview', url='https://discord.com/developers/docs/components/overview') ),
Section( TextDisplay('Danh sách các thành phần mới:'), accessory=Button(label='Reference', url='https://discord.com/developers/docs/components/reference') ))
layout.add_item(container)await channel.send(view=layout)

Các lệnh dựng layout của bot
/layout create
Tạo một layout (giao diện)
Tham số lệnh (Parameters)
Bắt buộc:name
: Chỉ định tên layout (dạng ID, chỉ được sử dụng chữ cái thường, dấu gạch _ và số)
Ví dụ sử dụng
-
Tạo layout bằng lệnh:
/layout create name:welcome -
Thực hiện chỉnh sửa layout qua Interactive UI.
-
Sau khi hoàn thành chỉnh sửa Layout, tạo một autoresponder như sau:
command /autoresponder add trigger:wlc ignorecase:True -
Nhập chuỗi kí tự sau vào ô
Phản hồi
:command {layout:welcome} -
Khi có người gõ đúng “wlc”, bot sẽ gửi layout
welcome
ra.
/layout edit
Chỉnh sửa 1 layout (giao diện) có sẵn
Tham số lệnh (Parameters)
Bắt buộc:name
: Chỉ định tên layout
Ví dụ sử dụng lệnh
Lệnh này sẽ chỉnh sửa layout welcome
/layout edit name:welcome
/layout delete
Xóa 1 layout (giao diện) có sẵn
Tham số lệnh (Parameters)
Bắt buộc:name
: Chỉ định tên layout
Ví dụ sử dụng lệnh
Lệnh này sẽ xóa layout welcome
/layout delete name:welcome