@streamplace/components 0.9.7 → 0.9.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/assets/badges/live.png +0 -0
  2. package/assets/badges/live_2x.png +0 -0
  3. package/assets/badges/mod.png +0 -0
  4. package/assets/badges/mod_2x.png +0 -0
  5. package/assets/badges/vip.png +0 -0
  6. package/assets/badges/vip_2x.png +0 -0
  7. package/dist/components/chat/badge.d.ts +10 -0
  8. package/dist/components/chat/badge.d.ts.map +1 -0
  9. package/dist/components/chat/badge.js +29 -0
  10. package/dist/components/chat/badge.js.map +1 -0
  11. package/dist/components/chat/chat-box.d.ts +5 -1
  12. package/dist/components/chat/chat-box.d.ts.map +1 -1
  13. package/dist/components/chat/chat-box.js +55 -50
  14. package/dist/components/chat/chat-box.js.map +1 -1
  15. package/dist/components/chat/chat-message.d.ts.map +1 -1
  16. package/dist/components/chat/chat-message.js +9 -11
  17. package/dist/components/chat/chat-message.js.map +1 -1
  18. package/dist/components/chat/chat.d.ts.map +1 -1
  19. package/dist/components/chat/chat.js +37 -43
  20. package/dist/components/chat/chat.js.map +1 -1
  21. package/dist/components/chat/emoji-suggestions.d.ts +7 -18
  22. package/dist/components/chat/emoji-suggestions.d.ts.map +1 -1
  23. package/dist/components/chat/emoji-suggestions.js +6 -2
  24. package/dist/components/chat/emoji-suggestions.js.map +1 -1
  25. package/dist/components/chat/system-message.d.ts.map +1 -1
  26. package/dist/components/chat/system-message.js +9 -1
  27. package/dist/components/chat/system-message.js.map +1 -1
  28. package/dist/components/chat/teleport-modal.d.ts +9 -0
  29. package/dist/components/chat/teleport-modal.d.ts.map +1 -0
  30. package/dist/components/chat/teleport-modal.js +148 -0
  31. package/dist/components/chat/teleport-modal.js.map +1 -0
  32. package/dist/components/chat/user-profile-card.d.ts +12 -0
  33. package/dist/components/chat/user-profile-card.d.ts.map +1 -0
  34. package/dist/components/chat/user-profile-card.js +135 -0
  35. package/dist/components/chat/user-profile-card.js.map +1 -0
  36. package/dist/components/dashboard/chat-panel.d.ts +3 -1
  37. package/dist/components/dashboard/chat-panel.d.ts.map +1 -1
  38. package/dist/components/dashboard/chat-panel.js +2 -2
  39. package/dist/components/dashboard/chat-panel.js.map +1 -1
  40. package/dist/components/dashboard/header.d.ts +2 -3
  41. package/dist/components/dashboard/header.d.ts.map +1 -1
  42. package/dist/components/dashboard/header.js +6 -2
  43. package/dist/components/dashboard/header.js.map +1 -1
  44. package/dist/components/dashboard/information-widget.d.ts.map +1 -1
  45. package/dist/components/dashboard/information-widget.js +15 -12
  46. package/dist/components/dashboard/information-widget.js.map +1 -1
  47. package/dist/components/mobile-player/fullscreen.d.ts.map +1 -1
  48. package/dist/components/mobile-player/fullscreen.js +2 -1
  49. package/dist/components/mobile-player/fullscreen.js.map +1 -1
  50. package/dist/components/mobile-player/fullscreen.native.d.ts.map +1 -1
  51. package/dist/components/mobile-player/fullscreen.native.js +3 -2
  52. package/dist/components/mobile-player/fullscreen.native.js.map +1 -1
  53. package/dist/components/mobile-player/player.d.ts.map +1 -1
  54. package/dist/components/mobile-player/player.js +15 -0
  55. package/dist/components/mobile-player/player.js.map +1 -1
  56. package/dist/components/mobile-player/ui/audio-only-overlay.d.ts +2 -0
  57. package/dist/components/mobile-player/ui/audio-only-overlay.d.ts.map +1 -0
  58. package/dist/components/mobile-player/ui/audio-only-overlay.js +29 -0
  59. package/dist/components/mobile-player/ui/audio-only-overlay.js.map +1 -0
  60. package/dist/components/mobile-player/ui/index.d.ts +1 -0
  61. package/dist/components/mobile-player/ui/index.d.ts.map +1 -1
  62. package/dist/components/mobile-player/ui/index.js +1 -0
  63. package/dist/components/mobile-player/ui/index.js.map +1 -1
  64. package/dist/components/mobile-player/ui/input.d.ts +3 -2
  65. package/dist/components/mobile-player/ui/input.d.ts.map +1 -1
  66. package/dist/components/mobile-player/ui/input.js +18 -2
  67. package/dist/components/mobile-player/ui/input.js.map +1 -1
  68. package/dist/components/mobile-player/ui/metrics.d.ts.map +1 -1
  69. package/dist/components/mobile-player/ui/metrics.js +20 -2
  70. package/dist/components/mobile-player/ui/metrics.js.map +1 -1
  71. package/dist/components/mobile-player/ui/streamer-context-menu.d.ts +3 -1
  72. package/dist/components/mobile-player/ui/streamer-context-menu.d.ts.map +1 -1
  73. package/dist/components/mobile-player/ui/streamer-context-menu.js +64 -2
  74. package/dist/components/mobile-player/ui/streamer-context-menu.js.map +1 -1
  75. package/dist/components/mobile-player/ui/viewer-context-menu.d.ts.map +1 -1
  76. package/dist/components/mobile-player/ui/viewer-context-menu.js +29 -1
  77. package/dist/components/mobile-player/ui/viewer-context-menu.js.map +1 -1
  78. package/dist/components/mobile-player/use-webrtc.d.ts +4 -2
  79. package/dist/components/mobile-player/use-webrtc.d.ts.map +1 -1
  80. package/dist/components/mobile-player/use-webrtc.js +89 -15
  81. package/dist/components/mobile-player/use-webrtc.js.map +1 -1
  82. package/dist/components/mobile-player/video-async.native.d.ts.map +1 -1
  83. package/dist/components/mobile-player/video-async.native.js +15 -5
  84. package/dist/components/mobile-player/video-async.native.js.map +1 -1
  85. package/dist/components/mobile-player/video.d.ts.map +1 -1
  86. package/dist/components/mobile-player/video.js +10 -7
  87. package/dist/components/mobile-player/video.js.map +1 -1
  88. package/dist/components/ui/dialog.d.ts.map +1 -1
  89. package/dist/components/ui/dialog.js +8 -0
  90. package/dist/components/ui/dialog.js.map +1 -1
  91. package/dist/components/ui/textarea.d.ts.map +1 -1
  92. package/dist/components/ui/textarea.js +1 -1
  93. package/dist/components/ui/textarea.js.map +1 -1
  94. package/dist/hooks/index.d.ts +1 -0
  95. package/dist/hooks/index.d.ts.map +1 -1
  96. package/dist/hooks/index.js +1 -0
  97. package/dist/hooks/index.js.map +1 -1
  98. package/dist/hooks/useAQState.d.ts +2 -0
  99. package/dist/hooks/useAQState.d.ts.map +1 -0
  100. package/dist/hooks/useAQState.js +37 -0
  101. package/dist/hooks/useAQState.js.map +1 -0
  102. package/dist/hooks/useLivestreamInfo.d.ts +1 -2
  103. package/dist/hooks/useLivestreamInfo.d.ts.map +1 -1
  104. package/dist/hooks/useLivestreamInfo.js +18 -22
  105. package/dist/hooks/useLivestreamInfo.js.map +1 -1
  106. package/dist/hooks/useSegmentTiming.d.ts +1 -1
  107. package/dist/hooks/useSegmentTiming.d.ts.map +1 -1
  108. package/dist/hooks/useSegmentTiming.js +4 -0
  109. package/dist/hooks/useSegmentTiming.js.map +1 -1
  110. package/dist/i18n/i18n-loader.native.d.ts.map +1 -1
  111. package/dist/i18n/i18n-loader.native.js +13 -4
  112. package/dist/i18n/i18n-loader.native.js.map +1 -1
  113. package/dist/lib/slash-commands/teleport.d.ts +5 -1
  114. package/dist/lib/slash-commands/teleport.d.ts.map +1 -1
  115. package/dist/lib/slash-commands/teleport.js +57 -1
  116. package/dist/lib/slash-commands/teleport.js.map +1 -1
  117. package/dist/lib/theme/atoms.d.ts +125 -125
  118. package/dist/livestream-store/chat.d.ts +1 -0
  119. package/dist/livestream-store/chat.d.ts.map +1 -1
  120. package/dist/livestream-store/chat.js +10 -1
  121. package/dist/livestream-store/chat.js.map +1 -1
  122. package/dist/livestream-store/livestream-state.d.ts +2 -0
  123. package/dist/livestream-store/livestream-state.d.ts.map +1 -1
  124. package/dist/livestream-store/livestream-store.d.ts +1 -1
  125. package/dist/livestream-store/livestream-store.d.ts.map +1 -1
  126. package/dist/livestream-store/livestream-store.js +10 -1
  127. package/dist/livestream-store/livestream-store.js.map +1 -1
  128. package/dist/livestream-store/websocket-consumer.d.ts.map +1 -1
  129. package/dist/livestream-store/websocket-consumer.js +1 -0
  130. package/dist/livestream-store/websocket-consumer.js.map +1 -1
  131. package/dist/player-store/player-state.d.ts +3 -5
  132. package/dist/player-store/player-state.d.ts.map +1 -1
  133. package/dist/player-store/player-store.d.ts.map +1 -1
  134. package/dist/player-store/player-store.js +28 -5
  135. package/dist/player-store/player-store.js.map +1 -1
  136. package/dist/player-store/single-player-provider.d.ts +0 -2
  137. package/dist/player-store/single-player-provider.d.ts.map +1 -1
  138. package/dist/player-store/single-player-provider.js +0 -2
  139. package/dist/player-store/single-player-provider.js.map +1 -1
  140. package/dist/streamplace-store/branding.d.ts.map +1 -1
  141. package/dist/streamplace-store/branding.js +52 -1
  142. package/dist/streamplace-store/branding.js.map +1 -1
  143. package/dist/streamplace-store/stream.d.ts +4 -2
  144. package/dist/streamplace-store/stream.d.ts.map +1 -1
  145. package/dist/streamplace-store/stream.js +36 -74
  146. package/dist/streamplace-store/stream.js.map +1 -1
  147. package/locales/en-US/common.ftl +13 -1
  148. package/locales/manifest.json +21 -1
  149. package/locales/ro-RO/common.ftl +74 -0
  150. package/locales/ro-RO/settings.ftl +233 -0
  151. package/locales/zh-Hans/common.ftl +57 -0
  152. package/locales/zh-Hans/settings.ftl +222 -0
  153. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
  154. package/package.json +2 -2
  155. package/src/components/chat/badge.tsx +45 -0
  156. package/src/components/chat/chat-box.tsx +84 -54
  157. package/src/components/chat/chat-message.tsx +25 -21
  158. package/src/components/chat/chat.tsx +107 -90
  159. package/src/components/chat/emoji-suggestions.tsx +12 -21
  160. package/src/components/chat/system-message.tsx +12 -2
  161. package/src/components/chat/teleport-modal.tsx +310 -0
  162. package/src/components/chat/user-profile-card.tsx +275 -0
  163. package/src/components/dashboard/chat-panel.tsx +8 -0
  164. package/src/components/dashboard/header.tsx +8 -17
  165. package/src/components/dashboard/information-widget.tsx +17 -10
  166. package/src/components/mobile-player/fullscreen.native.tsx +3 -0
  167. package/src/components/mobile-player/fullscreen.tsx +2 -0
  168. package/src/components/mobile-player/player.tsx +22 -1
  169. package/src/components/mobile-player/ui/audio-only-overlay.tsx +48 -0
  170. package/src/components/mobile-player/ui/index.ts +1 -0
  171. package/src/components/mobile-player/ui/input.tsx +42 -12
  172. package/src/components/mobile-player/ui/metrics.tsx +17 -2
  173. package/src/components/mobile-player/ui/streamer-context-menu.tsx +138 -2
  174. package/src/components/mobile-player/ui/viewer-context-menu.tsx +40 -3
  175. package/src/components/mobile-player/use-webrtc.tsx +118 -17
  176. package/src/components/mobile-player/video-async.native.tsx +18 -5
  177. package/src/components/mobile-player/video.tsx +10 -7
  178. package/src/components/ui/dialog.tsx +8 -0
  179. package/src/components/ui/textarea.tsx +2 -0
  180. package/src/hooks/index.ts +1 -0
  181. package/src/hooks/useAQState.ts +37 -0
  182. package/src/hooks/useLivestreamInfo.ts +21 -22
  183. package/src/hooks/useSegmentTiming.tsx +7 -2
  184. package/src/i18n/i18n-loader.native.ts +9 -0
  185. package/src/lib/slash-commands/teleport.ts +68 -0
  186. package/src/livestream-store/chat.tsx +12 -0
  187. package/src/livestream-store/livestream-state.tsx +2 -0
  188. package/src/livestream-store/livestream-store.tsx +9 -1
  189. package/src/livestream-store/websocket-consumer.tsx +1 -0
  190. package/src/player-store/player-state.tsx +4 -7
  191. package/src/player-store/player-store.tsx +33 -7
  192. package/src/player-store/single-player-provider.tsx +0 -4
  193. package/src/streamplace-store/branding.tsx +60 -1
  194. package/src/streamplace-store/stream.tsx +42 -99
  195. package/node-compile-cache/v22.15.0-x64-92db9086-0/37be0eec +0 -0
