diff --git a/app/components/Carousel.tsx b/app/components/Carousel.tsx index 0ea29e9..0baf57b 100755 --- a/app/components/Carousel.tsx +++ b/app/components/Carousel.tsx @@ -11,21 +11,14 @@ import { CarouselPrevious, type CarouselApi, } from "@/ui/carousel"; - const imageUrls = [ +import FireNewsList from "./FireNewsList"; - "/images/carousel-1.jpg", - "/images/carousel-2.jpg", - "/images/carousel-3.jpg", - "/images/carousel-4.jpg", - "/images/carousel-5.jpg", - "/images/carousel-6.jpg", -]; export function CarouselDemo() { const [api, setApi] = React.useState(); const [current, setCurrent] = React.useState(0); const [count, setCount] = React.useState(0); - const totalSlides = imageUrls.length; + const totalSlides = 6; React.useEffect(() => { if (!api) return; @@ -39,7 +32,7 @@ export function CarouselDemo() { }, [api]); return ( -
+
- - {imageUrls.map((src, index) => ( - + + {Array.from({ length: totalSlides }).map((_, index) => ( +
- - {`Slide + +
+
@@ -74,6 +69,7 @@ export function CarouselDemo() {
+ {/* 分页指示器 - 右下角 */}
{Array.from({ length: count }).map((_, index) => ( diff --git a/app/components/FireNewsList.tsx b/app/components/FireNewsList.tsx new file mode 100644 index 0000000..a4712ca --- /dev/null +++ b/app/components/FireNewsList.tsx @@ -0,0 +1,63 @@ +import React from 'react'; + +interface NewsItem { + content: string; +} + +const FireNewsList: React.FC = () => { + const newsItems: NewsItem[] = [ + { + content: "记者从16日召开的海南省政府新闻发布会上获悉,2018年,海南旅游总收入达1,262万人次,支出达399.7亿元...", + }, + { + content: "记者从16日召开的海南省政府新闻发布会上获悉,2018年,海南旅游总收入达1,262万人次,支出达399.7亿元...", + }, + { + content: "记者从16日召开的海南省政府新闻发布会上获悉,2018年,海南旅游总收入达1,262万人次,支出达399.7亿元...", + }, + { + content: "记者从16日召开的海南省政府新闻发布会上获悉,2018年,海南旅游总收入达1,262万人次,支出达399.7亿元...", + }, + { + content: "记者从16日召开的海南省政府新闻发布会上获悉,2018年,海南旅游总收入达1,262万人次,支出达399.7亿元...", + }, + + ]; + + return ( +
+ {/* 标题栏 */} +
+

烽火要闻

+ + 查看更多 {'>'} + +
+ + {/* 新闻列表 */} +
+ {newsItems.map((item, index) => ( +
+ + {/* 内容部分 */} +
+

+ {item.content} + + [MORE] + +

+
+
+ ))} +
+
+ ); +}; + +export default FireNewsList; \ No newline at end of file diff --git a/app/components/body/GrassrootsDynamics.tsx b/app/components/body/GrassrootsDynamics.tsx new file mode 100644 index 0000000..3c64040 --- /dev/null +++ b/app/components/body/GrassrootsDynamics.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import List from '../list/List'; + +export default function GrassrootsDynamics() { + return ( +
+ {/* 左边图片 */} +
+ 基层动态 +
+ {/* 右边列表 */} +
+ +
+
+ ); +} \ No newline at end of file diff --git a/app/components/list/List.tsx b/app/components/list/List.tsx new file mode 100644 index 0000000..0034864 --- /dev/null +++ b/app/components/list/List.tsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { mockNewsData } from './NewsData'; // 导入新闻数据 + + + +interface NewsProps { + title?: string; + description?: string; + time?: string; + type?: string; + url?: string; +} + + +const NewsItem: React.FC = ({ title = '', time = '', url = '' }) => { + return ( +
+
url && window.open(url)} + className="flex items-center justify-between hover:text-blue-600 cursor-pointer transition duration-300 ease-in-out" + > +

{title}

+

{time}

+
+
+ ); +}; + +// 使用新闻数据渲染列表 +const List: React.FC = () => { + return ( +
+
+
+
    + {mockNewsData.map((news) => ( + + ))} +
+
+
+
+ ); +}; + +export default List; \ No newline at end of file diff --git a/app/components/list/NewsData.tsx b/app/components/list/NewsData.tsx index 4d22885..d1d6c17 100644 --- a/app/components/list/NewsData.tsx +++ b/app/components/list/NewsData.tsx @@ -6,6 +6,10 @@ export interface News { url?: string; } +export interface NewsTitle { + id: string; + name: string; +} // 导出生成的模拟新闻数据 export const NewsData = (): News[] => { return [ @@ -25,5 +29,18 @@ export const NewsData = (): News[] => { ]; }; +export const NewsTitleData = (): NewsTitle[] => { + return [ + { id: "news-1", name: "科技" }, + { id: "news-2", name: "财经" }, + { id: "news-3", name: "娱乐" }, + { id: "news-4", name: "体育" }, + { id: "news-5", name: "教育" }, + { id: "news-6", name: "军事" }, + ] +} + + // 默认导出模拟新闻数据 -export const mockNewsData = NewsData(); \ No newline at end of file +export const mockNewsData = NewsData(); +export const mockNewsTitleData = NewsTitleData(); \ No newline at end of file diff --git a/app/components/list/NewsList.tsx b/app/components/list/NewsList.tsx index bdc5959..34160e7 100644 --- a/app/components/list/NewsList.tsx +++ b/app/components/list/NewsList.tsx @@ -1,5 +1,7 @@ import React from 'react'; import { mockNewsData } from './NewsData'; // 导入新闻数据 +import { mockNewsTitleData } from './NewsData'; // 导入新闻标题数据 + interface NewsProps { title?: string; @@ -9,6 +11,10 @@ interface NewsProps { url?: string; } +interface NewsTitle { + id: string; + name: string; +} const NewsItem: React.FC = ({ title = '', time = '', url = '' }) => { return (
@@ -37,8 +43,8 @@ const NewsList: React.FC = () => {
    - {mockNewsData.map((news, index) => ( - + {mockNewsData.map((news) => ( + ))}
diff --git a/app/components/news/body/Culturebg.tsx b/app/components/news/body/Culturebg.tsx new file mode 100644 index 0000000..25a08c5 --- /dev/null +++ b/app/components/news/body/Culturebg.tsx @@ -0,0 +1,54 @@ +import React from 'react'; + +export default function CultureBgPage() { + // 定义logo数据 + const logos = [ + { id: 1, src: '/public/logo/1.png', alt: 'Logo 1' }, + { id: 2, src: '/public/logo/1.png', alt: 'Logo 2' }, + { id: 3, src: '/public/logo/1.png', alt: 'Logo 3' }, + { id: 4, src: '/public/logo/1.png', alt: 'Logo 4' }, + { id: 5, src: '/public/logo/1.png', alt: 'Logo 5' }, + { id: 6, src: '/public/logo/1.png', alt: 'Logo 6' }, + { id: 7, src: '/public/logo/1.png', alt: 'Logo 7' }, + { id: 8, src: '/public/logo/1.png', alt: 'Logo 8' }, + { id: 9, src: '/public/logo/1.png', alt: 'Logo 9' }, + { id: 10, src: '/public/logo/1.png', alt: 'Logo 10' }, + { id: 11, src: '/public/logo/1.png', alt: 'Logo 11' }, + { id: 12, src: '/public/logo/1.png', alt: 'Logo 12' }, + { id: 13, src: '/public/logo/1.png', alt: 'Logo 13' }, + { id: 14, src: '/public/logo/1.png', alt: 'Logo 14' }, + { id: 15, src: '/public/logo/1.png', alt: 'Logo 15' }, + { id: 16, src: '/public/logo/1.png', alt: 'Logo 16' }, + ]; + + return ( +
+
+ +
+
+ {/* 两行八列:flex + wrap */} +
+ {logos.map((logo) => ( + {logo.alt} + ))} +
+
+
+
+ ); +} \ No newline at end of file diff --git a/app/components/news/body/Integrated.tsx b/app/components/news/body/Integrated.tsx new file mode 100644 index 0000000..96817c3 --- /dev/null +++ b/app/components/news/body/Integrated.tsx @@ -0,0 +1,72 @@ +import type { IconType } from 'react-icons'; +import { + FaUserGraduate, + FaUserShield, + FaLaptopCode, + FaMicrophoneLines, + FaEnvelopeOpenText, + FaWrench, + FaRegFileLines, + FaSpellCheck, + FaChartPie, + FaGlobe, + FaBookOpenReader, + FaPenRuler, +} from 'react-icons/fa6'; + +type ServiceItem = { + icon: IconType; + label: string; + href: string; +}; + +const services: ServiceItem[] = [ + { icon: FaUserGraduate, label: '警队自考', href: '/study' }, + { icon: FaUserShield, label: '警队教育', href: '/scholarship' }, + { icon: FaLaptopCode, label: '常用软件', href: '/software' }, + { icon: FaMicrophoneLines, label: '智能语音', href: '/voice' }, + { icon: FaEnvelopeOpenText, label: '蓝天邮局', href: '/mail' }, + { icon: FaWrench, label: '策划工具', href: '/plan' }, + { icon: FaRegFileLines, label: '办公模板', href: '/office' }, + { icon: FaSpellCheck, label: '智能校对', href: '/ai-check' }, + { icon: FaChartPie, label: '警情调研', href: '/survey' }, + { icon: FaGlobe, label: '上网助手', href: '/net' }, + { icon: FaBookOpenReader, label: '考试平台', href: '/exam' }, + { icon: FaPenRuler, label: '学习平台', href: '/study' }, +]; + +const columns = Array.from({ length: 3 }, (_, colIndex) => + services.slice(colIndex * 4, colIndex * 4 + 4) +); + +export default function Integrated() { + return ( +
+
+
+
+

综合服务

+
+ +
+ {columns.map((group, colIdx) => ( +
+ {group.map((service) => ( + +
+ +
+ {service.label} +
+ ))} +
+ ))} +
+
+
+ ); +} \ No newline at end of file diff --git a/app/components/header/Header.tsx b/app/components/news/header/Header.tsx similarity index 92% rename from app/components/header/Header.tsx rename to app/components/news/header/Header.tsx index 1714f94..96d3624 100644 --- a/app/components/header/Header.tsx +++ b/app/components/news/header/Header.tsx @@ -15,7 +15,7 @@ export function Header(){ return (
{/* 时间显示 只显示日期: "2025/3/15"*/} diff --git a/app/components/header/TopNav.tsx b/app/components/news/header/TopNav.tsx similarity index 100% rename from app/components/header/TopNav.tsx rename to app/components/news/header/TopNav.tsx diff --git a/app/routes/news.tsx b/app/routes/news.tsx index dd1e84b..c7e1696 100755 --- a/app/routes/news.tsx +++ b/app/routes/news.tsx @@ -1,9 +1,13 @@ -import { CarouselDemo } from "@/components/Carousel"; + import type { Route } from "./+types/news"; -import {Header} from "@/components/header/Header"; -import {TopNav} from "@/components/header/TopNav"; +import Integrated from "@/components/news/body/Integrated"; +import CultureBgPage from "@/components/news/body/Culturebg"; +import {Header} from "@/components/news/header/Header"; +import {TopNav} from "@/components/news/header/TopNav"; import NewsList from "@/components/list/NewsList"; import ImageGridSection from "@/components/body/ImageGridSection"; +import { CarouselDemo } from "@/components/Carousel"; +import GrassrootsDynamics from "@/components/body/GrassrootsDynamics"; export function meta( ) { return [ { title: "New React Router App" }, @@ -12,12 +16,16 @@ export function meta( ) { } export default function Home() { + return (
+ + +
); } diff --git a/package.json b/package.json index a6398ff..bfd31e6 100755 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "lucide-react": "^0.553.0", "next-themes": "^0.4.6", "react": "^19.1.1", + "react-icons": "^5.5.0", "react-dom": "^19.1.1", "react-router": "^7.9.2", "shadcn": "^3.5.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8313dcb..d8d961f 100755 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -65,6 +65,9 @@ importers: react-dom: specifier: ^19.1.1 version: 19.2.0(react@19.2.0) + react-icons: + specifier: ^5.5.0 + version: 5.5.0(react@19.2.0) react-router: specifier: ^7.9.2 version: 7.9.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -2382,6 +2385,11 @@ packages: peerDependencies: react: ^19.2.0 + react-icons@5.5.0: + resolution: {integrity: sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==} + peerDependencies: + react: '*' + react-refresh@0.14.2: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} @@ -5082,6 +5090,10 @@ snapshots: react: 19.2.0 scheduler: 0.27.0 + react-icons@5.5.0(react@19.2.0): + dependencies: + react: 19.2.0 + react-refresh@0.14.2: {} react-remove-scroll-bar@2.3.8(@types/react@19.2.6)(react@19.2.0): diff --git a/public/culture.png b/public/culture.png new file mode 100644 index 0000000..48c95bf Binary files /dev/null and b/public/culture.png differ diff --git a/public/logo/1.png b/public/logo/1.png new file mode 100644 index 0000000..7bd99b9 Binary files /dev/null and b/public/logo/1.png differ