Một giao diện là một tệp JSON nhỏ: bảng màu, chất giấy, độ bo góc, và nếu muốn thì cả cách sắp các khối trên tờ lịch. Lấy một bộ trong kho giao diện, đổi thứ bạn muốn, rồi nhập lại vào app.
.json nằm cạnh gói
.lunayatheme.id thành tên của bạn. Id trùng một giao diện dựng sẵn thì app
bỏ qua im lặng — không lỗi, không giao diện mới. Chín id đã dùng:
do-tet · gach-bong · giay-cu · giay-do · giay-moi · muc-dem · nuoc-luc · son-mai · truc-xanh.name và các màu. Giữ basedOn — nó kế thừa mọi trường bạn
không viết.<id-của-bạn>.lunayatheme rồi nhập: trong Lunaya,
Cài đặt → Giao diện → Nhập theme từ file. JSON trần cũng được — app
đọc bốn byte đầu và nhận cả hai dạng.Mười một token. Mọi màu trong app lấy từ một trong số đó, nên một giao diện không bao giờ khai một màu hai lần. Giá trị dạng #RRGGBB.
| Token | Dùng cho |
|---|---|
paper | Màu giấy — nền của cả tờ lịch |
paperShade | Nền phụ, sát màu giấy — ô đang chọn, dải chip |
ink | Mực chính — số ngày, chữ thường |
inkFaint | Mực nhạt — nhãn nhỏ, chú thích |
vermilion | Mực son — tên ngày lễ, chủ nhật |
seal | Dấu triện — viền ngày hôm nay |
jade | Mực lục — icon con giáp, chữ can chi |
gold | Kim nhũ — điểm nhấn hiếm |
divider | Đường kẻ phân cách |
surface | Nền thẻ nổi trên giấy |
onSurface | Chữ trên nền thẻ |
App đo tỉ số tương phản WCAG giữa ink và paper. Dưới 4.5 thì cảnh báo, dưới 3 thì cảnh báo mạnh hơn. Nó không bao giờ từ chối tệp — một giao diện khó đọc vẫn là lựa chọn của bạn, và cảnh báo nói rõ cặp màu nào có vấn đề.
Hai token dễ quên: inkFaint là màu các nhãn nhỏ, còn vermilion là màu tên ngày lễ và chủ nhật. Cả hai đều là chữ thật — đo chúng với paper nữa, đừng chỉ đo ink.
Hạt giấy, vệt ố và mực lem do app vẽ lên trên màu giấy. Hoa văn được vẽ bằng mã chứ không phải ảnh, nên nó đi theo màu mực của bạn và nét ở mọi mật độ. Năm slug:
hoi-van · song-nuoc · tram-cham · mat-vai · hoa-thi
Viết 5.0 vào chỗ khoảng chỉ tới 1.4 thì app dùng 1.4, chứ không bỏ tệp đi. Đó là cố ý: một con số lỡ vượt biên không nên làm mất cả giao diện. Khoảng đọc từ đặc tả:
| Trường | min | max |
|---|---|---|
typography.scale.dayNumber |
0.7 | 1.4 |
typography.scale.body |
0.7 | 1.4 |
texture.grainAlpha |
0 | 0.25 |
texture.stainAlpha |
0 | 0.25 |
texture.inkBleed |
0 | 1 |
shapes.cornerRadius |
0 | 24 |
shapes.borderWidth |
0 | 4 |
shapes.dividerWidth |
0 | 4 |
component.style.scale |
0.7 | 1.4 |
component.style.opacity |
0.2 | 1 |
texture.patternAlpha |
0 | 0.12 |
texture.patternScale |
0.5 | 2.5 |
Đặt isDark để nói bảng màu của bạn thuộc loại nào. Một giao diện sáng có thể kèm darkVariant — cùng tên token, giá trị khác — và app đổi sang đó khi cần bản tối. Bỏ trống thì giao diện giữ nguyên như đã viết.
Màn Hôm nay không phải một bố cục cố định — app vẽ nó theo một cây mà giao diện của bạn mô tả được. Bạn đặt thành phần vào những ô có tên, không đặt toạ độ. Toạ độ tự do vỡ trên mọi cỡ màn khác cỡ màn của bạn, và một bố cục hỏng thì không kẹp lại được như một màu hỏng.
| Ô chứa | min | max | Thành phần cho phép |
|---|---|---|---|
header |
0 | 2 | weekday month-year holiday-banner image divider spacer |
hero |
1 | 1 | day-number divider spacer |
lunar |
0 | 2 | weekday lunar-date can-chi holiday-banner divider spacer |
info |
0 | 6 | lunar-date can-chi holiday-banner solar-term good-hours quote event-list image divider spacer |
footer |
0 | 2 | month-year quote image divider spacer |
Chạm vào một thành phần thì app quyết định làm gì, theo loại thành phần — giao diện
không đặt được. Phông chữ: be-vietnam-pro · playfair-display · bitter
Tệp .lunayatheme là một zip có theme.json ở gốc, và nếu có ảnh thì một thư mục assets/ bên cạnh. Tên mục phải khớp đúng mẫu dưới đây — đó là danh sách cho phép, chứ không phải danh sách chặn.
ten-giao-dien.lunayatheme
├── theme.json
└── assets/
└── hoa-van.png
| Giới hạn | Giá trị |
|---|---|
fileBytes | 2097152 |
idMaxLength | 128 |
nameMaxLength | 60 |
authorMaxLength | 60 |
descriptionMaxLength | 200 |
maxImages | 2 |
jsonMaxDepth | 32 |
archiveBytes | 2097152 |
archiveUncompressedBytes | 8388608 |
archiveMaxEntries | 8 |
manifestBytes | 262144 |
archiveEntryNamePattern | ^(theme\.json|assets/[a-z0-9._-]{1,64})$ |
archiveMaxEntryBytes | 4194304 |
Lỗi có mã ổn định, nên app và trình soạn trên web có thể khác nhau về câu chữ nhưng không bao giờ khác nhau về nghĩa. ERR_ là từ chối tệp; WARN_ là vẫn nhận và báo cho bạn biết.
| Mã | Nghĩa |
|---|---|
ERR_FORMAT_VERSION_UNSUPPORTED | formatVersion lớn hơn bản app hiểu |
ERR_MISSING_REQUIRED | Thiếu trường bắt buộc |
ERR_ID_INVALID | id sai định dạng hoặc quá dài |
ERR_COLOR_FORMAT | Màu không phải #RRGGBB hoặc #AARRGGBB |
ERR_TOO_LARGE | File vượt giới hạn dung lượng |
ERR_BASEDON_UNKNOWN | basedOn trỏ tới theme dựng sẵn không tồn tại |
ERR_SLOT_UNKNOWN | Tên ô chứa không có trong slots.json |
ERR_SLOT_OVERFLOW | Ô chứa vượt số thành phần cho phép |
ERR_HERO_EMPTY | Ô hero bắt buộc có đúng 1 thành phần |
ERR_COMPONENT_NOT_ALLOWED_IN_SLOT | Loại thành phần không được phép trong ô này |
ERR_TOO_MANY_IMAGES | Vượt số ảnh cho phép |
WARN_CONTRAST_LOW | Tương phản ink/paper dưới 4.5:1 |
WARN_CONTRAST_VERY_LOW | Tương phản ink/paper dưới 3.0:1 — rất khó đọc |
WARN_COMPONENT_UNKNOWN | Loại thành phần không biết — đã bỏ qua |
WARN_FONT_SLUG_UNKNOWN | Slug font không biết — dùng font mặc định |
WARN_VALUE_CLAMPED | Giá trị vượt biên — đã kẹp lại |
ERR_ARCHIVE_INVALID | Gói nén hỏng hoặc không đọc được |
ERR_ARCHIVE_ENTRY_NAME | Tên mục trong gói không nằm trong danh sách cho phép |
ERR_ARCHIVE_TOO_MANY_ENTRIES | Gói có quá nhiều mục |
ERR_ARCHIVE_UNCOMPRESSED_TOO_LARGE | Tổng cỡ sau giải nén vượt trần |
ERR_MANIFEST_MISSING | Gói thiếu theme.json |
ERR_ARCHIVE_ENTRY_TOO_LARGE | Một mục giải nén vượt trần (chặn khi đọc, không tin cỡ khai trong zip) |
ERR_IMAGE_SRC_UNKNOWN | Thành phần image trỏ tới khoá không có trong images |
ERR_IMAGE_SOURCE_INVALID | Nguồn ảnh không phải assets/<tên> hay data: base64 |
WARN_IMAGE_SRC_MISSING | Thành phần image không khai src — sẽ không vẽ gì |
Mọi con số trên trang này đọc từ chính đặc tả của app lúc dựng trang, nên nó không thể cũ đi so với app.