@@ -0,0 +1,222 @@
1
+ # Settings Page Translations - Chinese (Simplified)
2
+
3
+ ## App Version
4
+ app-version = Streamplace v{ $version }
5
+ download-new-update = 下载新更新
6
+ check-for-updates = 检查更新
7
+
8
+ bundled-runtype = 捆绑版
9
+ ota-runtype = 空中下载 (OTA)
10
+ recovery-runtype = 复原模式
11
+
12
+ modal-latest-version = 您正在使用最新版本。
13
+ modal-no-update-available = 您已经在使用最新版本的 Streamplace,太棒了!
14
+ modal-update-available-title = 有可用更新
15
+ modal-update-available-description = 新版本的 Streamplace 已准备好下载
16
+ modal-update-failed = 更新检查失败。您可能需要透过 { $store } 更新应用程序。
17
+ modal-update-failed-title = 更新失败
18
+ modal-update-failed-description = 更新检查失败。您可能需要透过 { $store } 更新应用程序。
19
+ button-reload-app-on-update = 套用更新 (将重新加载应用程序)
20
+
21
+ ## Custom Node Settings
22
+ use-custom-node = 使用自定义节点
23
+ default-url = 默认:{ $url }
24
+ enter-custom-node-url = 输入自定义节点网址
25
+ save-button = 保存
26
+
27
+ ## Language Settings
28
+ language-selection = 语言
29
+ language-selection-description = 选择您偏好的语言
30
+ input-search-languages = 搜索语言...
31
+ help-translate = 帮助我们翻译 Streamplace
32
+ help-translate-description = 我们正在寻找志愿者协助将 Streamplace 翻译成更多语言。如果您有兴趣,请在 Discord 或 GitHub 上与我们联系!
33
+ currently-translating = 翻译正在进行中
34
+ currently-translating-description = 应用程序的某些部分可能看起来不完整。感谢您的耐心等待!
35
+
36
+ ## Debug Recording
37
+ debug-recording-title = 允许 { $host } 录制您的直播串流以进行除错和服务改善
38
+ debug-recording-description = 可选项目
39
+
40
+ ## Key Management
41
+ manage-keys = 管理密钥
42
+
43
+ ## Settings Page Specific
44
+ settings-title = 设置
45
+
46
+ ## Navigation Categories
47
+ about = 关于
48
+ account = 帐户
49
+ advanced = 高端
50
+ danmu = 弹幕
51
+ developer = 开发者
52
+ languages = 语言
53
+ privacy-security = 隐私与安全
54
+ streaming = 串流
55
+
56
+ ## Common Actions
57
+ cancel = 取消
58
+ create = 创建
59
+ delete = 删除
60
+ refresh = 刷新
61
+ save-button = 保存
62
+ sign-in = 登录
63
+ update = 更新
64
+ log-out = 注销
65
+ optional = 选填
66
+
67
+ ## Account Settings
68
+ account-greeting = 嗨,@{ $handle }。
69
+ edit-profile-bluesky = 在 Bluesky 编辑个人数据
70
+ change-name-color = 变更名称颜色
71
+
72
+ ## Key Management
73
+ key-management = 密钥管理
74
+ key-manager = 密钥管理器
75
+ manage-keys = 管理密钥
76
+ your-stream-pubkeys = 您的串流公开密钥
77
+ no-keys = 尚未设置密钥
78
+ pubkey-description = 公开密钥与串流密钥 (用于串流软件) 配对以签署和验证您的串流
79
+ keys-count = { $count } 个密钥
80
+
81
+ ## Recommendations
82
+ recommendations = 推荐主播
83
+ manage-recommendations = 管理推荐主播
84
+ recommendations-to-others = 向他人推荐主播
85
+ recommendations-description = 向您的观众推荐最多 8 位主播
86
+ no-recommendations-yet = 尚未配置推荐
87
+ add-recommendation = 添加推荐
88
+ streamer-did = 主播 DID
89
+ recommendations-count = { $count } 位推荐主播
90
+
91
+ ## Webhook Management
92
+ webhooks = Webhooks
93
+ webhook-integrations = Webhook 集成
94
+ webhook-integrations-description = 连接外部服务以即时接收有关您串流的更新
95
+ create-webhook = 创建 Webhook
96
+ edit-webhook = 编辑 Webhook
97
+ delete-webhook = 删除 Webhook
98
+ no-webhooks-yet = 尚未设置 Webhook
99
+ failed-load-webhooks = 加载 Webhook 失败
100
+ webhook-will-no-longer-receive-events = 此 Webhook 将不再接收事件
101
+ create-first-webhook-description = 创建您的第一个 Webhook 以开始接收串流事件
102
+ example-captain-hook = Hook 船长
103
+ webhooks-count = { $count } 个 Webhook
104
+
105
+ ## Webhook Events
106
+ activates-on = 触发于:
107
+ events = 事件
108
+ events-livestream = 直播串流事件
109
+ events-chat = 聊天事件
110
+ untitled-webhook = 未命名的 Webhook
111
+ inactive = 停用
112
+ active = 活动
113
+
114
+ ## Multistreaming
115
+ multistream = 多重串流
116
+ multistream-targets = 多重串流目标
117
+ multistream-description = 自动将您的 Streamplace 直播推送到 Twitch 或 YouTube 等其他直播平台。
118
+ create-multistream-target = 创建多重串流目标
119
+ untitled-multistream-target = 未命名目标
120
+ failed-load-multistream-targets = 加载多重串流目标失败。请重试。
121
+ failed-toggle-multistream-target = 切换多重串流目标失败。请重试。
122
+ failed-delete-multistream-target = 删除多重串流目标失败。请重试。
123
+ no-multistream-targets-yet = 还没有目标!
124
+ multistream-targets-count = { $count } 个目标
125
+ multistream-delete-target-confirmation = 您确定要删除“{ $target }”吗?
126
+ this-action-cannot-be-undone = 此操作无法撤销。
127
+ rtmp-target-name = RTMP 目标
128
+ rtmp-target-url = RTMP 网址
129
+ rtmp-target-name-placeholder = 我的多重串流目标
130
+ multistream-create-target = 创建目标
131
+ multistream-edit-target = 编辑目标
132
+ created = 创建于
133
+ status = 状态
134
+
135
+ ## Debug Recording
136
+ debug-recording = 调试录制
137
+
138
+ ## Danmu Settings
139
+ danmu = 弹幕
140
+ danmu-enabled = 启用弹幕
141
+ danmu-enabled-description = 将即时聊天消息以浮动评论的形式显示在您的屏幕上
142
+ danmu-opacity = 不透明度
143
+ danmu-speed = 速度
144
+ danmu-lane-count = 轨道数量
145
+ danmu-max-messages = 最大消息数
146
+
147
+ ## General
148
+ app-version-description = 当前没有可用的更新
149
+ confirm-delete = 您确定要删除吗?
150
+ action-cannot-be-undone = 此操作无法撤销
151
+ name-optional = 名称 (选填)
152
+ deleting = 正在删除...
153
+ saving = 正在保存...
154
+ go-to-dashboard = 前往仪表板
155
+ need-setup-live-dashboard = 需要先设置串流吗?请访问直播仪表板
156
+ no-languages-found = 找不到语言
157
+
158
+ ## Branding Administration
159
+ branding = 品牌
160
+ branding-admin = 品牌管理
161
+ branding-admin-description = 自定义您的 Streamplace 实例。请注意,设置可能需要几小时才能生效。
162
+ branding-login-required = 请登录以管理品牌
163
+ branding-configuration = 配置
164
+ branding-text-settings = 文字设置
165
+ branding-colors = 颜色
166
+ branding-legal-links = 法律链接
167
+ branding-images = 图像
168
+
169
+ ## Branding Fields
170
+ branding-broadcaster-did = 主播 DID
171
+ branding-broadcaster-did-description = 留空以使用服务器默认值
172
+ branding-site-title = 网站标题
173
+ branding-site-title-placeholder = 输入新网站标题
174
+ branding-site-description = 网站描述
175
+ branding-site-description-placeholder = 输入网站描述
176
+ branding-default-streamer = 默认主播
177
+ branding-default-streamer-none = 无
178
+ branding-default-streamer-placeholder = did:plc:...
179
+ branding-clear-default-streamer = 清除默认主播
180
+ branding-primary-color = 首要颜色
181
+ branding-primary-color-placeholder = #6366f1
182
+ branding-accent-color = 强调色
183
+ branding-accent-color-placeholder = #8b5cf6
184
+ branding-main-logo = 主标志
185
+ branding-main-logo-description = SVG、PNG 或 JPEG (最大 500KB)
186
+ branding-favicon = 网站图标
187
+ branding-favicon-description = SVG、PNG 或 ICO (最大 100KB)
188
+ branding-sidebar-bg = 侧边栏背景图片
189
+ branding-sidebar-bg-description = SVG、PNG 或 JPEG (最大 500KB) - 显示在侧边栏底部,全宽显示。为了获得最佳效果,请上传一张带有透明度的图片,因为目前没有单独的透明度选项。
190
+ branding-current = 当前:{ $value }
191
+ branding-dimensions = { $height } x { $width }
192
+
193
+ ## Branding Actions
194
+ branding-upload-logo = 上传标志
195
+ branding-delete-logo = 删除标志
196
+ branding-upload-favicon = 上传网站图标
197
+ branding-delete-favicon = 删除网站图标
198
+ branding-upload-background = 上传背景
199
+ branding-delete-background = 删除背景
200
+ branding-web-only = 图像上传仅在网页端可用。
201
+
202
+ ## Branding Legal Links
203
+ refresh-branding = 更新品牌资源
204
+ branding-add-legal-link = 添加法律链接
205
+ branding-edit-legal-link = 编辑法律链接
206
+ branding-legal-link-text-placeholder = 链接文本 (例如:隐私政策)
207
+ branding-legal-link-url-placeholder = 网址 (例如:https://example.com/privacy)
208
+ add = 添加
209
+ edit = 编辑
210
+
211
+ ## Branding Toast Messages
212
+ branding-not-authenticated = 请先登录
213
+ branding-empty-value = 请输入一个数值
214
+ branding-update-success = { $key } 更新成功
215
+ branding-upload-success = { $key } 上传成功
216
+ branding-delete-success = { $key } 删除成功
217
+ branding-upload-failed = 上传失败
218
+ branding-delete-failed = 删除失败
219
+ branding-not-available = 文件上传仅在网页版上可用
220
+
221
+ ## Navigation Categories (About Page)
222
+ node-legal-documents = 主播专属文档
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamplace/components",
3
- "version": "0.9.7",
3
+ "version": "0.9.10",
4
4
  "description": "Streamplace React (Native) Components",
5
5
  "main": "dist/index.js",
6
6
  "types": "src/index.tsx",
@@ -81,5 +81,5 @@
81
81
  "i18n:watch": "nodemon --watch 'locales/**/*.ftl' --exec 'node scripts/compile-translations.js'",
82
82
  "i18n:extract": "i18next-cli extract && node scripts/migrate-i18n.js"
83
83
  },
