diff --git a/README.md b/README.md
index 827e847..060c6b6 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
TypstMomoTalk 是 Typst 的一个模板,专用于制作碧蓝档案的 MomoTalk 聊天记录图片。
相较于其他编辑器的优点:
-* 高度可自定义;
+* 高度可自定义,易于扩展修改;
* 类似于 Markdown 的纯文本式编辑体验;
* 可导出为 SVG 与 PDF 矢量图。
相较于其他编辑器的缺点:
@@ -26,12 +26,12 @@ WIP
## 待办 Todo
- 更多消息
- [ ] 支持行动消息的人物注明
- - [ ] 支持文件消息
+ - [x] 支持文件消息
- [ ] 支持分享卡片消息
- [ ] 支持转账/红包消息
- 其他
- - [ ] i18n 支持;
- - [ ] 优化分页逻辑。
+ - [ ] i18n 支持
+ - [ ] 优化分页逻辑
## 版权 Copyright
本项目中所有游戏素材图片均来自 [SchaleDB](https://schale.gg/),版权归上海悠星网络科技有限公司(Yostar)与韩国乐线股份有限公司(NEXON)所属。
diff --git a/examples/introduction.typ b/examples/introduction.typ
index 2cee8c2..43eeaa7 100644
--- a/examples/introduction.typ
+++ b/examples/introduction.typ
@@ -1,4 +1,5 @@
#import "/momotalk/momotalk.typ": *
+#import "/momotalk/files.typ": *
#import "/momotalk/characters.typ" : *
#show: doc => chat(
doc,
@@ -28,6 +29,7 @@
(PS:由于字体原因,粗体和中文斜体无法显示。)
],
[当然,你也可以插入图片:#image("/examples/azusa.jpg", width: 30%)],
+ // arguments(no_box: true)[#image("/examples/azusa.jpg", width: 30%)],
[
以及标题:
= 标题
@@ -114,11 +116,19 @@
))
#sensei(voice_call[对方已拒绝])
-#yuuka[行动消息展示:]
+#yuuka[行动消息:]
#action[这是一条行动消息 #emoji.thumb]
#time[15:22:41]
#unsend[优香]
#unsend[优香]
#time[以下是新消息]
+#yuuka[文件消息:]
+#yuuka((
+ file("RABBIT dance.mp3", "3.2 MB"),
+ file("a.mp4", "4.7 GB"),
+ file("本月开支.xlsx", "2.7 MB", footer: [MomoTalk 电脑版])
+))
+#sensei(file("检讨.docx", "6.7 MB"))
+
#yuuka[更多消息类型正在开发中!]
\ No newline at end of file
diff --git a/momotalk/assets/files/audio.svg b/momotalk/assets/files/audio.svg
new file mode 100644
index 0000000..b42577b
--- /dev/null
+++ b/momotalk/assets/files/audio.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/momotalk/assets/files/code.svg b/momotalk/assets/files/code.svg
new file mode 100644
index 0000000..c67cf1f
--- /dev/null
+++ b/momotalk/assets/files/code.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/momotalk/assets/files/document.svg b/momotalk/assets/files/document.svg
new file mode 100644
index 0000000..4921a1f
--- /dev/null
+++ b/momotalk/assets/files/document.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/momotalk/assets/files/exe.svg b/momotalk/assets/files/exe.svg
new file mode 100644
index 0000000..f7ac6b8
--- /dev/null
+++ b/momotalk/assets/files/exe.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/momotalk/assets/files/image.svg b/momotalk/assets/files/image.svg
new file mode 100644
index 0000000..f6838f2
--- /dev/null
+++ b/momotalk/assets/files/image.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/momotalk/assets/files/pack.svg b/momotalk/assets/files/pack.svg
new file mode 100644
index 0000000..bcf9d67
--- /dev/null
+++ b/momotalk/assets/files/pack.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/momotalk/assets/files/pdf.svg b/momotalk/assets/files/pdf.svg
new file mode 100644
index 0000000..15a1b35
--- /dev/null
+++ b/momotalk/assets/files/pdf.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/momotalk/assets/files/psd.svg b/momotalk/assets/files/psd.svg
new file mode 100644
index 0000000..154de2d
--- /dev/null
+++ b/momotalk/assets/files/psd.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/momotalk/assets/files/sheet.svg b/momotalk/assets/files/sheet.svg
new file mode 100644
index 0000000..189a7d5
--- /dev/null
+++ b/momotalk/assets/files/sheet.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/momotalk/assets/files/slide.svg b/momotalk/assets/files/slide.svg
new file mode 100644
index 0000000..3c0bb64
--- /dev/null
+++ b/momotalk/assets/files/slide.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/momotalk/assets/files/txt.svg b/momotalk/assets/files/txt.svg
new file mode 100644
index 0000000..4502f38
--- /dev/null
+++ b/momotalk/assets/files/txt.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/momotalk/assets/files/unknown.svg b/momotalk/assets/files/unknown.svg
new file mode 100644
index 0000000..c4cb84d
--- /dev/null
+++ b/momotalk/assets/files/unknown.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/momotalk/assets/files/video.svg b/momotalk/assets/files/video.svg
new file mode 100644
index 0000000..1529599
--- /dev/null
+++ b/momotalk/assets/files/video.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/momotalk/files.typ b/momotalk/files.typ
index cd1c329..e2abdf7 100644
--- a/momotalk/files.typ
+++ b/momotalk/files.typ
@@ -1 +1,159 @@
-#import "momotalk.typ" : *
\ No newline at end of file
+#import "momotalk.typ" : *
+
+#let FORMAT_VIDEO = "assets/files/video.svg"
+#let FORMAT_AUDIO = "assets/files/audio.svg"
+#let FORMAT_IMAGE = "assets/files/image.svg"
+#let FORMAT_TEXT = "assets/files/txt.svg"
+#let FORMAT_PDF = "assets/files/pdf.svg"
+#let FORMAT_DOCUMENT = "assets/files/document.svg"
+#let FORMAT_SHEET = "assets/files/sheet.svg"
+#let FORMAT_SLIDES = "assets/files/slides.svg"
+#let FORMAT_ARCHIVE = "assets/files/pack.svg"
+#let FORMAT_CODE = "assets/files/code.svg"
+#let FORMAT_EXECUTABLE = "assets/files/exe.svg"
+#let FORMAT_PSD = "assets/files/psd.svg"
+#let FORMAT_UNKNOWN = "assets/files/unknown.svg"
+
+#let ICON_MAP = (
+ // 音频
+ "mp3": FORMAT_AUDIO,
+ "wav": FORMAT_AUDIO,
+ "flac": FORMAT_AUDIO,
+ "ape": FORMAT_AUDIO,
+ "aac": FORMAT_AUDIO,
+ "ogg": FORMAT_AUDIO,
+ "wma": FORMAT_AUDIO,
+ "m4a": FORMAT_AUDIO,
+ // 视频
+ "mp4": FORMAT_VIDEO,
+ "avi": FORMAT_VIDEO,
+ "mkv": FORMAT_VIDEO,
+ "rmvb": FORMAT_VIDEO,
+ "rm": FORMAT_VIDEO,
+ "wmv": FORMAT_VIDEO,
+ "mov": FORMAT_VIDEO,
+ "flv": FORMAT_VIDEO,
+ "f4v": FORMAT_VIDEO,
+ "m4v": FORMAT_VIDEO,
+ "3gp": FORMAT_VIDEO,
+ "3g2": FORMAT_VIDEO,
+ "webm": FORMAT_VIDEO,
+ // 图片
+ "jpg": FORMAT_IMAGE,
+ "jpeg": FORMAT_IMAGE,
+ "png": FORMAT_IMAGE,
+ "gif": FORMAT_IMAGE,
+ "bmp": FORMAT_IMAGE,
+ "webp": FORMAT_IMAGE,
+ "tiff": FORMAT_IMAGE,
+ "svg": FORMAT_IMAGE,
+ // 文档
+ "pdf": FORMAT_PDF,
+ "doc": FORMAT_DOCUMENT,
+ "docx": FORMAT_DOCUMENT,
+ "xls": FORMAT_SHEET,
+ "xlsx": FORMAT_SHEET,
+ "ppt": FORMAT_SLIDES,
+ "pptx": FORMAT_SLIDES,
+ // 压缩包
+ "zip": FORMAT_ARCHIVE,
+ "rar": FORMAT_ARCHIVE,
+ "7z": FORMAT_ARCHIVE,
+ "tar": FORMAT_ARCHIVE,
+ "gz": FORMAT_ARCHIVE,
+ "bz2": FORMAT_ARCHIVE,
+ "xz": FORMAT_ARCHIVE,
+ "z": FORMAT_ARCHIVE,
+ "lz": FORMAT_ARCHIVE,
+ "lzma": FORMAT_ARCHIVE,
+ "cab": FORMAT_ARCHIVE,
+ "iso": FORMAT_ARCHIVE,
+ // 代码
+ "c": FORMAT_CODE,
+ "cpp": FORMAT_CODE,
+ "h": FORMAT_CODE,
+ "hpp": FORMAT_CODE,
+ "java": FORMAT_CODE,
+ "cs": FORMAT_CODE,
+ "py": FORMAT_CODE,
+ "go": FORMAT_CODE,
+ "js": FORMAT_CODE,
+ "ts": FORMAT_CODE,
+ "html": FORMAT_CODE,
+ "css": FORMAT_CODE,
+ "php": FORMAT_CODE,
+ "json": FORMAT_CODE,
+ "xml": FORMAT_CODE,
+ "md": FORMAT_CODE,
+ "sh": FORMAT_CODE,
+ "bat": FORMAT_CODE,
+ // 其他
+ "exe": FORMAT_EXECUTABLE,
+ "txt": FORMAT_TEXT,
+ "psd": FORMAT_PSD,
+)
+
+// 产生一条文件消息内容。
+// @param file_icon str 文件图标路径
+// @param file_name str 文件名
+// @param file_size str 文件大小
+// @param footer str|content|none 附加信息
+#let __file(
+ file_icon,
+ file_name,
+ file_size,
+ footer: "MomoTalk 手机版",
+) = {
+ // 参数检查
+ if (file_icon == none) {
+ panic("file_icon is none")
+ }
+ if (file_name == none) {
+ panic("file_name is none")
+ }
+ if (file_size == none) {
+ panic("file_size is none")
+ }
+
+ // 渲染
+ let result = rect(
+ radius: 3pt,
+ stroke: 0.5pt + rgb("#e0e0e0"),
+ inset: 10pt,
+ width: 15em
+ )[
+ #grid(
+ columns: (auto, 1fr),
+ rows: 1,
+ column-gutter: 1.5em,
+ [
+ #file_name \
+ #align(text(size: 0.8em, fill: rgb("#999"))[#file_size], left)
+ ],
+ align(image(file_icon, width: 3em), right)
+ )
+ #text(size: 0.8em, fill: rgb("#999"))[#footer]
+ ]
+ // 以无边框消息返回
+ arguments(no_box: true, result)
+}
+
+// 产生一条文件消息内容。
+// @param file_name str 文件名
+// @param file_size str 文件大小
+// @param footer str|content|none 附加信息
+#let file(
+ file_name,
+ file_size,
+ footer: "MomoTalk 手机版",
+) = {
+ // 自动判断文件类型
+ let file_icon = none
+ let file_ext = file_name.split(".").at(-1)
+ __file(
+ ICON_MAP.at(file_ext, default: FORMAT_UNKNOWN),
+ file_name,
+ file_size,
+ footer: footer,
+ )
+}
\ No newline at end of file
diff --git a/momotalk/momotalk.typ b/momotalk/momotalk.typ
index 1234350..7ec8c27 100644
--- a/momotalk/momotalk.typ
+++ b/momotalk/momotalk.typ
@@ -89,7 +89,7 @@
triangle = scale(triangle, x: 50%, y: 50%)
if (no_box){
- return text(fill: white, content)
+ return text(content)
}
if (direction == "left") {
@@ -130,7 +130,9 @@
// @param name str|none 发送者名字。可空。
// @param avatar_path str|none 头像图片路径。可空
// @param direction str 消息方向。可选 left、right。
-// @param contents array|content|str 消息内容。
+// @param contents any|arguments|array[any|arguments]
+// 消息内容。可以为空,或 content/str 对象。
+// 也可以是一个 arguments 对象,相当于传入给 `msgbox` 函数的参数。
#let messages(
name,
avatar_path,
@@ -159,18 +161,24 @@
weight: "bold",
name
))
+
+ // 然后渲染消息框
+ let render(_content, _direction) = {
+ if (type(_content) == arguments) {
+ msgbox(.._content)
+ }
+ else {
+ msgbox(
+ direction: _direction,
+ background_color: background_color,
+ _content
+ )
+ }
+ }
// 第一个消息框有小三角,后续的没有
- rendered_contents.push(msgbox(
- contents.remove(0),
- direction: direction,
- background_color: background_color
- ))
+ rendered_contents.push(render(contents.remove(0), direction))
for c in contents {
- rendered_contents.push(msgbox(
- c,
- direction: "none",
- background_color: background_color
- ))
+ rendered_contents.push(render(c, "none"))
}
// 头像部分