forked from polka_billy/porridger
Implemented UserPage
This commit is contained in:
25
front/src/components/BackHeader.tsx
Normal file
25
front/src/components/BackHeader.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Navbar } from 'react-bootstrap'
|
||||
|
||||
import BackButton from '../assets/backArrow.svg'
|
||||
|
||||
type BackHeaderProps = {
|
||||
text: string
|
||||
}
|
||||
|
||||
function BackHeader({ text }: BackHeaderProps) {
|
||||
return (
|
||||
<Navbar>
|
||||
<Navbar.Brand as={Link} to='/'>
|
||||
<img src={BackButton} alt='Go back' />
|
||||
</Navbar.Brand>
|
||||
<Navbar.Text className='me-auto'>
|
||||
<h4 className='mb-0'>
|
||||
{text}
|
||||
</h4>
|
||||
</Navbar.Text>
|
||||
</Navbar>
|
||||
)
|
||||
}
|
||||
|
||||
export default BackHeader
|
25
front/src/components/CategoryPreview.tsx
Normal file
25
front/src/components/CategoryPreview.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import { StoriesPreview } from '.'
|
||||
import { UserCategoriesNames, UserCategory, composeUserCategoriesFilters } from '../assets/userCategories'
|
||||
import { useAnnouncements } from '../hooks/api'
|
||||
import { gotError } from '../hooks/useFetch'
|
||||
|
||||
type CategoryPreviewProps = {
|
||||
category: UserCategory
|
||||
}
|
||||
|
||||
function CategoryPreview({ category }: CategoryPreviewProps) {
|
||||
const announcements = useAnnouncements(composeUserCategoriesFilters[category]())
|
||||
|
||||
return (
|
||||
<section>
|
||||
<h4 className='fw-bold'>{UserCategoriesNames[category]}</h4>
|
||||
{gotError(announcements) ? (
|
||||
<p className='text-danger'>{announcements.error}</p>
|
||||
) : (announcements.loading ? 'Загрузка...' :
|
||||
<StoriesPreview announcements={announcements.data} category={category} />
|
||||
)}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
export default CategoryPreview
|
143
front/src/components/StoriesPreview.tsx
Normal file
143
front/src/components/StoriesPreview.tsx
Normal file
@ -0,0 +1,143 @@
|
||||
import { Link } from 'react-router-dom'
|
||||
import { CSSProperties, useEffect, useMemo, useRef, useState } from 'react'
|
||||
|
||||
import { UserCategory, userCategoriesInfos } from '../assets/userCategories'
|
||||
import { Announcement } from '../api/announcement/types'
|
||||
import { categoryGraphics, categoryNames } from '../assets/category'
|
||||
|
||||
import rightAngleIcon from '../assets/rightAngle.svg'
|
||||
import { Button } from 'react-bootstrap'
|
||||
|
||||
type StoriesPreviewProps = {
|
||||
announcements: Announcement[],
|
||||
category: UserCategory,
|
||||
}
|
||||
|
||||
const styles = {
|
||||
container: {
|
||||
transform: 'translateX(0)',
|
||||
} as CSSProperties,
|
||||
ul: {
|
||||
display: 'flex',
|
||||
gap: 10,
|
||||
listStyleType: 'none',
|
||||
overflow: 'scroll',
|
||||
paddingLeft: 0,
|
||||
scrollBehavior: 'smooth',
|
||||
} as CSSProperties,
|
||||
link: {
|
||||
textDecoration: 'none',
|
||||
color: 'var(--bs-body-color)'
|
||||
} as CSSProperties,
|
||||
image: {
|
||||
height: '25vh',
|
||||
maxWidth: 'calc(25vh * 9 / 16)',
|
||||
objectFit: 'contain',
|
||||
borderRadius: 12,
|
||||
marginBottom: 5,
|
||||
} as CSSProperties,
|
||||
title: {
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
marginBottom: 5,
|
||||
} as CSSProperties,
|
||||
scrollButton: {
|
||||
position: 'fixed',
|
||||
right: 0,
|
||||
top: 0,
|
||||
zIndex: 100,
|
||||
background: 'linear-gradient(to right, rgba(17, 17, 17, 0) 0%, rgba(17, 17, 17, 255) 100%)',
|
||||
display: 'block',
|
||||
height: '100%',
|
||||
width: '10%',
|
||||
border: 'none',
|
||||
cursor: 'default',
|
||||
borderRadius: 0,
|
||||
} as CSSProperties,
|
||||
leftScrollButton: {
|
||||
left: 0,
|
||||
transform: 'scaleX(-1)'
|
||||
} as CSSProperties,
|
||||
rightScrollButton: {
|
||||
right: 0,
|
||||
} as CSSProperties,
|
||||
}
|
||||
|
||||
function StoriesPreview({ announcements, category }: StoriesPreviewProps) {
|
||||
const ulElement = useRef<HTMLUListElement | null>(null)
|
||||
const [showScrollButtons, setShowScrollButtons] = useState({ left: false, right: false })
|
||||
|
||||
const determineShowScrollButtons = (ul: HTMLUListElement) => (
|
||||
setShowScrollButtons({
|
||||
left: ul.scrollLeft > 0,
|
||||
right: ul.scrollLeft < (ul.scrollWidth - ul.clientWidth),
|
||||
})
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const ul = ulElement.current
|
||||
if (ul) {
|
||||
determineShowScrollButtons(ul)
|
||||
|
||||
const f = () => determineShowScrollButtons(ul)
|
||||
|
||||
ul.addEventListener('scroll', f)
|
||||
|
||||
return () => ul.removeEventListener('scroll', f)
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const ul = ulElement.current
|
||||
|
||||
if (ul) {
|
||||
determineShowScrollButtons(ul)
|
||||
}
|
||||
}, [announcements])
|
||||
|
||||
const doScroll = (forward: boolean) => () => {
|
||||
const ul = ulElement.current
|
||||
if (ul) {
|
||||
const storyWidth = window.innerHeight * 0.25 * 9 / 16 + 10
|
||||
ul.scrollLeft += forward ? storyWidth : -storyWidth
|
||||
}
|
||||
}
|
||||
|
||||
return <div style={styles.container}>
|
||||
{showScrollButtons.left &&
|
||||
<Button onClick={doScroll(false)} style={{ ...styles.scrollButton, ...styles.leftScrollButton }}>
|
||||
<img src={rightAngleIcon} alt='Показать ещё' />
|
||||
</Button>
|
||||
}
|
||||
<ul style={styles.ul} className='StoriesPreview_ul' ref={ulElement}>
|
||||
{useMemo(() => announcements.map((ann, i) => (
|
||||
<li key={`${category}${i}`}>
|
||||
<Link to={'/?' + new URLSearchParams({
|
||||
userId: Number(-1).toString(),
|
||||
userCat: category,
|
||||
storyIndex: i.toString()
|
||||
}).toString()} style={styles.link}>
|
||||
{ann.src?.endsWith('mp4') ? (
|
||||
<video src={ann.src} style={styles.image} />
|
||||
) : (
|
||||
<img
|
||||
src={ann.src || categoryGraphics[ann.category]}
|
||||
alt={'Изображение' + (ann.src ? 'предмета' : categoryNames[ann.category])}
|
||||
style={styles.image}
|
||||
/>
|
||||
)}
|
||||
<p style={styles.title}>{ann.name}</p>
|
||||
<p style={styles.title}>{userCategoriesInfos[category](ann)}</p>
|
||||
</Link>
|
||||
</li>
|
||||
)), [announcements, category])}
|
||||
</ul>
|
||||
{showScrollButtons.right &&
|
||||
<Button onClick={doScroll(true)} style={{ ...styles.scrollButton, ...styles.rightScrollButton }}>
|
||||
<img src={rightAngleIcon} alt='Показать ещё' />
|
||||
</Button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
export default StoriesPreview
|
@ -7,3 +7,6 @@ export { default as TrashboxMarkers } from './TrashboxMarkers'
|
||||
export { default as WithToken } from './WithToken'
|
||||
export { default as ClickHandler } from './ClickHandler'
|
||||
export { default as AuthForm } from './AuthForm'
|
||||
export { default as BackHeader } from './BackHeader'
|
||||
export { default as CategoryPreview } from './CategoryPreview'
|
||||
export { default as StoriesPreview } from './StoriesPreview'
|
||||
|
Reference in New Issue
Block a user