84
- "gitHead": "46b5c8833f5c53934374899c417e6c83a9b0c1f2"
84
+ "gitHead": "7425b89eb9dd8fa0be23a19861508714b1d233cd"
85
85
  }
@@ -0,0 +1,45 @@
1
+ import { Image } from "react-native";
2
+ import { ChatMessageViewHydrated } from "streamplace";
3
+
4
+ export const BADGE_IMAGES: Record<string, ReturnType<typeof require>> = {
5
+ "place.stream.badge.defs#mod": require("../../../assets/badges/mod_2x.png"),
6
+ "place.stream.badge.defs#streamer": require("../../../assets/badges/live_2x.png"),
7
+ "place.stream.badge.defs#vip": require("../../../assets/badges/vip_2x.png"),
8
+ };
9
+
10
+ export const Badge = ({
11
+ badgeType,
12
+ size = 18,
13
+ }: {
14
+ badgeType: string;
15
+ size?: number;
16
+ }) => {
17
+ const source = BADGE_IMAGES[badgeType];
18
+ if (!source) return null;
19
+ return (
20
+ <Image
21
+ source={source}
22
+ style={{
23
+ height: size,
24
+ width: size,
25
+ marginBottom: -size / 5,
26
+ marginRight: 2,
27
+ }}
28
+ />
29
+ );
30
+ };
31
+
32
+ export const BadgeDisplayRow = ({
33
+ badges,
34
+ }: {
35
+ badges: ChatMessageViewHydrated["badges"];
36
+ }) => {
37
+ if (!badges?.length) return null;
38
+ return (
39
+ <>
40
+ {badges.map((badge, index) => (
41
+ <Badge key={index} badgeType={badge.badgeType} />
42
+ ))}
43
+ </>
44
+ );
45
+ };
@@ -1,13 +1,15 @@
1
- import Picker from "@emoji-mart/react";
2
1
  import Graphemer from "graphemer";
