mirror of
https://github.com/LiuYuYang01/ThriveX-Blog.git
synced 2026-07-01 05:14:20 +08:00
大改动
This commit is contained in:
7
package-lock.json
generated
7
package-lock.json
generated
@@ -8,6 +8,7 @@
|
||||
"name": "thrive",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"dayjs": "^1.11.13",
|
||||
"next": "14.2.5",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
@@ -556,6 +557,12 @@
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.13",
|
||||
"resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz",
|
||||
"integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/didyoumean": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmmirror.com/didyoumean/-/didyoumean-1.2.2.tgz",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"dayjs": "^1.11.13",
|
||||
"next": "14.2.5",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import Swiper from "@/components/Swiper";
|
||||
import Typed from "@/components/Typed";
|
||||
import Starry from "@/components/Starry"
|
||||
import Container from "@/components/Container";
|
||||
import ArticleLayout from "@/components/ArticleLayout";
|
||||
import Sidebar from "@/components/Sidebar";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
@@ -11,6 +14,13 @@ export default function Home() {
|
||||
{/* 打字机组件 */}
|
||||
<Typed className="absolute top-[40%] left-[50%] transform -translate-x-1/2 w-[80%] text-center text-white text-[30px] custom_text_shadow"></Typed>
|
||||
</Swiper>
|
||||
|
||||
<Container>
|
||||
{/* 文章列表 */}
|
||||
<ArticleLayout />
|
||||
{/* 侧边栏 */}
|
||||
<Sidebar />
|
||||
</Container>
|
||||
</>
|
||||
);
|
||||
}
|
||||
145
src/components/ArticleLayout/Classics/index.scss
Normal file
145
src/components/ArticleLayout/Classics/index.scss
Normal file
@@ -0,0 +1,145 @@
|
||||
@import "@/styles/var.scss";
|
||||
|
||||
.ClassicsComponent {
|
||||
.classics {
|
||||
|
||||
// 文章列表
|
||||
.item {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
height: 230px;
|
||||
margin-bottom: 15px;
|
||||
background-color: #333;
|
||||
@include container;
|
||||
|
||||
// 文章封面
|
||||
.cover {
|
||||
position: relative;
|
||||
width: 45%;
|
||||
background: url("") no-repeat center;
|
||||
background-size: cover;
|
||||
transition: all $move;
|
||||
transform: scale(1);
|
||||
clip-path: polygon(0 0, 100% 0, 90% 100%, 0 100%);
|
||||
z-index: 1;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.2);
|
||||
transition: all $move;
|
||||
}
|
||||
}
|
||||
|
||||
// 文章信息
|
||||
.info {
|
||||
position: relative;
|
||||
width: 65%;
|
||||
padding: 20px 40px;
|
||||
z-index: 2;
|
||||
|
||||
.link {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
height: 100%;
|
||||
|
||||
// 文章标题
|
||||
h3 {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 20px;
|
||||
color: #fff;
|
||||
font-size: 25px;
|
||||
|
||||
// 防止超长文本 溢出
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
// 文章简述
|
||||
p {
|
||||
color: #dfdfdf;
|
||||
font-size: 15px;
|
||||
line-height: 30px;
|
||||
text-indent: 2em;
|
||||
|
||||
// 多行文本溢出
|
||||
display: -webkit-box !important;
|
||||
overflow: hidden;
|
||||
word-break: break-all;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
}
|
||||
|
||||
.fun {
|
||||
display: flex;
|
||||
padding-top: 20px;
|
||||
text-align: end;
|
||||
|
||||
.fun_item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 30px;
|
||||
font-size: 12px;
|
||||
color: #ffffff;
|
||||
|
||||
span:nth-of-type(1) {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
svg {
|
||||
padding: 4px;
|
||||
margin-top: -2px;
|
||||
margin-right: 3px;
|
||||
font-size: 23px;
|
||||
color: #fff;
|
||||
border-radius: 50%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&:nth-child(1) svg {
|
||||
background-color: #539dfd;
|
||||
}
|
||||
|
||||
&:nth-child(2) svg {
|
||||
margin-right: 0;
|
||||
background-color: #eb373a;
|
||||
}
|
||||
|
||||
&:nth-child(3) svg {
|
||||
background-color: #f5a630;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.start {
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
.end {
|
||||
justify-content: end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 背景虚化
|
||||
.bg {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 250px;
|
||||
background-position-x: center;
|
||||
background-position-y: center;
|
||||
background-size: cover;
|
||||
filter: blur(2.5rem) brightness(0.6);
|
||||
}
|
||||
}
|
||||
|
||||
// 最后一个文章取消下边距
|
||||
& .item:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
95
src/components/ArticleLayout/Classics/index.tsx
Normal file
95
src/components/ArticleLayout/Classics/index.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import dayjs from 'dayjs';
|
||||
import Link from 'next/link';
|
||||
import { randomImage } from '@/utils';
|
||||
// import Empty from '@/components/Empty';
|
||||
// import Pagination from '@/components/Pagination';
|
||||
import { Article } from '@/types/app/article';
|
||||
import "./index.scss"
|
||||
|
||||
import { RiFireLine } from "react-icons/ri";
|
||||
import { IoTimeOutline } from "react-icons/io5";
|
||||
import { GoTag } from "react-icons/go";
|
||||
|
||||
interface ClassicsProps {
|
||||
data: Paginate<Article[]>;
|
||||
}
|
||||
|
||||
const Classics: React.FC<ClassicsProps> = ({ data }) => {
|
||||
// const [paginate, setPaginate] = useState<Page>({ page: data.page, size: data.size });
|
||||
|
||||
// useEffect(() => {
|
||||
// if (data) onGet({ page: paginate.page, size: paginate.size });
|
||||
// }, [paginate, data, onGet]);
|
||||
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='ClassicsComponent'>
|
||||
<div className="classics">
|
||||
{data?.result.map((item, index) => (
|
||||
<div className="item" key={item.id}>
|
||||
{index % 2 === 0 && (
|
||||
<div
|
||||
className="cover"
|
||||
style={{ backgroundImage: `url(${item.cover || randomImage()})` }}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="info">
|
||||
<Link href={`/article/${item.id}`} className='link'>
|
||||
<h3>{item.title}</h3>
|
||||
<p>{item.description}</p>
|
||||
|
||||
<div className={`fun ${index % 2 === 0 ? 'end' : 'start'}`}>
|
||||
<div className='fun_item'>
|
||||
<span><IoTimeOutline /></span>
|
||||
<span>{dayjs(+item.createTime!).format('YYYY-MM-DD')}</span>
|
||||
</div>
|
||||
|
||||
<div className='fun_item'>
|
||||
<span><RiFireLine /></span>
|
||||
<span>{item.view}</span>
|
||||
</div>
|
||||
|
||||
<div className='fun_item'>
|
||||
<span><GoTag /></span>
|
||||
<span>{item.cateList[0]?.name}</span>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="bg"
|
||||
style={{ backgroundImage: `url(${item.cover || randomImage()})` }}
|
||||
/>
|
||||
|
||||
{index % 2 !== 0 && (
|
||||
<div
|
||||
className="cover"
|
||||
style={{
|
||||
clipPath: 'polygon(10% 0, 100% 0, 100% 100%, 0 100%)',
|
||||
backgroundImage: `url(${item.cover || randomImage()})`,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* {!data.total && <Empty info="暂无文章" />} */}
|
||||
|
||||
{/* {data.total >= 5 && (
|
||||
<Pagination
|
||||
paginate={paginate}
|
||||
onChange={(newPaginate) => setPaginate(newPaginate)}
|
||||
/>
|
||||
)} */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Classics;
|
||||
12
src/components/ArticleLayout/index.tsx
Normal file
12
src/components/ArticleLayout/index.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import Classics from "./Classics"
|
||||
import Request from '@/utils/request'
|
||||
|
||||
export default async () => {
|
||||
const { data } = await Request("/article")
|
||||
|
||||
return (
|
||||
<>
|
||||
<Classics data={data}></Classics>
|
||||
</>
|
||||
)
|
||||
}
|
||||
26
src/components/Container/index.scss
Normal file
26
src/components/Container/index.scss
Normal file
@@ -0,0 +1,26 @@
|
||||
.ContainerComponent {
|
||||
.main {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
padding: 20px;
|
||||
margin: 0 auto;
|
||||
|
||||
.left {
|
||||
margin: 0 auto;
|
||||
transition: width $move;
|
||||
}
|
||||
|
||||
.right {
|
||||
width: 24%;
|
||||
border-radius: $round;
|
||||
transition: width $move;
|
||||
|
||||
// 粘性定位
|
||||
.sticky {
|
||||
position: sticky;
|
||||
top: 70px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/components/Container/index.tsx
Normal file
11
src/components/Container/index.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
export default ({ children }: { children: React.ReactNode }) => {
|
||||
return (
|
||||
<>
|
||||
<div className="ContainerComponent">
|
||||
<div className="main w-[1200px]">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,24 +1,23 @@
|
||||
"use client"
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import Link from 'next/link';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import Request from '@/utils/request';
|
||||
import Show from '@/components/Show'
|
||||
|
||||
import lightLogo from '@/assets/image/light_logo.png';
|
||||
import darkLogo from '@/assets/image/dark_logo.png';
|
||||
|
||||
import "./index.scss"
|
||||
import { IoIosArrowDown } from 'react-icons/io';
|
||||
import { Cate } from '@/types/app/cate';
|
||||
|
||||
import Show from '@/components/Show'
|
||||
import "./index.scss"
|
||||
|
||||
const Header = () => {
|
||||
const [isScrolled, setIsScrolled] = useState(false);
|
||||
const [cateList, setCateList] = useState<Cate[]>([])
|
||||
|
||||
const getCateList = async () => {
|
||||
const res = await fetch("http://localhost:9999/api/cate/all")
|
||||
const { data } = await res.json()
|
||||
const { data } = await Request("/cate/all")
|
||||
console.log(data);
|
||||
setCateList(data)
|
||||
}
|
||||
|
||||
9
src/components/Sidebar/index.tsx
Normal file
9
src/components/Sidebar/index.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
export default () => {
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<h1>Hello World!</h1>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -3,6 +3,18 @@ body {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
// 滚动条轨道
|
||||
::-webkit-scrollbar-track {
|
||||
border-radius: 5px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
// 进度条颜色
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: #d4d4d4;
|
||||
}
|
||||
|
||||
// 文字阴影
|
||||
.custom_text_shadow {
|
||||
text-shadow: 0 0.1875rem 0.3125rem #1c1f21;
|
||||
}
|
||||
@@ -12,4 +12,47 @@ $move: 0.3s;
|
||||
$round: 5px;
|
||||
|
||||
// 阴影效果
|
||||
$boxShadow: 0 2px 8px rgba(186, 186, 186, 0.15);
|
||||
$boxShadow: 0 2px 8px rgba(186, 186, 186, 0.15);
|
||||
|
||||
// 文字效果
|
||||
$fontSty: PingFang SC, "Hiragino Sans GB", "Microsoft JhengHei", "Microsoft YaHei", sans-serif; //文章列表字体
|
||||
|
||||
// 文本标题
|
||||
$textColor: var(--textColor, #333);
|
||||
// 边框
|
||||
$borderColor: var(--borderColor, #eee);
|
||||
// 下边框
|
||||
$underBorderColor: var(--underBorderColor, #eee);
|
||||
// 阴影
|
||||
$shadeColor: var(--shadeColor, 0 2px 8px rgba(186, 186, 186, 0.15));
|
||||
|
||||
// 封装CSS容器样式
|
||||
@mixin container {
|
||||
border-radius: $round;
|
||||
border: 1px solid $borderColor;
|
||||
transition: all $move;
|
||||
|
||||
&:hover {
|
||||
box-shadow: $shadeColor;
|
||||
}
|
||||
}
|
||||
|
||||
// 封装右侧模块标题样式
|
||||
@mixin titleRight {
|
||||
.title {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid $underBorderColor;
|
||||
font-size: 17px;
|
||||
font-weight: 400;
|
||||
color: $textColor;
|
||||
transition: all $move;
|
||||
|
||||
img {
|
||||
width: 30px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/utils/index.ts
Normal file
27
src/utils/index.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
// 生成随机数
|
||||
export function getRandom(min: number, max: number): number {
|
||||
return Math.floor(Math.random() * (max - min + 1) + min);
|
||||
}
|
||||
|
||||
// 随机预览图
|
||||
export function randomImage() {
|
||||
const covers = [
|
||||
"https://bu.dusays.com/2023/11/10/654e2da1d80f8.jpg",
|
||||
"https://bu.dusays.com/2023/11/10/654e2d719d31c.jpg",
|
||||
"https://bu.dusays.com/2023/11/10/654e2cf92cd45.jpg",
|
||||
"https://bu.dusays.com/2023/11/10/654e2cf6055b0.jpg",
|
||||
"https://bu.dusays.com/2023/11/10/654e2db0889fe.jpg",
|
||||
"https://bu.dusays.com/2023/11/10/654e2d50015a9.jpg",
|
||||
"https://bu.dusays.com/2023/11/05/65473848ed863.jpg",
|
||||
"https://bu.dusays.com/2023/11/10/654e2c870e280.jpg",
|
||||
"https://bu.dusays.com/2023/11/10/654e2c717eb73.jpg",
|
||||
"https://bu.dusays.com/2023/11/10/654e2c5d75d5b.jpg",
|
||||
"https://bu.dusays.com/2023/11/10/654e2da27801e.jpg",
|
||||
"https://bu.dusays.com/2023/11/10/654e2d2a67517.jpg",
|
||||
"https://bu.dusays.com/2023/11/10/654e2cf47f17a.jpg",
|
||||
"https://bu.dusays.com/2023/11/05/65473848ed863.jpg"
|
||||
];
|
||||
|
||||
|
||||
return covers[getRandom(0, covers.length - 1)];
|
||||
}
|
||||
6
src/utils/request.ts
Normal file
6
src/utils/request.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
const url = "http://localhost:9999/api"
|
||||
|
||||
export default async (api: string) => {
|
||||
const res = await fetch(`${url}${api}`)
|
||||
return res.json()
|
||||
}
|
||||
Reference in New Issue
Block a user