@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.
- package/assets/badges/live.png +0 -0
- package/assets/badges/live_2x.png +0 -0
- package/assets/badges/mod.png +0 -0
- package/assets/badges/mod_2x.png +0 -0
- package/assets/badges/vip.png +0 -0
- package/assets/badges/vip_2x.png +0 -0
- package/dist/components/chat/badge.d.ts +10 -0
- package/dist/components/chat/badge.d.ts.map +1 -0
- package/dist/components/chat/badge.js +29 -0
- package/dist/components/chat/badge.js.map +1 -0
- package/dist/components/chat/chat-box.d.ts +5 -1
- package/dist/components/chat/chat-box.d.ts.map +1 -1
- package/dist/components/chat/chat-box.js +55 -50
- package/dist/components/chat/chat-box.js.map +1 -1
- package/dist/components/chat/chat-message.d.ts.map +1 -1
- package/dist/components/chat/chat-message.js +9 -11
- package/dist/components/chat/chat-message.js.map +1 -1
- package/dist/components/chat/chat.d.ts.map +1 -1
- package/dist/components/chat/chat.js +37 -43
- package/dist/components/chat/chat.js.map +1 -1
- package/dist/components/chat/emoji-suggestions.d.ts +7 -18
- package/dist/components/chat/emoji-suggestions.d.ts.map +1 -1
- package/dist/components/chat/emoji-suggestions.js +6 -2
- package/dist/components/chat/emoji-suggestions.js.map +1 -1
- package/dist/components/chat/system-message.d.ts.map +1 -1
- package/dist/components/chat/system-message.js +9 -1
- package/dist/components/chat/system-message.js.map +1 -1
- package/dist/components/chat/teleport-modal.d.ts +9 -0
- package/dist/components/chat/teleport-modal.d.ts.map +1 -0
- package/dist/components/chat/teleport-modal.js +148 -0
- package/dist/components/chat/teleport-modal.js.map +1 -0
- package/dist/components/chat/user-profile-card.d.ts +12 -0
- package/dist/components/chat/user-profile-card.d.ts.map +1 -0
- package/dist/components/chat/user-profile-card.js +135 -0
- package/dist/components/chat/user-profile-card.js.map +1 -0
- package/dist/components/dashboard/chat-panel.d.ts +3 -1
- package/dist/components/dashboard/chat-panel.d.ts.map +1 -1
- package/dist/components/dashboard/chat-panel.js +2 -2
- package/dist/components/dashboard/chat-panel.js.map +1 -1
- package/dist/components/dashboard/header.d.ts +2 -3
- package/dist/components/dashboard/header.d.ts.map +1 -1
- package/dist/components/dashboard/header.js +6 -2
- package/dist/components/dashboard/header.js.map +1 -1
- package/dist/components/dashboard/information-widget.d.ts.map +1 -1
- package/dist/components/dashboard/information-widget.js +15 -12
- package/dist/components/dashboard/information-widget.js.map +1 -1
- package/dist/components/mobile-player/fullscreen.d.ts.map +1 -1
- package/dist/components/mobile-player/fullscreen.js +2 -1
- package/dist/components/mobile-player/fullscreen.js.map +1 -1
- package/dist/components/mobile-player/fullscreen.native.d.ts.map +1 -1
- package/dist/components/mobile-player/fullscreen.native.js +3 -2
- package/dist/components/mobile-player/fullscreen.native.js.map +1 -1
- package/dist/components/mobile-player/player.d.ts.map +1 -1
- package/dist/components/mobile-player/player.js +15 -0
- package/dist/components/mobile-player/player.js.map +1 -1
- package/dist/components/mobile-player/ui/audio-only-overlay.d.ts +2 -0
- package/dist/components/mobile-player/ui/audio-only-overlay.d.ts.map +1 -0
- package/dist/components/mobile-player/ui/audio-only-overlay.js +29 -0
- package/dist/components/mobile-player/ui/audio-only-overlay.js.map +1 -0
- package/dist/components/mobile-player/ui/index.d.ts +1 -0
- package/dist/components/mobile-player/ui/index.d.ts.map +1 -1
- package/dist/components/mobile-player/ui/index.js +1 -0
- package/dist/components/mobile-player/ui/index.js.map +1 -1
- package/dist/components/mobile-player/ui/input.d.ts +3 -2
- package/dist/components/mobile-player/ui/input.d.ts.map +1 -1
- package/dist/components/mobile-player/ui/input.js +18 -2
- package/dist/components/mobile-player/ui/input.js.map +1 -1
- package/dist/components/mobile-player/ui/metrics.d.ts.map +1 -1
- package/dist/components/mobile-player/ui/metrics.js +20 -2
- package/dist/components/mobile-player/ui/metrics.js.map +1 -1
- package/dist/components/mobile-player/ui/streamer-context-menu.d.ts +3 -1
- package/dist/components/mobile-player/ui/streamer-context-menu.d.ts.map +1 -1
- package/dist/components/mobile-player/ui/streamer-context-menu.js +64 -2
- package/dist/components/mobile-player/ui/streamer-context-menu.js.map +1 -1
- package/dist/components/mobile-player/ui/viewer-context-menu.d.ts.map +1 -1
- package/dist/components/mobile-player/ui/viewer-context-menu.js +29 -1
- package/dist/components/mobile-player/ui/viewer-context-menu.js.map +1 -1
- package/dist/components/mobile-player/use-webrtc.d.ts +4 -2
- package/dist/components/mobile-player/use-webrtc.d.ts.map +1 -1
- package/dist/components/mobile-player/use-webrtc.js +89 -15
- package/dist/components/mobile-player/use-webrtc.js.map +1 -1
- package/dist/components/mobile-player/video-async.native.d.ts.map +1 -1
- package/dist/components/mobile-player/video-async.native.js +15 -5
- package/dist/components/mobile-player/video-async.native.js.map +1 -1
- package/dist/components/mobile-player/video.d.ts.map +1 -1
- package/dist/components/mobile-player/video.js +10 -7
- package/dist/components/mobile-player/video.js.map +1 -1
- package/dist/components/ui/dialog.d.ts.map +1 -1
- package/dist/components/ui/dialog.js +8 -0
- package/dist/components/ui/dialog.js.map +1 -1
- package/dist/components/ui/textarea.d.ts.map +1 -1
- package/dist/components/ui/textarea.js +1 -1
- package/dist/components/ui/textarea.js.map +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/useAQState.d.ts +2 -0
- package/dist/hooks/useAQState.d.ts.map +1 -0
- package/dist/hooks/useAQState.js +37 -0
- package/dist/hooks/useAQState.js.map +1 -0
- package/dist/hooks/useLivestreamInfo.d.ts +1 -2
- package/dist/hooks/useLivestreamInfo.d.ts.map +1 -1
- package/dist/hooks/useLivestreamInfo.js +18 -22
- package/dist/hooks/useLivestreamInfo.js.map +1 -1
- package/dist/hooks/useSegmentTiming.d.ts +1 -1
- package/dist/hooks/useSegmentTiming.d.ts.map +1 -1
- package/dist/hooks/useSegmentTiming.js +4 -0
- package/dist/hooks/useSegmentTiming.js.map +1 -1
- package/dist/i18n/i18n-loader.native.d.ts.map +1 -1
- package/dist/i18n/i18n-loader.native.js +13 -4
- package/dist/i18n/i18n-loader.native.js.map +1 -1
- package/dist/lib/slash-commands/teleport.d.ts +5 -1
- package/dist/lib/slash-commands/teleport.d.ts.map +1 -1
- package/dist/lib/slash-commands/teleport.js +57 -1
- package/dist/lib/slash-commands/teleport.js.map +1 -1
- package/dist/lib/theme/atoms.d.ts +125 -125
- package/dist/livestream-store/chat.d.ts +1 -0
- package/dist/livestream-store/chat.d.ts.map +1 -1
- package/dist/livestream-store/chat.js +10 -1
- package/dist/livestream-store/chat.js.map +1 -1
- package/dist/livestream-store/livestream-state.d.ts +2 -0
- package/dist/livestream-store/livestream-state.d.ts.map +1 -1
- package/dist/livestream-store/livestream-store.d.ts +1 -1
- package/dist/livestream-store/livestream-store.d.ts.map +1 -1
- package/dist/livestream-store/livestream-store.js +10 -1
- package/dist/livestream-store/livestream-store.js.map +1 -1
- package/dist/livestream-store/websocket-consumer.d.ts.map +1 -1
- package/dist/livestream-store/websocket-consumer.js +1 -0
- package/dist/livestream-store/websocket-consumer.js.map +1 -1
- package/dist/player-store/player-state.d.ts +3 -5
- package/dist/player-store/player-state.d.ts.map +1 -1
- package/dist/player-store/player-store.d.ts.map +1 -1
- package/dist/player-store/player-store.js +28 -5
- package/dist/player-store/player-store.js.map +1 -1
- package/dist/player-store/single-player-provider.d.ts +0 -2
- package/dist/player-store/single-player-provider.d.ts.map +1 -1
- package/dist/player-store/single-player-provider.js +0 -2
- package/dist/player-store/single-player-provider.js.map +1 -1
- package/dist/streamplace-store/branding.d.ts.map +1 -1
- package/dist/streamplace-store/branding.js +52 -1
- package/dist/streamplace-store/branding.js.map +1 -1
- package/dist/streamplace-store/stream.d.ts +4 -2
- package/dist/streamplace-store/stream.d.ts.map +1 -1
- package/dist/streamplace-store/stream.js +36 -74
- package/dist/streamplace-store/stream.js.map +1 -1
- package/locales/en-US/common.ftl +13 -1
- package/locales/manifest.json +21 -1
- package/locales/ro-RO/common.ftl +74 -0
- package/locales/ro-RO/settings.ftl +233 -0
- package/locales/zh-Hans/common.ftl +57 -0
- package/locales/zh-Hans/settings.ftl +222 -0
- package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
- package/package.json +2 -2
- package/src/components/chat/badge.tsx +45 -0
- package/src/components/chat/chat-box.tsx +84 -54
- package/src/components/chat/chat-message.tsx +25 -21
- package/src/components/chat/chat.tsx +107 -90
- package/src/components/chat/emoji-suggestions.tsx +12 -21
- package/src/components/chat/system-message.tsx +12 -2
- package/src/components/chat/teleport-modal.tsx +310 -0
- package/src/components/chat/user-profile-card.tsx +275 -0
- package/src/components/dashboard/chat-panel.tsx +8 -0
- package/src/components/dashboard/header.tsx +8 -17
- package/src/components/dashboard/information-widget.tsx +17 -10
- package/src/components/mobile-player/fullscreen.native.tsx +3 -0
- package/src/components/mobile-player/fullscreen.tsx +2 -0
- package/src/components/mobile-player/player.tsx +22 -1
- package/src/components/mobile-player/ui/audio-only-overlay.tsx +48 -0
- package/src/components/mobile-player/ui/index.ts +1 -0
- package/src/components/mobile-player/ui/input.tsx +42 -12
- package/src/components/mobile-player/ui/metrics.tsx +17 -2
- package/src/components/mobile-player/ui/streamer-context-menu.tsx +138 -2
- package/src/components/mobile-player/ui/viewer-context-menu.tsx +40 -3
- package/src/components/mobile-player/use-webrtc.tsx +118 -17
- package/src/components/mobile-player/video-async.native.tsx +18 -5
- package/src/components/mobile-player/video.tsx +10 -7
- package/src/components/ui/dialog.tsx +8 -0
- package/src/components/ui/textarea.tsx +2 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useAQState.ts +37 -0
- package/src/hooks/useLivestreamInfo.ts +21 -22
- package/src/hooks/useSegmentTiming.tsx +7 -2
- package/src/i18n/i18n-loader.native.ts +9 -0
- package/src/lib/slash-commands/teleport.ts +68 -0
- package/src/livestream-store/chat.tsx +12 -0
- package/src/livestream-store/livestream-state.tsx +2 -0
- package/src/livestream-store/livestream-store.tsx +9 -1
- package/src/livestream-store/websocket-consumer.tsx +1 -0
- package/src/player-store/player-state.tsx +4 -7
- package/src/player-store/player-store.tsx +33 -7
- package/src/player-store/single-player-provider.tsx +0 -4
- package/src/streamplace-store/branding.tsx +60 -1
- package/src/streamplace-store/stream.tsx +42 -99
- 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 = 主播专属文档
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@streamplace/components",
|
|
3
|
-
"version": "0.9.
|
|
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": "
|
|
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 {
|
|
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 {
|
|
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(
|
|
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
|
-
|
|
120
|
-
|
|
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.
|
|
261
|
+
if (emoji.m.toLowerCase().includes(searchText)) {
|
|
209
262
|
return {
|
|
210
263
|
emoji,
|
|
211
|
-
sort: [6, emoji.
|
|
264
|
+
sort: [6, emoji.m.toLowerCase().indexOf(searchText), 0],
|
|
212
265
|
};
|
|
213
266
|
}
|
|
214
267
|
if (
|
|
215
|
-
emoji.
|
|
216
|
-
emoji.
|
|
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={() =>
|
|
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
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
|
|
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 || []}
|