3
2
  import { AtSignIcon, ExternalLink, X } from "lucide-react-native";
4
3
  import { env } from "process";
5
- import { useEffect, useMemo, useRef, useState } from "react";
4
+ import { ReactNode, useEffect, useMemo, useRef, useState } from "react";
6
5
  import { Platform, Pressable, TextInput } from "react-native";
7
6
  import { ChatMessageViewHydrated } from "streamplace";
8
7
  import { Button, Loader, Text, toast, useTheme, View } from "../../";
9
8
  import { handleSlashCommand } from "../../lib/slash-commands";
10
- import { registerTeleportCommand } from "../../lib/slash-commands/teleport";
9
+ import {
10
+ createTeleport,
11
+ registerTeleportCommand,
12
+ } from "../../lib/slash-commands/teleport";
11
13
  import { StreamNotifications } from "../../lib/stream-notifications";
12
14
  import { SystemMessages } from "../../lib/system-messages";
13
15
  import {
@@ -24,6 +26,7 @@ import {
24
26
  w,
25
27
  } from "../../lib/theme/atoms";
26
28
  import {
29
+ useAddSystemMessage,
27
30
  useChat,
28
31
  useCreateChatMessage,
29
32
  useLivestream,
@@ -34,8 +37,13 @@ import {
34
37
  import { useDID, usePDSAgent } from "../../streamplace-store";
35
38
  import { Textarea } from "../ui/textarea";
36
39
  import { RenderChatMessage } from "./chat-message";
37
- import { EmojiData, EmojiSuggestions } from "./emoji-suggestions";
40
+ import {
41
+ EmojiData,
42
+ EmojiSuggestions,
43
+ getSkinNative,
44
+ } from "./emoji-suggestions";
38
45
  import { MentionSuggestions } from "./mention-suggestions";
46
+ import { TeleportModal } from "./teleport-modal";
39
47
 
40
48
  const COOL_EMOJI_LIST = [
41
49
  // @ts-ignore we can iterate through this just fine it seems
@@ -49,11 +57,21 @@ export function ChatBox({
49
57
  chatBoxStyle,
50
58
  emojiData,
51
59
  setIsChatVisible,
60
+ onEmojiPickerToggle,
61
+ emojiPicker,
62
+ skinTone = 0,
52
63
  }: {
53
64
  isPopout?: boolean;
54
65
  chatBoxStyle?: any;
55
66
  emojiData: EmojiData | null;
56
67
  setIsChatVisible?: (visible: boolean) => void;
68
+ onEmojiPickerToggle?: () => void;
69
+ emojiPicker?: (
70
+ isOpen: boolean,
71
+ onClose: () => void,
72
+ onSelect: (emoji: any) => void,
73
+ ) => ReactNode;
74
+ skinTone?: number;
57
75
  }) {
58
76
  const [submitting, setSubmitting] = useState(false);
59
77
  const [message, setMessage] = useState("");
@@ -68,6 +86,7 @@ export function ChatBox({
68
86
  new Map(),
69
87
  );
70
88
  const [filteredEmojis, setFilteredEmojis] = useState<any[]>([]);
89
+ const [showTeleportModal, setShowTeleportModal] = useState(false);
71
90
  const isOverLimit = graphemer.countGraphemes(message) > 300;
72
91
 
73
92
  let linfo = useLivestream();
@@ -76,6 +95,7 @@ export function ChatBox({
76
95
 
77
96
  const chat = useChat();
78
97
  const createChatMessage = useCreateChatMessage();
98
+ const addSystemMessage = useAddSystemMessage();
79
99
  const replyTo = useReplyToMessage();
80
100
  const setReplyToMessage = useSetReplyToMessage();
81
101
  const textAreaRef = useRef<TextInput>(null);
@@ -88,7 +108,9 @@ export function ChatBox({
88
108
 
89
109
  useEffect(() => {
90
110
  if (pdsAgent && userDID) {
91
- registerTeleportCommand(pdsAgent, userDID, setActiveTeleportUri);
111
+ registerTeleportCommand(pdsAgent, userDID, setActiveTeleportUri, () =>
112
+ setShowTeleportModal(true),
113
+ );
92
114
  }
93
115
  }, [pdsAgent, userDID, setActiveTeleportUri]);
94
116
 
@@ -105,7 +127,12 @@ export function ChatBox({
105
127
 
106
128
  useEffect(() => {
107
129
  if (pdsAgent && linfo?.author?.did && pdsAgent.did === linfo.author.did) {
108
- registerTeleportCommand(pdsAgent, pdsAgent.did, setActiveTeleportUri);
130
+ registerTeleportCommand(
131
+ pdsAgent,
132
+ pdsAgent.did,
133
+ setActiveTeleportUri,
134
+ () => setShowTeleportModal(true),
135
+ );
109
136
  }
110
137
  }, [pdsAgent, linfo?.author?.did, setActiveTeleportUri]);
111
138
 
@@ -116,11 +143,37 @@ export function ChatBox({
116
143
  };
117
144
 
118
145
  const handleEmojiSelect = (emoji: any) => {
119
- const beforeColon = message.slice(0, message.lastIndexOf(":"));
120
- setMessage(`${beforeColon}${emoji.skins[0]?.native} `);
146
+ console.log("[ChatBox] handleEmojiSelect", emoji);
147
+ if (emoji.s) {
148
+ const beforeColon = message.slice(0, message.lastIndexOf(":"));
149
+ setMessage(`${beforeColon}${getSkinNative(emoji, skinTone)} `);
150
+ } else if (emoji.type === "standard") {
151
+ setMessage(message + emoji.native);
152
+ } else if (emoji.type === "custom") {
153
+ setMessage(message + `:${emoji.name}: `);
154
+ }
121
155
  setShowEmojiSuggestions(false);
122
156
  };
123
157
 
158
+ const handleTeleportSubmit = async (
159
+ targetHandle: string,
160
+ countdownSeconds: number,
161
+ ) => {
162
+ if (!pdsAgent || !userDID) return;
163
+
164
+ const result = await createTeleport(
165
+ pdsAgent,
166
+ userDID,
167
+ targetHandle,
168
+ countdownSeconds,
169
+ setActiveTeleportUri,
170
+ );
171
+
172
+ if (!result.success && result.error) {
173
+ SystemMessages.commandError(result.error);
174
+ }
175
+ };
176
+
124
177
  const updateSuggestions = (text: string) => {
125
178
  // Handle mentions
126
179
  const atIndex = text.lastIndexOf("@");
@@ -205,15 +258,15 @@ export function ChatBox({
205
258
  sort: [5, emoji.id.toLowerCase().indexOf(searchText), 0],
206
259
  }; // includes id
207
260
  }
208
- if (emoji.name.toLowerCase().includes(searchText)) {
261
+ if (emoji.m.toLowerCase().includes(searchText)) {
209
262
  return {
210
263
  emoji,
211
- sort: [6, emoji.name.toLowerCase().indexOf(searchText), 0],
264
+ sort: [6, emoji.m.toLowerCase().indexOf(searchText), 0],
212
265
  };
213
266
  }
214
267
  if (
215
- emoji.keywords &&
216
- emoji.keywords.some((keyword: string) =>
268
+ emoji.k &&
269
+ emoji.k.some((keyword: string) =>
217
270
  keyword.toLowerCase().includes(searchText),
218
271
  )
219
272
  ) {
@@ -280,7 +333,7 @@ export function ChatBox({
280
333
  if (result.handled) {
281
334
  if (result.error) {
282
335
  console.error("Slash command error:", result.error);
283
- SystemMessages.commandError(result.error);
336
+ addSystemMessage(SystemMessages.commandError(result.error));
284
337
  }
285
338
  return;
286
339
  }
@@ -321,6 +374,11 @@ export function ChatBox({
321
374
 
322
375
  return (
323
376
  <View style={[layout.flex.column, flex.shrink[1], gap.all[2]]}>
377
+ <TeleportModal
378
+ open={showTeleportModal}
379
+ onOpenChange={setShowTeleportModal}
380
+ onSubmit={handleTeleportSubmit}
381
+ />
324
382
  {replyTo && (
325
383
  <View
326
384
  style={[
@@ -360,45 +418,6 @@ export function ChatBox({
360
418
  </Pressable>
361
419
  </View>
362
420
  )}
363
- {showEmojiSelector && (
364
- <View
365
- style={{
366
- position: "absolute",
367
- top: 0,
368
- left: 0,
369
- right: 0,
370
- bottom: 0,
371
- zIndex: 200,
372
- }}
373
- pointerEvents="box-none"
374
- >
375
- {/* Overlay to catch outside clicks */}
376
- <Pressable
377
- style={{
378
- position: "absolute",
379
- top: 0,
380
- left: 0,
381
- right: 0,
382
- bottom: 0,
383
- }}
384
- onPress={() => setShowEmojiSelector(false)}
385
- />
386
- <View
387
- style={{
388
- position: "absolute",
389
- bottom: "100%",
390
- left: 0,
391
- zIndex: 2001,
392
- }}
393
- pointerEvents="auto"
394
- >
395
- <Picker
396
- data={emojiData}
397
- onEmojiSelect={(e) => setMessage(message + e.native)}
398
- />
399
- </View>
400
- </View>
401
- )}
402
421
  <View style={[layout.flex.row, layout.flex.alignCenter, gap.all[2]]}>
403
422
  <Textarea
404
423
  ref={textAreaRef}
@@ -508,6 +527,7 @@ export function ChatBox({
508
527
  emojis={filteredEmojis}
509
528
  highlightedIndex={highlightedIndex}
510
529
  onSelect={handleEmojiSelect}
530
+ skinTone={skinTone}
511
531
  />
512
532
  )}
513
533
  {Platform.OS === "web" && (
@@ -516,9 +536,14 @@ export function ChatBox({
516
536
  layout.flex.row,
517
537
  mb[2],
518
538
  gap.all[2],
519
- { justifyContent: "flex-end" },
539
+ { justifyContent: "flex-end", position: "relative" },
520
540
  ]}
521
541
  >
542
+ {emojiPicker?.(
543
+ showEmojiSelector,
544
+ () => setShowEmojiSelector(false),
545
+ handleEmojiSelect,
546
+ )}
522
547
  {env.NODE_ENV === "development" && (
523
548
  <Button
524
549
  variant="secondary"
@@ -562,9 +587,14 @@ export function ChatBox({
562
587
  >
563
588
  <Button
564
589
  variant="secondary"
590
+ id="web-emoji-picker-btn"
565
591
  aria-label="Insert Emoji"
566
592
  style={{ borderRadius: 16, maxWidth: 44, aspectRatio: 1 }}
567
- onPress={() => setShowEmojiSelector(!showEmojiSelector)}
593
+ onPress={() => {
594
+ onEmojiPickerToggle
595
+ ? onEmojiPickerToggle()
596
+ : setShowEmojiSelector(!showEmojiSelector);
597
+ }}
568
598
  >
569
599
  <Text>{COOL_EMOJI_LIST[emojiIconIndex]}</Text>
570
600
  </Button>
@@ -25,6 +25,8 @@ interface Facet {
25
25
 
26
26
  import { useLivestreamStore } from "../../livestream-store";
27
27
  import { Text } from "../ui/text";
28
+ import { BadgeDisplayRow } from "./badge";
29
+ import { UserProfileCard } from "./user-profile-card";
28
30
 
29
31
  const getRgbColor = (color?: { red: number; green: number; blue: number }) =>
30
32
  color ? `rgb(${color.red}, ${color.green}, ${color.blue})` : colors.gray[500];
@@ -152,39 +154,41 @@ export const RenderChatMessage = memo(
152
154
  </Text>
153
155
  </View>
154
156
  )}
155
- <View
156
- style={[
157
- gap.all[2],
158
- layout.flex.row,
159
- { minWidth: 0, maxWidth: "100%" },
160
- ]}
161
- >
157
+ <View style={[layout.flex.row, { minWidth: 0, maxWidth: "100%" }]}>
162
158
  {showTime && (
163
159
  <Text
164
160
  style={{
165
161
  fontVariant: ["tabular-nums"],
166
162
  color: colors.gray[400],
163
+ width: 44,
164
+ marginRight: 8,
167
165
  }}
168
166
  >
169
167
  {formatTime(item.record.createdAt)}
170
168
  </Text>
171
169
  )}
172
- <Text
173
- weight="bold"
174
- color="default"
175
- style={[flex.shrink[1], { minWidth: 0, overflow: "hidden" }]}
176
- >
177
- <Text
178
- style={[
179
- {
180
- cursor: "pointer",
181
- color: getRgbColor(item.chatProfile?.color),
182
- },
183
- ]}
170
+ <Text style={[flex.shrink[1], { minWidth: 0 }]}>
171
+ <UserProfileCard
172
+ uri={item.uri}
173
+ author={item.author}
174
+ badges={item.badges}
184
175
  >
185
- {formatHandleWithAt(item.author)}
176
+ <Text>
177
+ <BadgeDisplayRow badges={item.badges} />
178
+ <Text
179
+ weight="bold"
180
+ style={{
181
+ cursor: "pointer",
182
+ color: getRgbColor(item.chatProfile?.color),
183
+ }}
184
+ >
185
+ {formatHandleWithAt(item.author)}
186
+ </Text>
187
+ </Text>
188
+ </UserProfileCard>
189
+ <Text weight="bold" color="default">
190
+ {": "}
186
191
  </Text>
187
- :{" "}
188
192
  <RichTextMessage
189
193
  text={item.record.text}
190
194
  facets={item.record.facets || []}