diff --git a/public/img/icon/FM.svg b/public/img/icon/FM.svg new file mode 100644 index 0000000..50884ea --- /dev/null +++ b/public/img/icon/FM.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/img/icon/comment.svg b/public/img/icon/comment.svg new file mode 100644 index 0000000..3548c8a --- /dev/null +++ b/public/img/icon/comment.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/img/icon/love-active.svg b/public/img/icon/love-active.svg new file mode 100644 index 0000000..e47a576 --- /dev/null +++ b/public/img/icon/love-active.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/img/icon/love.svg b/public/img/icon/love.svg new file mode 100644 index 0000000..6440348 --- /dev/null +++ b/public/img/icon/love.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/app/about/about.module.css b/src/app/about/about.module.css index 6e17828..812d35b 100644 --- a/src/app/about/about.module.css +++ b/src/app/about/about.module.css @@ -1,29 +1,29 @@ -.halo { - position: absolute; - top: 160px; - left: 240px; - width: 560px; - height: 280px; - margin-left: 30px; - background: linear-gradient(135.88deg, rgba(255, 240, 240, 0.0126) 31.88%, rgba(255, 53, 53, 0.06) 75.38%); - filter: blur(50px); - transform: matrix(1, -0.09, -0.02, 1, 0, 0); -} - -.weibo { - position: relative; - color: #000; - font-size: 20px; - line-height: 28px; -} - -.weibo::after { - content: ''; - display: block; - left: 83px; - bottom: 0; - position: absolute; - width: 24px; - height: 24px; - background: url('/img/icon/arrow-right.svg'); -} +.halo { + position: absolute; + top: 160px; + left: 240px; + width: 560px; + height: 280px; + margin-left: 30px; + background: linear-gradient(135.88deg, rgba(255, 240, 240, 0.0126) 31.88%, rgba(255, 53, 53, 0.06) 75.38%); + filter: blur(50px); + transform: matrix(1, -0.09, -0.02, 1, 0, 0); +} + +.weibo { + position: relative; + color: #000; + font-size: 20px; + line-height: 28px; +} + +.weibo::after { + content: ''; + display: block; + left: 83px; + bottom: 2px; + position: absolute; + width: 24px; + height: 24px; + background: url('/img/icon/arrow-right.svg'); +} diff --git a/src/app/about/components/contributor-card.tsx b/src/app/about/components/contributor-card.tsx deleted file mode 100644 index 33a64e6..0000000 --- a/src/app/about/components/contributor-card.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import Image from 'next/image'; - -import { ContributorCardType } from '../page'; - -export default function ContributorCard({ nickname, avatarUrl, occupation }: ContributorCardType) { - return ( -
-
- {/* {`${nickname}-avatar`} */} - wechat qrCode -
-

{nickname}

-

{occupation}

-
- ); -} diff --git a/src/app/about/page.tsx b/src/app/about/page.tsx index 43a8a55..0ab14ad 100644 --- a/src/app/about/page.tsx +++ b/src/app/about/page.tsx @@ -1,183 +1,105 @@ -import Image from 'next/image'; - -import styles from './about.module.css'; -import ContributorCard from './components/contributor-card'; - -export interface ContributorCardType { - nickname: string; - avatarUrl: string; - occupation: string; -} - -const contributorList: ContributorCardType[] = [ - { - nickname: 'Blaksder', - avatarUrl: '/img/about/avatar.png', - occupation: '前端工程师', - }, - { - nickname: 'Blaksder', - avatarUrl: '/img/about/avatar.png', - occupation: '前端工程师', - }, - { - nickname: 'Blaksder', - avatarUrl: '/img/about/avatar.png', - occupation: '前端工程师', - }, - { - nickname: 'Blaksder', - avatarUrl: '/img/about/avatar.png', - occupation: '前端工程师', - }, - { - nickname: 'Blaksder', - avatarUrl: '/img/about/avatar.png', - occupation: '前端工程师', - }, - { - nickname: 'Blaksder', - avatarUrl: '/img/about/avatar.png', - occupation: '前端工程师', - }, - { - nickname: 'Blaksder', - avatarUrl: '/img/about/avatar.png', - occupation: '前端工程师', - }, - { - nickname: 'Blaksder', - avatarUrl: '/img/about/avatar.png', - occupation: '前端工程师', - }, - { - nickname: 'Blaksder', - avatarUrl: '/img/about/avatar.png', - occupation: '前端工程师', - }, - { - nickname: 'Blaksder', - avatarUrl: '/img/about/avatar.png', - occupation: '前端工程师', - }, - { - nickname: 'Blaksder', - avatarUrl: '/img/about/avatar.png', - occupation: '前端工程师', - }, - { - nickname: 'Blaksder', - avatarUrl: '/img/about/avatar.png', - occupation: '前端工程师', - }, - { - nickname: 'Blaksder', - avatarUrl: '/img/about/avatar.png', - occupation: '前端工程师', - }, - { - nickname: 'Blaksder', - avatarUrl: '/img/about/avatar.png', - occupation: '前端工程师', - }, - { - nickname: 'Blaksder', - avatarUrl: '/img/about/avatar.png', - occupation: '前端工程师', - }, - { - nickname: 'Blaksder', - avatarUrl: '/img/about/avatar.png', - occupation: '前端工程师', - }, -]; - -export default function Download() { - return ( -
-
- {/* about */} -
-

关于雀乐

-

原「落网APP」

-
-

- 听音乐是蛮私人的事情,我们去做这些歌单同样也是,不过,一个产品影响到那么多人之后,个体表达就变成了群体表达,音乐总是能够让人超脱于此刻和当下,变成了记忆里最底层的符号。 -

-

- 我们赤裸裸的来,我们沉淀淀的去,我们之所以沉淀下来,是因为你们都在,因为你们都在,我才无所畏惧!
- Indie but not in die -

-
-
- - {/* contributor */} -
-

贡献者

- -
- - 贡献者 - -
-

- 无论是过去的“落网”还是现在的“雀乐”,到现在为止已经走过了二十多个年头。这一路走来充满着艰辛和不易,但是无论再多的苦难,我们终究还是坚持了下来。当然,止步不前的坚持是毫无意义的,我们想去创造更好的未来。我们想让更多真诚的音乐能够让更多的人接触到、想让更多的独立音乐人能够通过自己的创作获得应有的报酬和尊重、想让雀乐成为国内最好的独立音乐传播平台。 -

-
-

- 值得庆幸的是,虽然外面的世界多变且让人充满着畏惧。但是人更多的时候是充满着善意的。 -
- - 以下的这些朋友们在我们最困难的时候用自己力所能及的方式支持着我们达成一个个目标,是他们无私的奉献,才有着“雀乐”一步步拓实的脚印以面对这复杂的世界、才有着上面的想法能够逐步实现。 - -

-
-

- 如果你也想加入我们,无论是提供技术、资金或是其他任何方式的支持,都可以加 - 微信号indier - 联系到我们。
- 感谢音乐,感谢遇见,感谢所有的贡献者。还有感谢那些途中参与过,给予我们帮助的人们。所有的奉献都值得被铭记。 -

-
- -

- 雀乐团队

-
- -
- {contributorList.map((card) => ( - - ))} -
- - {/* contributor wall */} -
- - {/* 联系我们 */} -
-

联系我们

- -
-

商务合作

-

rock@indie.cn

-
- -
-

Weibo

-

官方微博

-
- -
- wechat qrCode -

雀乐公众号

-
-
-
-
- ); -} +import Image from 'next/image'; + +import styles from './about.module.css'; +import ContributorCard from '@/components'; + +import { apiThanks } from '@/services/server/about'; + +export interface ContributorCardType { + id: number; + nickName: string; + avatar: string; + contributorRole: string; +} + +export default async function Download() { + const contributorList: ContributorCardType[] = await apiThanks(); + + return ( +
+
+ {/* about */} +
+

关于雀乐

+

原「落网APP」

+
+

+ 听音乐是蛮私人的事情,我们去做这些歌单同样也是,不过,一个产品影响到那么多人之后,个体表达就变成了群体表达,音乐总是能够让人超脱于此刻和当下,变成了记忆里最底层的符号。 +

+

+ 我们赤裸裸的来,我们沉淀淀的去,我们之所以沉淀下来,是因为你们都在,因为你们都在,我才无所畏惧!
+ Indie but not in die +

+
+
+ + {/* contributor */} +
+

贡献者

+ +
+ + 贡献者 + +
+

+ 无论是过去的“落网”还是现在的“雀乐”,到现在为止已经走过了二十多个年头。这一路走来充满着艰辛和不易,但是无论再多的苦难,我们终究还是坚持了下来。当然,止步不前的坚持是毫无意义的,我们想去创造更好的未来。我们想让更多真诚的音乐能够让更多的人接触到、想让更多的独立音乐人能够通过自己的创作获得应有的报酬和尊重、想让雀乐成为国内最好的独立音乐传播平台。 +

+
+

+ 值得庆幸的是,虽然外面的世界多变且让人充满着畏惧。但是人更多的时候是充满着善意的。 +
+ + 以下的这些朋友们在我们最困难的时候用自己力所能及的方式支持着我们达成一个个目标,是他们无私的奉献,才有着“雀乐”一步步拓实的脚印以面对这复杂的世界、才有着上面的想法能够逐步实现。 + +

+
+

+ 如果你也想加入我们,无论是提供技术、资金或是其他任何方式的支持,都可以加微信号  + indier +  联系到我们。
+ 感谢音乐,感谢遇见,感谢所有的贡献者。还有感谢那些途中参与过,给予我们帮助的人们。所有的奉献都值得被铭记。 +

+
+ +

- 雀乐团队

+
+ +
+ {contributorList.map((card) => ( + + ))} +
+ + {/* contributor wall */} +
+ + {/* 联系我们 */} +
+

联系我们

+ +
+

商务合作

+

rock@indie.cn

+
+ +
+

Weibo

+

官方微博

+
+ +
+ wechat qrCode +

雀乐公众号

+
+
+
+
+ ); +} diff --git a/src/app/discover/journal/page.tsx b/src/app/discover/journal/page.tsx new file mode 100644 index 0000000..5a18c17 --- /dev/null +++ b/src/app/discover/journal/page.tsx @@ -0,0 +1,21 @@ +import { TagCategory, JournalList } from '@/components'; + +export default function Home() { + return ( +
+ {/* 左侧 */} +
+ {/* category */} + + {/* 期刊列表 */} + +
+ + {/* 右侧 */} +
+

热门推荐

+
+
+
+ ); +} diff --git a/src/app/journal/page.tsx b/src/app/journal/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/loading.tsx b/src/app/loading.tsx new file mode 100644 index 0000000..6520a78 --- /dev/null +++ b/src/app/loading.tsx @@ -0,0 +1,3 @@ +export default function Loading() { + return
Loading...
; +} diff --git a/src/app/page.tsx b/src/app/page.tsx index 0721d3a..e6c017d 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,3 +1,24 @@ -export default function Home() { - return
; -} +import { useState, useEffect } from 'react'; + +import { TagCategory } from '@/components'; + +import { getTagName } from '@/store'; + +export default function Home() { + return ( +
+ {/* 左侧 */} +
+ {/* category */} + + {/* 期刊列表 */} +
+ + {/* 右侧 */} +
+

热门推荐

+
+
+
+ ); +} diff --git a/src/app/playlist/page.tsx b/src/app/playlist/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/Avatar.tsx b/src/components/Avatar.tsx index 9d4f1af..5d0d4ea 100644 --- a/src/components/Avatar.tsx +++ b/src/components/Avatar.tsx @@ -1,8 +1,18 @@ import Image from 'next/image'; -const Avatar = ({ src, alt, size }: { src: string; alt: string; size: number }) => { +const Avatar = ({ + src, + alt = 'avatar', + size, + className = '', +}: { + src: string; + alt?: string; + size: number; + className?: string; +}) => { return ( -
+
{alt}
); diff --git a/src/components/ContributorCard.tsx b/src/components/ContributorCard.tsx new file mode 100644 index 0000000..7a22d8a --- /dev/null +++ b/src/components/ContributorCard.tsx @@ -0,0 +1,13 @@ +import Avatar from '@/components/Avatar'; + +import { ContributorCardType } from '../app/about/page'; + +export default function ContributorCard({ nickName, avatar, contributorRole }: ContributorCardType) { + return ( +
+ +

{nickName}

+

{contributorRole}

+
+ ); +} diff --git a/src/components/JournalCard.tsx b/src/components/JournalCard.tsx new file mode 100644 index 0000000..007f62d --- /dev/null +++ b/src/components/JournalCard.tsx @@ -0,0 +1,78 @@ +import Image from 'next/image'; + +import Avatar from '@/components/Avatar'; + +export default function JournalCard({ + journalNo, + title, + image, + summary, + haveCollect, + totalCommentReply, + commentList, +}: JournalInfo) { + console.log({ commentList }); + + return ( +
+ {/* banner container */} +
+ {/* 左上角标 */} +
+

{journalNo}

+
+

VOL

+
+ + {/* banner */} + {title} + + {/* 标题 */} +

{title}

+
+ {/* 摘要 */} +

+ {summary} +

+ {/* 评论 */} + {commentList.length && ( +
+
+ {commentList?.[0]?.avatar && } + {commentList?.[1]?.avatar && ( +
+ +
+ )} +
+

+ {commentList[0].content} +

+
+ )} + + {/* 评论 & 收藏 */} +
+ love +

+ {totalCommentReply} +

+ comment +

{totalCommentReply}

+
+
+ ); +} diff --git a/src/components/JournalList.tsx b/src/components/JournalList.tsx new file mode 100644 index 0000000..4c4874d --- /dev/null +++ b/src/components/JournalList.tsx @@ -0,0 +1,46 @@ +import Image from 'next/image'; + +import JournalCard from './JournalCard'; + +import { apiJournalList } from '@/services/server/journal'; + +const JournalList = async ({ + categoryId, + journalNoRange, + pageNum, + pageSize, +}: { + categoryId?: string; + journalNoRange?: string; + pageNum?: number; + pageSize?: number; +}) => { + const journalList: JournalList = await apiJournalList({ + categoryId, + journalNoRange, + pageNum, + pageSize, + }); + + return ( +
+ {/* 分类 & 电台 */} +
+
{'摇滚'}
+
+ FM +

电台

+
+
+ + {/* 期刊 list */} +
+ {journalList.rows.map((item: JournalInfo) => ( + + ))} +
+
+ ); +}; + +export default JournalList; diff --git a/src/components/Login/LoginForm.tsx b/src/components/Login/LoginForm.tsx index 9b0b8cb..d6d92d9 100644 --- a/src/components/Login/LoginForm.tsx +++ b/src/components/Login/LoginForm.tsx @@ -2,21 +2,22 @@ import React, { useState } from 'react'; -import Input from '@/components/common/Input'; +import { Input, Button } from '@/components'; +import { useDebounce } from '@/hooks'; export default function LoginForm({ onClose }: { onClose: () => void }) { - const [phone, setPhone] = useState(''); - const [authCode, seAuthCode] = useState(''); + const [phone, setPhone] = useState(''); // 手机号 + const [authCode, seAuthCode] = useState(''); // 验证码 - const handleLogin = () => { + const handleGetAuthCode = () => { + console.log('handleGetAuthCode'); event.preventDefault(); - console.log(phone, authCode); - onClose(); }; - const handleGetAuthCode = () => { + const handleLogin = (event: Event) => { + console.log('handleLogin'); event.preventDefault(); - console.log('获取验证码'); + // onClose(); }; const handleInputChange = (e: React.ChangeEvent, fn: (text: string) => void) => { @@ -29,7 +30,6 @@ export default function LoginForm({ onClose }: { onClose: () => void }) { }; return ( - //
void }) { className="w-full" type="text" value={authCode} - maxLength={4} + maxLength={6} onChange={(e: React.ChangeEvent) => handleInputChange(e, seAuthCode)} placeholder="输入验证码" /> - +
- + ); } diff --git a/src/components/RecommendCard.tsx b/src/components/RecommendCard.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/TagCategory.tsx b/src/components/TagCategory.tsx new file mode 100644 index 0000000..ec4223e --- /dev/null +++ b/src/components/TagCategory.tsx @@ -0,0 +1,21 @@ +import { apiTagName } from '@/services/server/journal'; + +const Avatar = async () => { + const tagNameList = await apiTagName({ level: 1, state: 1 }); + + return ( +
+ {tagNameList.map((item: TagName) => ( +
+ {item.nameCh} +
+ ))} +
+ ); +}; + +export default Avatar; diff --git a/src/components/common/Button.tsx b/src/components/common/Button.tsx new file mode 100644 index 0000000..2c6da66 --- /dev/null +++ b/src/components/common/Button.tsx @@ -0,0 +1,36 @@ +import React from 'react'; + +interface ButtonProps { + type?: 'default' | 'primary' | 'black'; + disabled?: boolean; + className?: string; + children: React.ReactNode; + [key: string]: any; +} + +const Button: React.FC = ({ + type = 'default', + disabled = false, + className = '', + children, + ...restPropps +}) => { + const buttonColorList = { + default: { default: 'bg-blue text-[#000]', disabled: 'opacity-50' }, + primary: { default: 'bg-[#B44343] text-[#fff]', disabled: 'opacity-50' }, + black: { default: 'bg-[#000] text-[#fff]', disabled: 'opacity-10' }, + }; + + return ( + + ); +}; + +export default Button; diff --git a/src/components/index.ts b/src/components/index.ts index 69f1ed6..e1ba5f6 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -2,8 +2,14 @@ export { default as Logo } from './Logo'; export { default as Header } from './Header'; export { default as Footer } from './Footer'; +// Home +export { default as TagCategory } from './TagCategory'; +export { default as JournalList } from './JournalList'; +export { default as ContributorCard } from './ContributorCard'; + export { default as LoginModal } from './Login/LoginModal'; export { default as LoginForm } from './Login/LoginForm'; // Common export { default as Input } from './common/Input'; +export { default as Button } from './common/Button'; diff --git a/src/services/server/journal.ts b/src/services/server/journal.ts index fb4c83e..51a702c 100644 --- a/src/services/server/journal.ts +++ b/src/services/server/journal.ts @@ -1,68 +1,30 @@ // 期刊 import { request, verifyResponse } from '@/utils'; -export interface journalList { - total: number; - row: JournalInfo[]; -} - -export interface Comment { - _id: string; - avatar: string; - commentCount: number; - content: string; - journalId: string; - location: string; - nickName: string; - parentId: string; - publishTime: string; - state: number; - thumbupCount: number; - userId: string; -} - -export interface JournalInfo { - /** 期刊评论top5 */ - commentList: Comment[]; - /** 文案 */ - content: string; - /** 编辑日期 */ - date: string; - /** 编辑人 */ - editor: string; - /** 已收藏 */ - haveCollect: boolean; - id: string; - /** 期刊封面 */ - image: string; - /** 期刊发布于 */ - ipLocation: string; - /** 剘刊号 */ - journalNo: string; - /** 概要 */ - summary: string; - /** 期刊标签 */ - tags: string[]; - /** 期刊名 */ - title: string; - /** 期刊总评论数,大于99,显示99+ */ - totalCommentReply: string; - /** 期刊总评论数 int */ - totalCommentReplyInt: number; -} - /** * @description 查询期刊信息 默认10条 */ -export const getJournalList = async () => { - const result = await request('/luoo-music/journal/list'); - return result; +export const apiJournalList = async ({ + categoryId = '', + journalNoRange = '', + pageNum = 1, + pageSize = 10, +}: { + categoryId?: string; + journalNoRange?: string; + pageNum?: number; + pageSize?: number; +}) => { + const result: FetchResponse = await request( + `/luoo-music/journal/list?categoryId=${categoryId}&journalNoRange=${journalNoRange}&pageNum=${pageNum}&pageSize=${pageSize}`, + ); + return verifyResponse(result); }; /** * @description 获取期刊筛选条件 */ -export const getJournalFilter = async () => { +export const apiJournalFilter = async () => { const result = await request('/luoo-music/journal/filter'); return result; }; @@ -82,6 +44,8 @@ export const apiTagName = async ({ parentId?: string; state?: number; }) => { - const result = await request(`/luoo-tag/tag/name?level=${level}&parentId=${parentId}&state=${state}`); + const result: FetchResponse = await request( + `/luoo-tag/tag/name?level=${level}&parentId=${parentId}&state=${state}`, + ); return verifyResponse(result); }; diff --git a/src/types/reqeust.d.ts b/src/types/reqeust.d.ts index 6aea924..b13b080 100644 --- a/src/types/reqeust.d.ts +++ b/src/types/reqeust.d.ts @@ -3,3 +3,71 @@ declare interface FetchResponse { message: string; data: T; } + +declare interface TagName { + /** ID */ + id: string; + /** 是否显示 */ + isShow: number; + /** 等级 */ + level: number; + /** 中文名称 */ + nameCh: string; + /** 英文名称 */ + nameEn: string; + /** 父类别ID */ + parentId: string; + /** 状态 */ + state: number; +} + +declare interface JournalList { + total: number; + rows: JournalInfo[]; +} + +declare interface Comment { + _id: string; + avatar: string; + commentCount: number; + content: string; + journalId: string; + location: string; + nickName: string; + parentId: string; + publishTime: string; + state: number; + thumbupCount: number; + userId: string; +} + +declare interface JournalInfo { + /** 期刊评论top5 */ + commentList: Comment[]; + /** 文案 */ + content: string; + /** 编辑日期 */ + date: string; + /** 编辑人 */ + editor: string; + /** 已收藏 */ + haveCollect: boolean; + /** ID */ + id: string; + /** 期刊封面 */ + image: string; + /** 期刊发布于 */ + ipLocation: string; + /** 剘刊号 */ + journalNo: string; + /** 概要 */ + summary: string; + /** 期刊标签 */ + tags: string[]; + /** 期刊名 */ + title: string; + /** 期刊总评论数,大于99,显示99+ */ + totalCommentReply: string; + /** 期刊总评论数 int */ + totalCommentReplyInt: number; +} diff --git a/src/types/tag.d.ts b/src/types/tag.d.ts deleted file mode 100644 index 88e1621..0000000 --- a/src/types/tag.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -declare interface TagName { - /** ID */ - id: string; - /** 是否显示 */ - isShow: number; - /** 等级 */ - level: number; - /** 中文名称 */ - nameCh: string; - /** 英文名称 */ - nameEn: string; - /** 父类别ID */ - parentId: string; - /** 状态 */ - state: number; -}