rendering asset carousel

This commit is contained in:
Roland Osborne 2022-04-12 12:51:44 -07:00
parent 6d60525774
commit fc5de3ee08
9 changed files with 372 additions and 1 deletions

View File

@ -11,6 +11,7 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-easy-crop": "^4.1.4",
"react-resize-detector": "^7.0.0",
"react-router-dom": "^6.2.2",
"react-scripts": "5.0.0",
"react-virtualized": "^9.22.3",

View File

@ -0,0 +1,103 @@
import React, { useState, useEffect, useRef } from 'react';
import { AddCarouselWrapper } from './AddCarousel.styled';
import { RightOutlined, LeftOutlined } from '@ant-design/icons';
import ReactResizeDetector from 'react-resize-detector';
import login from '../../../../login.png';
import test from '../../../../test.png';
export function AddCarousel({ state, actions }) {
const [items, setItems] = useState([]);
let carousel = useRef();
let itemWidth = useRef(new Map());
let itemIndex = useRef(0);
let itemCount = useRef(0);
const [scrollLeft, setScrollLeft] = useState('hidden');
const [scrollRight, setScrollRight] = useState('hidden');
const onLeft = () => {
console.log(itemIndex.current);
if (itemIndex.current > 0) {
itemIndex.current -= 1;
setScroll();
}
}
const onRight = () => {
console.log(itemIndex.current);
if(itemIndex.current + 1 < itemCount.current) {
itemIndex.current += 1;
setScroll();
}
}
const setScroll = () => {
console.log(">>", itemIndex.current);
let pos = 0;
for (let i = 0; i < itemIndex.current; i++) {
pos += itemWidth.current.get(i) + 32;
}
carousel.current.scrollTo({ top: 0, left: pos, behavior: 'smooth' });
setArrows();
}
const setArrows = () => {
if (itemIndex.current == 0) {
setScrollLeft('hidden');
}
else {
setScrollLeft('unset');
}
if (itemIndex.current + 1 >= itemCount.current) {
setScrollRight('hidden');
}
else {
setScrollRight('unset');
}
}
useEffect(() => {
if (state.assets == null || state.assets.length == 0) {
setItems([]);
return;
}
let assets = [];
for (let i = 0; i < 10; i++) {
assets.push((
<ReactResizeDetector handleWidth={true} handleHeight={false}>
{({ width, height }) => {
itemWidth.current.set(i, width);
if (i % 2 == 0) {
return <div class="item"><img class="object" src={login} alt="" /></div>
}
return <div class="item"><img class="object" src={test} alt="" /></div>
}}
</ReactResizeDetector>
));
}
itemCount.current = assets.length;
if (itemIndex.current >= itemCount.current) {
itemIndex.current = itemCount.current - 1;
}
setItems(assets);
setArrows();
}, [state]);
if (items.length != 0) {
return (
<AddCarouselWrapper>
<div class="carousel" ref={carousel}>
{items}
</div>
<div class="arrows">
<div class="arrow" style={{ visibility: scrollLeft }} onClick={onLeft}><LeftOutlined /></div>
<div class="arrow" style={{ visibility: scrollRight }} onClick={onRight}><RightOutlined /></div>
</div>
</AddCarouselWrapper>
);
}
return <></>
}

View File

@ -0,0 +1,70 @@
import styled from 'styled-components';
export const AddCarouselWrapper = styled.div`
position: relative;
display: grid;
width: 100%;
height: 128px;
margin-top: 16px;
.carousel {
display: flex;
flex-direction: row;
width: 100%;
padding-left: 16px;
overflow: hidden;
padding-right: 100%;
/* hide scrollbar for IE, Edge and Firefox */
-ms-overflow-style: none;
scrollbar-width: none;
}
.carousel::-webkit-scrollbar {
display: none;
}
.arrows {
width: 128px;
display: flex;
flex-direction: row;
position: absolute;
left: calc(50% - 64px);
justify-content: center;
bottom: 8px;
}
.arrow {
background-color: #888888;
color: white;
opacity: 0.8;
padding-left: 4px;
padding-right: 4px;
margin-left: 8px;
margin-right: 8px;
font-size: 20px;
border-radius: 8px;
cursor: pointer;
border: 1px solid white;
}
.arrow:hover {
opacity: 1;
}
.item {
height: 128px;
margin-right: 32px;
}
.space {
width: 100%;
background-color: red;
}
.object {
height: 100%;
object-fit: contain;
}
`;

View File

