import React from 'react'; import Navigation from '../lib/navigation.js'; const navigate = view => Navigation.navigateTo(view); export const MESSAGE_COMPOSER_VIEWS = [ 'compose-keyboard', 'mentions-select', 'mentions-complete', 'mentions-message', 'emoji-panel', 'emoji-message', 'voice-ready', 'voice-hold', 'voice-recording', 'media-uploading', 'media-gallery', 'media-retry', 'upload-file', 'file-message', 'message-multiselect', 'favorite-success', 'forward-select', 'forward-multiple', 'forward-individual', 'forward-bundle' ]; const MEMBERS = [ {id: 'all', name: '所有人', note: '提醒群内所有成员', avatar: 'campaign'}, {id: 'annie', name: '安妮', note: '产品设计组', image: 'img/bkg/p09.jpg'}, {id: 'lizi', name: '栗子来了', note: '前端开发组', image: 'img/bkg/p15.jpg'}, {id: 'wang', name: '王珊珊', note: '市场运营组', image: 'img/bkg/p14.jpg'}, {id: 'chen', name: '陈晨', note: '项目管理组', image: 'img/bkg/p05.jpg'} ]; const TARGETS = [ {id: 'file', name: '文件助手', note: '仅自己可见', icon: 'folder_special'}, {id: 'team', name: '产品研发群', note: '18人', image: 'img/bkg/p22.jpg'}, {id: 'annie', name: '安妮', note: '在线', image: 'img/bkg/p09.jpg'}, {id: 'lizi', name: '栗子来了', note: '刚刚活跃', image: 'img/bkg/p15.jpg'}, {id: 'wang', name: '王珊珊', note: '市场运营组', image: 'img/bkg/p14.jpg'} ]; const EMOJIS = ['😀', '😄', '😂', '🥰', '😎', '🤔', '👍', '👏', '🎉', '❤️', '🔥', '💡', '✅', '🙏', '💪', '🌟', '📌', '🚀']; function Icon({children}) { return ; } function Avatar({item}) { return {item.image ? : {item.icon || item.avatar || 'person'}} ; } function Header({title = '产品研发群', subtitle = '18人', onMore}) { return

{title}

{subtitle ? {subtitle} : null}
; } function Toast({message, onDone}) { React.useEffect(() => { if (!message) return undefined; const timer = window.setTimeout(onDone, 2000); return () => window.clearTimeout(timer); }, [message, onDone]); return message ?
{message}
: null; } function VoiceBubble({mine = false, duration = 8, unread = false}) { return
{!mine ? : null} {mine ? : null}
; } function TextBubble({mine = false, children, selected, onSelect}) { return
{selected !== undefined ? : null}
{!mine ? : null}
{children}
{mine ? : null}
; } function ImageBubble({progress, failed = false, selected, onSelect}) { return
{selected !== undefined ? : null}
会议白板照片 {progress < 100 || failed ?
{failed ? 'refresh' : 'cloud_upload'}{failed ? '上传失败,点击重试' : `${progress}%`}{!failed ? : null}
: null}
; } function VideoBubble() { return
; } function FileBubble({progress = 100, name = '产品需求说明书.pdf', selected, onSelect}) { return
{selected !== undefined ? : null}
PDF
{name}2.4 MB · {progress < 100 ? `上传中 ${progress}%` : '已发送'}{progress < 100 ? : null}
{progress < 100 ? 'close' : 'download'}
; } function BaseTimeline({mode, uploadProgress, selected, toggleSelected}) { const selectable = mode === 'message-multiselect' || mode === 'favorite-success'; return

今天 10:24

上午的评审结论已经整理好了,大家有空看一下。 toggleSelected('text')}>好的,我补充一下交互细节。 {mode === 'mentions-message' ? @安妮 @栗子来了 下午三点一起确认新版流程。 : null} {['media-uploading', 'media-gallery', 'media-retry'].includes(mode) ? <> {mode === 'media-gallery' ? <> : null} : null} {['file-message', 'message-multiselect', 'favorite-success'].includes(mode) ? toggleSelected('file')} /> : null} {selectable ? toggleSelected('image')} /> : null}
; } function EmojiPanel({onEmoji, onDelete}) { return
{EMOJIS.map(emoji => )}
; } function Composer({mode, draft, setDraft, onSend, setMode}) { const voice = ['voice-ready', 'voice-hold', 'voice-recording'].includes(mode); const emoji = ['emoji-panel', 'emoji-message'].includes(mode); const keyDown = event => { if (event.key === '@' && mode !== 'mentions-message') window.setTimeout(() => navigate('mentions-select'), 0); }; return <>
{event.preventDefault(); onSend();}}> {voice ? : setDraft(event.target.value)} onKeyDown={keyDown} placeholder="输入消息" />} {draft.trim() && !voice ? : }
{emoji ? setDraft(draft + value)} onDelete={() => setDraft(draft.slice(0, -1))} /> : null} ; } function VoiceOverlay({cancel = false}) { return
{cancel ? 'delete_outline' : 'mic'}
{[2, 5, 8, 12, 9, 6, 11, 4].map((height, index) => )}
{cancel ? '松开手指,取消发送' : '手指上滑,取消发送'}00:08
; } function MemberPicker({complete}) { const [query, setQuery] = React.useState(''); const [selected, setSelected] = React.useState(complete ? ['annie', 'lizi'] : []); const visible = MEMBERS.filter(item => item.name.includes(query) || item.note.includes(query)); const toggle = id => setSelected(values => values.includes(id) ? values.filter(value => value !== id) : values.concat(id)); return

选择提醒人

群成员

{visible.map(item => )}
; } function UploadFilePage({onToast}) { const [files, setFiles] = React.useState([{name: '产品需求说明书.pdf', size: '2.4 MB', progress: 64}]); React.useEffect(() => { if (files.every(file => file.progress >= 100)) return undefined; const timer = window.setTimeout(() => setFiles(items => items.map(file => ({...file, progress: Math.min(100, file.progress + 6)}))), 300); return () => window.clearTimeout(timer); }, [files]); return
onToast('单个文件最大 100 MB')} />

待发送文件

{files.map(file =>
{file.name.split('.').pop().slice(0, 4).toUpperCase()}
{file.name}{file.size} · {file.progress < 100 ? `上传中 ${file.progress}%` : '上传完成'}
)}
; } function ForwardPage({mode, onToast}) { const multi = mode !== 'forward-select'; const confirm = mode === 'forward-individual' || mode === 'forward-bundle'; const [selected, setSelected] = React.useState(() => { if (!confirm) return []; try { return JSON.parse(sessionStorage.getItem('im-forward-targets')) || ['team', 'annie']; } catch (_) { return ['team', 'annie']; } }); const [query, setQuery] = React.useState(''); const [comment, setComment] = React.useState(''); const toggle = id => setSelected(values => values.includes(id) ? values.filter(value => value !== id) : multi ? values.concat(id).slice(0, 9) : [id]); const visible = TARGETS.filter(item => item.name.includes(query) || item.note.includes(query)); return

{confirm ? (mode === 'forward-bundle' ? '合并转发' : '逐条转发') : '选择转发对象'}

{!confirm ? : }
{!confirm ? <>

最近会话

{visible.map(item => )}
{multi ?
已选择 {selected.length}/9 个会话
: null} :

发送给

{TARGETS.filter(item => selected.includes(item.id)).map(item => {item.name})}

{mode === 'forward-bundle' ? '产品研发群的聊天记录' : '将逐条发送 3 条消息'}

栗子来了:上午的评审结论已经整理好了

我:好的,我补充一下交互细节。

我:[图片]