Compare commits

...

2 Commits

Author SHA1 Message Date
eaef7f304c Attachment list (Gallery) 2025-01-09 21:18:19 +08:00
94ae812822 💄 Optimize drawer 2025-01-09 20:50:42 +08:00
6 changed files with 105 additions and 47 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -13,11 +13,11 @@
"@emotion/react": "^11.14.0",
"@emotion/server": "^11.11.0",
"@emotion/styled": "^11.14.0",
"@mui/icons-material": "^6.3.0",
"@mui/material": "^6.3.0",
"@mui/icons-material": "^6.3.1",
"@mui/material": "^6.3.1",
"@mui/material-nextjs": "^6.3.1",
"@mui/x-charts": "^7.23.2",
"@tailwindcss/typography": "^0.5.15",
"@tailwindcss/typography": "^0.5.16",
"@vercel/speed-insights": "^1.1.0",
"animate.css": "^4.1.1",
"axios": "^1.7.9",
@ -37,18 +37,18 @@
"remark-rehype": "^11.1.1",
"sitemap": "^8.0.0",
"unified": "^11.0.5",
"zustand": "^5.0.2"
"zustand": "^5.0.3"
},
"devDependencies": {
"typescript": "^5",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"postcss": "^8",
"tailwindcss": "^3.4.1",
"eslint": "^9",
"typescript": "^5.7.3",
"@types/node": "^20.17.12",
"@types/react": "^19.0.4",
"@types/react-dom": "^19.0.2",
"postcss": "^8.4.49",
"tailwindcss": "^3.4.17",
"eslint": "^9.17.0",
"eslint-config-next": "15.1.3",
"@eslint/eslintrc": "^3"
"@eslint/eslintrc": "^3.2.0"
},
"trustedDependencies": [
"@vercel/speed-insights"

View File

@ -9,26 +9,29 @@ import {
Drawer,
Toolbar,
Typography,
Link,
} from '@mui/material'
import { JSX } from 'react'
import Image from 'next/image'
import FeedIcon from '@mui/icons-material/Feed'
import ExploreIcon from '@mui/icons-material/Explore'
import PhotoLibraryIcon from '@mui/icons-material/PhotoLibrary'
import PolicyIcon from '@mui/icons-material/Policy'
import Link from 'next/link'
import NextLink from 'next/link'
import { useRouter } from 'next/router'
interface NavLink {
title: string
icon: JSX.Element
icon?: JSX.Element
href: string
}
export function CapDrawer({ width, open, onClose }: { width: number; open: boolean; onClose: () => void }) {
const router = useRouter()
const functionLinks: NavLink[] = [
{
title: 'Posts',
icon: <FeedIcon />,
title: 'Explore',
icon: <ExploreIcon />,
href: '/posts',
},
{
@ -41,7 +44,6 @@ export function CapDrawer({ width, open, onClose }: { width: number; open: boole
const additionalLinks: NavLink[] = [
{
title: 'Terms & Conditions',
icon: <PolicyIcon />,
href: '/terms',
},
]
@ -74,29 +76,26 @@ export function CapDrawer({ width, open, onClose }: { width: number; open: boole
<List>
{functionLinks.map((l) => (
<Link passHref href={l.href} key={l.href}>
<NextLink passHref href={l.href} key={l.href}>
<ListItem disablePadding>
<ListItemButton>
<ListItemButton selected={router.pathname == l.href}>
<ListItemIcon>{l.icon}</ListItemIcon>
<ListItemText primary={l.title} />
</ListItemButton>
</ListItem>
</Link>
</NextLink>
))}
</List>
<Divider />
<List dense>
<Box sx={{ display: 'flex', flexWrap: 'wrap', px: 2, py: 1.5 }}>
{additionalLinks.map((l) => (
<Link passHref href={l.href} key={l.href}>
<ListItem disablePadding>
<ListItemButton>
<ListItemIcon>{l.icon}</ListItemIcon>
<ListItemText primary={l.title} />
</ListItemButton>
</ListItem>
</Link>
<NextLink passHref href={l.href} key={l.href}>
<Link variant="body2" color={'textSecondary'} fontSize={13}>
{l.title}
</Link>
</NextLink>
))}
</List>
</Box>
</Box>
</Drawer>
)

View File

@ -4,18 +4,26 @@ import { QuestionMark } from '@mui/icons-material'
import { Link, Paper, Typography } from '@mui/material'
import { ComponentProps } from 'react'
export function AttachmentItem({ item, ...rest }: { item: SnAttachment } & ComponentProps<'div'>) {
export function AttachmentItem({
item,
borderRadius,
...rest
}: { item: SnAttachment; borderRadius?: string } & ComponentProps<'div'>) {
switch (item.mimetype.split('/')[0]) {
case 'image':
return (
<Paper {...rest}>
<img src={getAttachmentUrl(item.rid)} alt={item.alt} style={{ objectFit: 'cover', borderRadius: '8px' }} />
<img
src={getAttachmentUrl(item.rid)}
alt={item.alt}
style={{ objectFit: 'cover', borderRadius: borderRadius ?? '8px' }}
/>
</Paper>
)
case 'video':
return (
<Paper {...rest}>
<video src={getAttachmentUrl(item.rid)} controls style={{ borderRadius: '8px' }} />
<video src={getAttachmentUrl(item.rid)} controls style={{ borderRadius: borderRadius ?? '8px' }} />
</Paper>
)
default:

View File

@ -0,0 +1,62 @@
import { AttachmentItem } from '@/components/attachments/AttachmentItem'
import { SnAttachment } from '@/services/attachment'
import { sni } from '@/services/network'
import { Box, ImageList, ImageListItem, Pagination, useMediaQuery, useTheme } from '@mui/material'
import { GetServerSideProps, InferGetServerSidePropsType } from 'next'
import { useRouter } from 'next/router'
export const getServerSideProps: GetServerSideProps = async (context) => {
let page: number = parseInt(context.query.page as string)
if (isNaN(page)) page = 1
const countPerPage = 20
const { data: resp } = await sni.get<{ data: SnAttachment[]; count: number }>('/cgi/uc/attachments', {
params: {
take: countPerPage,
offset: (page - 1) * countPerPage,
},
})
const attachments = resp.data
return { props: { attachments, page, pages: Math.ceil(resp.count / countPerPage) } }
}
export default function AttachmentsPage({
attachments,
page,
pages,
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
const router = useRouter()
const theme = useTheme()
const breakpoints = useMediaQuery(theme.breakpoints.up('md'))
return (
<Box>
<ImageList variant="masonry" cols={breakpoints ? 3 : 2} gap={8} sx={{ mx: 2 }}>
{attachments.map((item: SnAttachment) => (
<ImageListItem key={item.rid}>
<AttachmentItem item={item} borderRadius="0" />
</ImageListItem>
))}
</ImageList>
<Box
sx={{
mx: 'auto',
mb: 5,
mt: 3,
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
placeItems: 'center',
gap: 1.5,
textAlign: 'center',
}}
>
<Pagination count={pages} page={page} onChange={(_, page) => router.push('/attachments?page=' + page)} />
</Box>
</Box>
)
}

View File

@ -2,18 +2,7 @@ import { AttachmentItem } from '@/components/attachments/AttachmentItem'
import { SnAttachment, listAttachment } from '@/services/attachment'
import { getAttachmentUrl, sni } from '@/services/network'
import { SnPost } from '@/services/post'
import {
Avatar,
Box,
Button,
Container,
Divider,
Grid2 as Grid,
Link,
Pagination,
Paper,
Typography,
} from '@mui/material'
import { Avatar, Box, Container, Divider, Grid2 as Grid, Link, Pagination, Paper, Typography } from '@mui/material'
import { GetServerSideProps, InferGetServerSidePropsType } from 'next'
import NextLink from 'next/link'
import { useRouter } from 'next/router'