@ -0,0 +1,21 @@
import { useContext, useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
export function useAddCarousel() {
const [state, setState] = useState({
});
const updateState = (value) => {
setState((s) => ({ ...s, ...value }));
}
const navigate = useNavigate();
const actions = {
};
return { state, actions };
}

View File

@ -0,0 +1,66 @@
import React from 'react';
import { Button, Dropdown, Input, Tooltip, Menu } from 'antd';
import { AddTopicWrapper } from './AddTopic.styled';
import { AddCarousel } from './AddCarousel/AddCarousel';
import { useAddTopic } from './useAddTopic.hook';
import { BgColorsOutlined, FontColorsOutlined, FontSizeOutlined, PaperClipOutlined, SendOutlined } from '@ant-design/icons';
export function AddTopic() {
const { state, actions } = useAddTopic();
const onAttach = () => {
console.log("ADD IMAGE");
actions.addImage(null);
}
const menu = (
<Menu>
<Menu.Item key="0">
<div onClick={() => actions.addImage()}>Attach Image</div>
</Menu.Item>
<Menu.Item key="1">
<div onClick={() => actions.addVideo()}>Attach Video</div>
</Menu.Item>
<Menu.Item key="2">
<div onClick={() => actions.addAudio()}>Attach Audio</div>
</Menu.Item>
<Menu.Item key="3">
<div onClick={() => actions.addIframe()}>Embed Link</div>
</Menu.Item>
</Menu>
);
return (
<AddTopicWrapper>
<div class="container">
<AddCarousel state={state} actions={actions} />
<div class="input">
<Input.TextArea placeholder="Message" autoSize={{ minRows: 2, maxRows: 6 }}
onChange={(e) => actions.setMessageText(e.target.value)} value={state.messageText} />
</div>
<div class="buttons">
<div class="option">
<Dropdown overlay={menu} overlayStyle={{ minWidth: 0 }} trigger={['click']} placement="topRight">
<Button icon={<PaperClipOutlined />} size="medium" />
</Dropdown>
</div>
<div class="option">
<Button icon={<FontSizeOutlined />} size="medium" />
</div>
<div class="option">
<Button icon={<FontColorsOutlined />} size="medium" />
</div>
<div class="option">
<Button icon={<BgColorsOutlined />} size="medium" />
</div>
<div class="send">
<Button icon={<SendOutlined />} size="medium" />
</div>
</div>
</div>
</AddTopicWrapper>
);
}

View File

@ -0,0 +1,41 @@
import styled from 'styled-components';
export const AddTopicWrapper = styled.div`
width: 100%;
.container {
overflow: hidden;
display: flex;
flex-direction: column;
padding-bottom: 24px;
border-top: 1px solid #dddddd;
}
.input {
margin-top: 16px;
padding-left: 16px;
padding-right: 16px;
width: 100%;
}
.buttons {
padding-left: 16px;
padding-right: 16px;
width: 100%;
display: flex;
flex-direction: row;
}
.option {
padding-right: 4px;
padding-top: 4px;
}
.send {
display: flex;
flex-grow: 1;
justify-content: flex-end;
padding-top: 4px;
}
`;

View File

@ -0,0 +1,55 @@
import { useContext, useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
export function useAddTopic() {
const [state, setState] = useState({
assets: [],
messageText: null,
messageColor: null,
messageWeight: null,
messageSize: null,
backgroundColor: null,
});
const updateState = (value) => {
setState((s) => ({ ...s, ...value }));
}
const addAsset = (value) => {
setState((s) => {
s.assets.push(value);
return { ...s };
});
}
const navigate = useNavigate();
const actions = {
addImage: (image) => { addAsset(image) },
addVideo: (video) => { addAsset(video) },
addAudio: (audio) => { addAsset(audio) },
addIframe: (iframe) => { addAsset(iframe) },
removeAsset: (idx) => {},
setMessageText: (value) => {
updateState({ messageText: value });
},
setMessageColor: (value) => {
updateState({ messageColor: value });
},
setMessageWeight: (value) => {
updateState({ messageWeight: value });
},
setMessageSize: (value) => {
updateState({ messageSize: value });
},
setBackgroundColor: (value) => {
updateState({ backgroundColor: value });
},
addTopic: () => {},
};
return { state, actions };
}

View File

@ -3,8 +3,9 @@ import styled from 'styled-components';
export const SideBarWrapper = styled.div`
width: 20%;
height: 100%;
max-width: 300px;
min-width: 260px;
max-width: 300px;
flex-shrink 0;
border-right: 1px solid #8fbea7;
background-color: #8fbea7;
`;

View File

@ -1933,6 +1933,11 @@
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/resize-observer-browser@^0.1.6":
version "0.1.7"
resolved "https://registry.yarnpkg.com/@types/resize-observer-browser/-/resize-observer-browser-0.1.7.tgz#294aaadf24ac6580b8fbd1fe3ab7b59fe85f9ef3"
integrity sha512-G9eN0Sn0ii9PWQ3Vl72jDPgeJwRWhv2Qk/nQkJuWmRmOB4HX3/BhD5SE1dZs/hzPZL/WKnvF0RHdTSG54QJFyg==
"@types/resolve@1.17.1":
version "1.17.1"
resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz"
@ -7688,6 +7693,14 @@ react-refresh@^0.11.0:
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz"
integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==
react-resize-detector@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/react-resize-detector/-/react-resize-detector-7.0.0.tgz#fbd46917ee905b7796c797aa6b301b454a6b9229"
integrity sha512-Xd1POfpVzH9O3F/xB/0xYy2ijtKjE/z7y4c/aJP593YSzhPy2vDhsNPjes+uQbgL1RezxJajQ679qPs8K5LAFw==
dependencies:
"@types/resize-observer-browser" "^0.1.6"
lodash "^4.17.21"
react-router-dom@^6.2.2:
version "6.2.2"
resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.2.tgz"