Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
883 changes: 559 additions & 324 deletions app/[nsfront]/[nsbehind]/[name]/[version]/page.tsx

Large diffs are not rendered by default.

120 changes: 104 additions & 16 deletions components/CrateNav.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React from 'react';
import React, { useState, useEffect } from 'react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import NewHeader from '@/components/NewHeader';
import { useHeaderContext } from '../app/context/CrateContext';
import Image from 'next/image';

interface CrateNavProps {
nsfront: string;
Expand All @@ -13,6 +15,10 @@ interface CrateNavProps {
const CrateNav: React.FC<CrateNavProps> = ({ nsfront, nsbehind, name, version }) => {
const pathname = usePathname();
const basePath = `/${nsfront}/${nsbehind}/${name}/${version}`;
const [isOpen, setIsOpen] = useState(false);
const [currentVersion, setCurrentVersion] = useState(version);
const [searchTerm, setSearchTerm] = useState('');
const { crateData, setCrateData } = useHeaderContext();

const navItems = [
{ name: 'Overview', path: '' },
Expand All @@ -21,32 +27,114 @@ const CrateNav: React.FC<CrateNavProps> = ({ nsfront, nsbehind, name, version })
{ name: 'Versions', path: '/versions' },
];

useEffect(() => {
const fetchData = async () => {
if (!crateData.results) {
const response = await fetch(`/api/crates/${nsfront}/${nsbehind}/${name}/${version}`);
const data = await response.json();
setCrateData({
crateName: data.crate_name,
crateVersion: version,
results: data,
});
}
};

fetchData();
}, [nsfront, nsbehind, name, version, setCrateData, crateData.results]);

const isActive = (path: string) => {
if (path === '') {
return pathname === basePath;
}
return pathname === `${basePath}${path}`;
};

const toggleDropdown = () => {
setIsOpen((prev) => !prev);
};

const closeDropdown = () => {
setIsOpen(false);
};

return (
<div>
<NewHeader />
<nav className="border-b border-gray-200 mb-4">
<div className="flex space-x-8 px-4">
{navItems.map((item) => (
<Link
key={item.name}
href={`${basePath}${item.path}`}
className={`py-4 px-2 border-b-2 ${isActive(item.path)
? 'border-blue-500 text-blue-500'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
}`}
>
{item.name}
</Link>
))}
<div className="flex justify-center px-4 py-6">
<div className="w-[1500px] h-[120px] bg-white rounded-2xl shadow-[0_0_12px_0_rgba(43,88,221,0.09)] px-8">
<div className="flex items-center justify-between h-16">
<div className="flex items-center space-x-4">
<h1 className="text-2xl font-semibold" style={{ color: 'rgb(28, 63, 115)' }}>{name}</h1>
<div className="relative">
<button
onClick={toggleDropdown}
className="flex items-center justify-between w-[150px] h-[36px] flex-shrink-0 rounded-[18.5px] border border-[#333333] bg-white px-4"
>
<span>{currentVersion || 'Select Version'}</span>
<Image
src={isOpen ? "/images/homepage/verison-up.png" : "/images/homepage/version-down.png"}
alt="version"
width={16}
height={16}
/>
</button>
{isOpen && (
<div className="absolute mt-1 w-full z-50">
<div className="fixed inset-0" onClick={closeDropdown}></div>
<div className="relative w-[150px] h-[196px] flex-shrink-0 rounded-[16px] bg-white border border-gray-300 shadow-lg">
<div className="p-2 border-b border-gray-100">
<input
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-[125px] h-[30px] flex-shrink-0 rounded-[9.5px] bg-white focus:bg-[#E2E9FF] border border-[#E5E5E5] focus:outline-none px-2"
/>
</div>
<ul className="max-h-[150px] overflow-y-auto [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none] [&:hover::-webkit-scrollbar]:block [&:hover::-webkit-scrollbar]:w-1 [&:hover::-webkit-scrollbar-thumb]:bg-gray-300 [&:hover::-webkit-scrollbar-track]:bg-transparent">
{crateData.results?.versions
.filter(version => version.toLowerCase().includes(searchTerm.toLowerCase()))
.map((version, index) => (
<Link
key={index}
onClick={() => {
setCurrentVersion(version);
setSearchTerm('');
closeDropdown();
}}
href={`/${nsfront}/${nsbehind}/${crateData.results?.crate_name}/${version}`}
>
<li className="px-4 py-2 hover:bg-[#E2E9FF] cursor-pointer">
{version}
</li>
</Link>
))}
</ul>
</div>
</div>
)}
</div>
</div>
</div>
<nav className="flex space-x-8">
{navItems.map((item) => (
<Link
key={item.name}
href={`${basePath}${item.path}`}
className={`py-4 px-2 relative font-['HarmonyOS_Sans_SC'] text-center min-w-[108px] ${isActive(item.path)
? 'text-blue-500'
: 'text-gray-500 hover:text-gray-700'
}`}
>
{item.name}
{isActive(item.path) && (
<div className="absolute bottom-0 left-1/2 -translate-x-1/2 w-[108px] h-[4px] flex-shrink-0 rounded-t-[3px] bg-[#4B68FF]"></div>
)}
</Link>
))}
</nav>
</div>
</nav>
</div>
</div>
);
};
Expand Down
105 changes: 4 additions & 101 deletions components/HeaderWithSearch.tsx
Original file line number Diff line number Diff line change
@@ -1,83 +1,34 @@
// components/Header.js
'use client';
import React, { useEffect, useState } from 'react';
import React, { useState } from 'react';
import Link from 'next/link';
import { useHeaderContext } from '../app/context/CrateContext';
import { useParams } from 'next/navigation';
import { message } from 'antd';
import { useRouter } from 'next/navigation';
// import { cratesInfo } from '@/app/lib/all_interface';

const Header = () => {
const router = useRouter();
console.log('paramsssssssssssss:', router.refresh);
const params = useParams();
const [messageApi, contextHolder] = message.useMessage();//antd-message的hooks调用
const [messageApi, contextHolder] = message.useMessage();
const [searchQuery, setSearchQuery] = useState('');
const { crateData, setCrateData } = useHeaderContext();
const [isOpen, setIsOpen] = useState(false);


const [currentVersion, setCurrentVersion] = useState(params.version); // 存储当前选中的版本

const handleKeyPress = (e: { key: string; }) => {
// 检查是否按下了回车键
if (e.key === 'Enter') {
// 如果是回车键,执行搜索
performSearch();
}
};

const performSearch = () => {
if (!searchQuery || searchQuery.trim() === '') {

messageApi.warning('请输入搜索内容');
//alert("请输入搜索内容"); // 可选:提示用户输入内容
}
if (searchQuery.trim()) {
// 使用 Link 跳转到搜索页面
window.location.href = `/search?crate_name=${searchQuery}`;
}
};
useEffect(() => {
const path = params.path || ''; // 确保有值
console.log('path:', path);
}, [params.path]); // 依赖于 params.path
// 使用 useEffect 从 API 获取数据
useEffect(() => {
const fetchData = async () => {
// 如果 crateData.results 为空,说明数据还未加载
if (!crateData.results) {
const response = await fetch(`/api/crates/${params.nsfront}/${params.nsbehind}/${params.name}/${params.version}`);
const data = await response.json();
console.log('dataaaaaaaaaaaaaa:', data);
setCrateData({
crateName: data.crate_name,
crateVersion: params.version,
results: data,
});

}
};

fetchData();
}, [params.nsfront, params.nsbehind, params.name, params.version, setCrateData, crateData.crateVersion, crateData.results]); // 添加 crateData 作为依赖项

const toggleDropdown = () => {
setIsOpen((prev) => !prev);
};

const closeDropdown = () => {
setIsOpen(false);

};

return (
<>
{contextHolder}
<header className="bg-white shadow p-4">
<div className="flex justify-between items-center">
<div className="text-xl font-bold flex flex-col items-start space-y-1">
<div className="text-xl font-bold">
<Link href="/">
<div className="text-xl font-bold flex items-center space-x-1">
<span style={{ color: 'rgb(57,62,70)' }}>open</span>
Expand All @@ -87,55 +38,8 @@ const Header = () => {
<span style={{ color: 'rgb(57,62,70)' }}>insights</span>
</div>
</Link>
<div className="flex items-center space-x-2 mt-15">
<span className="text-2xl" style={{ color: 'rgb(28, 63, 115)' }}>{params.name}</span>
<div className="relative">
<button
onClick={toggleDropdown}
className="flex items-center px-4 py-2 border border-gray-300 rounded hover:bg-gray-100"
>
{/* {crateData.crateVersion || 'Select Version'} */}
{currentVersion || 'Select Version'}
<svg
className="ml-2 w-4 h-4"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fillRule="evenodd"
d="M5 10a1 1 0 011-1h8a1 1 0 110 2H6a1 1 0 01-1-1z"
clipRule="evenodd"
/>
</svg>
</button>
{isOpen && (
<div className="absolute mt-1 w-full">
<div className="absolute inset-0 bg-black opacity-50" onClick={closeDropdown}></div>
<div className="relative bg-white border border-gray-300 rounded shadow-lg z-20">
<ul className="max-h-60 overflow-y-auto">
{crateData.results?.versions.map((version, index) => (
<Link
key={index}
onClick={() => {
setCurrentVersion(version);
}}
href={`/${params.nsfront}/${params.nsbehind}/${crateData.results?.crate_name}/${version}`}
>
<li className="px-4 py-2 hover:bg-gray-100 cursor-pointer">

{version}

</li>
</Link>
))}
</ul>
</div>
</div>
)}
</div>
</div>
</div>
<div className="flex items-center mb-4">
<div className="flex items-center">
<input
type="text"
placeholder="Search for open source crates"
Expand All @@ -152,7 +56,6 @@ const Header = () => {
</div>
</header>
</>

);
};

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@
"@types/node": "22.13.10",
"@types/react": "18.3.12",
"@types/react-dom": "18.3.1",
"eslint": "9.22.0",
"eslint": "9.21.0",
"eslint-config-next": "^15.1.0"
},
"engines": {
"node": ">=20.12.0"
}
}
}
Binary file added public/images/homepage/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/homepage/2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/homepage/3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/homepage/4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/homepage/5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/homepage/Vector.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/homepage/miss.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/homepage/verison-up.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/homepage/version-down.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.