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")) } // 头像部分