animating height for attachments

This commit is contained in:
Roland Osborne 2024-12-16 10:29:15 -08:00
parent 968bf983ee
commit 9f78c7b54b
4 changed files with 80 additions and 62 deletions

View File

@ -27,6 +27,7 @@
"jest": "29.1.1",
"jsencrypt": "^3.3.2",
"react": "18.3.1",
"react-animate-height": "^3.2.3",
"react-color": "^2.19.3",
"react-dom": "18.2.0",
"react-easy-crop": "^5.0.8",

View File

@ -75,12 +75,20 @@
}
.add {
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
flex-shrink: 0;
width: 100%;
}
.staging {
position: absolute;
bottom: 0;
width: 100%;
}
.close {
cursor: pointer;
padding-top: 2px;

View File

@ -11,6 +11,8 @@ import { VideoFile } from './videoFile/VideoFile';
import { AudioFile } from './audioFile/AudioFile';
import { BinaryFile } from './binaryFile/BinaryFile';
import { SketchPicker } from "react-color";
import AnimateHeight from 'react-animate-height';
import { useResizeDetector } from 'react-resize-detector';
const PAD_HEIGHT = (1024 - 64);
const LOAD_DEBOUNCE = 1000;
@ -33,6 +35,7 @@ export function Conversation() {
const attachVideo = useRef({ click: ()=>{} } as HTMLInputElement);
const attachAudio = useRef({ click: ()=>{} } as HTMLInputElement);
const attachBinary = useRef({ click: ()=>{} } as HTMLInputElement);
const { width, height, ref } = useResizeDetector();
const addImage = (image: File | undefined) => {
if (image) {
@ -141,8 +144,7 @@ export function Conversation() {
}
});
console.log("SEND? ", sending, state.progress);
console.log("HIIGHT: ", height);
return (
<div className={classes.conversation}>
@ -207,68 +209,70 @@ console.log("SEND? ", sending, state.progress);
<div className={classes.progress} style={{ width: `${state.progress}%` }}/>
)}
</div>
<div className={classes.add}>
<input type='file' name="asset" accept="image/*" ref={attachImage} onChange={e => addImage(e.target?.files?.[0])} style={{display: 'none'}}/>
<input type='file' name="asset" accept="video/*" ref={attachVideo} onChange={e => addVideo(e.target?.files?.[0])} style={{display: 'none'}}/>
<input type='file' name="asset" accept="audio/*" ref={attachAudio} onChange={e => addAudio(e.target?.files?.[0])} style={{display: 'none'}}/>
<input type='file' name="asset" accept="*/*" ref={attachBinary} onChange={e => addBinary(e.target?.files?.[0])} style={{display: 'none'}}/>
<div className={classes.files}>
{ media }
</div>
<Textarea className={classes.message} placeholder={state.strings.newMessage} styles={{ input: {color: state.textColorSet ? state.textColor : undefined, fontSize: state.textSizeSet ? state.textSize : undefined }}} value={state.message} onChange={(event) => actions.setMessage(event.currentTarget.value)} disabled={!state.detail || state.detail.locked || sending} onKeyDown={(e) => { console.log(e); keyDown(e.key, e.shiftKey)}} />
<div className={classes.controls}>
<ActionIcon className={classes.attach} variant="light" disabled={!state.detail || state.detail.locked || sending} onClick={() => attachImage.current.click()}>
<IconCamera />
</ActionIcon>
<ActionIcon className={classes.attach} variant="light" disabled={!state.detail || state.detail.locked || sending} onClick={() => attachVideo.current.click()}>
<IconVideo />
</ActionIcon>
<ActionIcon className={classes.attach} variant="light" disabled={!state.detail || state.detail.locked || sending} onClick={() => attachAudio.current.click()}>
<IconDisc />
</ActionIcon>
<ActionIcon className={classes.attach} variant="light" disabled={!state.detail || state.detail.locked || sending} onClick={() => attachBinary.current.click()}>
<IconFile />
</ActionIcon>
<Divider size="sm" orientation="vertical" />
<Menu shadow="md" position="top">
<Menu.Target>
<ActionIcon className={classes.attach} variant="light" disabled={!state.detail || state.detail.locked || sending}>
<IconTextSize />
</ActionIcon>
</Menu.Target>
<Menu.Dropdown>
<Menu.Item onClick={() => actions.setTextSize(12)}>
{ state.strings.textSmall }
</Menu.Item>
<Menu.Item onClick={() => actions.setTextSize(16)}>
{ state.strings.textMedium }
</Menu.Item>
<Menu.Item onClick={() => actions.setTextSize(20)}>
{ state.strings.textLarge }
</Menu.Item>
</Menu.Dropdown>
</Menu>
<Menu shadow="md" position="top">
<Menu.Target>
<ActionIcon className={classes.attach} variant="light" disabled={!state.detail || state.detail.locked || sending}>
<IconTextColor />
</ActionIcon>
</Menu.Target>
<Menu.Dropdown>
<SketchPicker disableAlpha={true}
color={state.textColor}
onChange={(color) => {
actions.setTextColor(color.hex);
}} />
</Menu.Dropdown>
</Menu>
<div className={classes.send}>
<ActionIcon className={classes.attach} variant="light" disabled={(!state.message && state.assets.length === 0) || !state.detail || state.detail.locked || sending} onClick={sendMessage} loading={sending}>
<IconSend />
</ActionIcon>
<AnimateHeight className={classes.add} duration={500} height={height}>
<div ref={ref} className={classes.staging}>
<input type='file' name="asset" accept="image/*" ref={attachImage} onChange={e => addImage(e.target?.files?.[0])} style={{display: 'none'}}/>
<input type='file' name="asset" accept="video/*" ref={attachVideo} onChange={e => addVideo(e.target?.files?.[0])} style={{display: 'none'}}/>
<input type='file' name="asset" accept="audio/*" ref={attachAudio} onChange={e => addAudio(e.target?.files?.[0])} style={{display: 'none'}}/>
<input type='file' name="asset" accept="*/*" ref={attachBinary} onChange={e => addBinary(e.target?.files?.[0])} style={{display: 'none'}}/>
<div className={classes.files}>
{ media }
</div>
<Textarea className={classes.message} placeholder={state.strings.newMessage} styles={{ input: {color: state.textColorSet ? state.textColor : undefined, fontSize: state.textSizeSet ? state.textSize : undefined }}} value={state.message} onChange={(event) => actions.setMessage(event.currentTarget.value)} disabled={!state.detail || state.detail.locked || sending} onKeyDown={(e) => { console.log(e); keyDown(e.key, e.shiftKey)}} />
<div className={classes.controls}>
<ActionIcon className={classes.attach} variant="light" disabled={!state.detail || state.detail.locked || sending} onClick={() => attachImage.current.click()}>
<IconCamera />
</ActionIcon>
<ActionIcon className={classes.attach} variant="light" disabled={!state.detail || state.detail.locked || sending} onClick={() => attachVideo.current.click()}>
<IconVideo />
</ActionIcon>
<ActionIcon className={classes.attach} variant="light" disabled={!state.detail || state.detail.locked || sending} onClick={() => attachAudio.current.click()}>
<IconDisc />
</ActionIcon>
<ActionIcon className={classes.attach} variant="light" disabled={!state.detail || state.detail.locked || sending} onClick={() => attachBinary.current.click()}>
<IconFile />
</ActionIcon>
<Divider size="sm" orientation="vertical" />
<Menu shadow="md" position="top">
<Menu.Target>
<ActionIcon className={classes.attach} variant="light" disabled={!state.detail || state.detail.locked || sending}>
<IconTextSize />
</ActionIcon>
</Menu.Target>
<Menu.Dropdown>
<Menu.Item onClick={() => actions.setTextSize(12)}>
{ state.strings.textSmall }
</Menu.Item>
<Menu.Item onClick={() => actions.setTextSize(16)}>
{ state.strings.textMedium }
</Menu.Item>
<Menu.Item onClick={() => actions.setTextSize(20)}>
{ state.strings.textLarge }
</Menu.Item>
</Menu.Dropdown>
</Menu>
<Menu shadow="md" position="top">
<Menu.Target>
<ActionIcon className={classes.attach} variant="light" disabled={!state.detail || state.detail.locked || sending}>
<IconTextColor />
</ActionIcon>
</Menu.Target>
<Menu.Dropdown>
<SketchPicker disableAlpha={true}
color={state.textColor}
onChange={(color) => {
actions.setTextColor(color.hex);
}} />
</Menu.Dropdown>
</Menu>
<div className={classes.send}>
<ActionIcon className={classes.attach} variant="light" disabled={(!state.message && state.assets.length === 0) || !state.detail || state.detail.locked || sending} onClick={sendMessage} loading={sending}>
<IconSend />
</ActionIcon>
</div>
</div>
</div>
</div>
</AnimateHeight>
</div>
);
}

View File

@ -4245,6 +4245,11 @@ queue-microtask@^1.2.2:
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
react-animate-height@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/react-animate-height/-/react-animate-height-3.2.3.tgz#90929aadac1bd1851cb6a685acc105b50ccfda8c"
integrity sha512-R6DSvr7ud07oeCixScyvXWEMJY/Mt2+GyOWC1KMaRc69gOBw+SsCg4TJmrp4rKUM1hyd6p+YKw90brjPH93Y2A==
react-color@^2.19.3:
version "2.19.3"
resolved "https://registry.yarnpkg.com/react-color/-/react-color-2.19.3.tgz#ec6c6b4568312a3c6a18420ab0472e146aa5683d"