Skip to content
Merged
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
2 changes: 1 addition & 1 deletion src/app/bounties/ListSkeleton.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function ListSkeleton() {
</div>
</div>
</div>
<div className="mb-9 mt-6 grid gap-5 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-4 3xl:grid-cols-5">
<div className="mb-9 mt-3.5 grid gap-5 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-4 3xl:grid-cols-5">
{new Array(10).fill(',').map((i, k) => (
<div
key={`ListSkeleton-${k}`}
Expand Down
92 changes: 50 additions & 42 deletions src/domain/bounty/views/bounty-list/BountyItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,65 +18,73 @@ import Link from 'next/link';

import Avatar from '@/components/Avatar';
import { ArrowRightLineIcon } from '@/components/Icons';
import Image from '@/components/Image';
import { fromNow } from '@/utils/date';

import { useConfig } from '#/state/application/hooks';

import StatusBadge from './StatusBadge';

// import { useConfig } from '#/state/application/hooks';


function BountyItem({ data }) {
const config = useConfig();
const filters = config?.find(f => f.config_id === 1)?.config_value['bounty'];
const ecosystem = filters?.find(f => f.name === 'Ecosystem')?.labels.find(f => f.id === data.ecosystem);
// const config = useConfig();
// const filters = config?.find(f => f.config_id === 1)?.config_value['bounty'];
// const ecosystem = filters?.find(f => f.name === 'Ecosystem')?.labels.find(f => f.id === data.ecosystem);

// 根据状态确定顶部边框颜色
const getBorderColor = status => {
if (status === 3) return 'border-t-[#17C489]'; // Recruiting - 绿色
if (status > 6 && status < 24) return 'border-t-[#D672EF]'; // Building - 紫色
if (status === 30 || status === 24 || status === 20) return 'border-t-[#82ADD8]'; // Completed/Closed - 蓝色
return 'border-t-[#D1D5DB]';
};

return (
<Link
href={`/bounties/${data.id}`}
className={`
group flex flex-col relative cursor-pointer overflow-hidden rounded-2xl
bg-gradient-to-b ${ data.status === 3 ? 'from-[#E5E5FE] to-[#FFFFFF]' : 'bg-white'}
py-4 transition-all duration-300 ease-in-out hover:shadow-lg hover:-translate-y-2 [&>div]:px-4
group flex flex-col relative cursor-pointer overflow-hidden rounded-xl
bg-white border border-[#E5E7EB] border-t-[3px] ${getBorderColor(data.status)}
transition-all duration-300 ease-in-out hover:shadow-xl hover:-translate-y-1
`}
>
<div>
<Image className="mb-4 bg-neutral-300 rounded-full object-cover" width={80} height={80} src={ecosystem?.img} alt={ecosystem?.name} />
<h5 className="mb-2 text-lg line-clamp-2">
<span className="relative top-[2px]">{data.title}</span>
</h5>
</div>
<div className="flex-1">
<div className="mb-4 max-h-10 text-sm opacity-80 line-clamp-2">
<p>{data.summary}</p>
</div>
<div className="flex items-center gap-2">
<div className="flex items-center">
<StatusBadge status={data.status} />
</div>
{/* 顶部状态标签区域 */}
<div className="px-6 pt-5 pb-4">
<div className="flex items-center gap-2 flex-wrap">
<StatusBadge status={data.status} />
{/* 这里可以添加其他标签,如 Front-end, Part-time 等 */}
</div>
</div>
<hr className="mt-6 mb-4 border-gray-400" />
<div className="flex items-center justify-between">
<p className="text-sm">Reward</p>
<div className="text-right">
<div className="flex items-center justify-end text-sm">
<strong className="text-lg">${data.amount / 100}</strong>
</div>

{/* 标题和描述 */}
<div className="px-6 pb-4 flex-1 min-h-[162px]">
<h3 className="mb-2 text-[24px] font-extrabold line-clamp-2 leading-[26px]">
{data.title}
</h3>
<p className="text-[16px] font-normal line-clamp-2 leading-[20px] opacity-80">
{data.summary}
</p>
</div>

{/* Bounty Amount */}
<div className="px-6 py-6 border-t border-[#1a1a1a0f]">
<div className="flex items-center justify-between">
<span className="text-[14px] font-bold leading-[24px]">Bounty Amount</span>
<span className="text-[20px] font-extrabold text-[#111827] leading-[24px]">${data.amount / 100}</span>
</div>
</div>
<hr className="my-4 border-gray-400" />
<div className="flex items-center">
<div className="flex flex-1 items-center truncate">
<Avatar className="mr-4" size={48} user={data?.employer_user} />
<div className="text-xs text-gray-50">
<p className="truncate">
{fromNow(data.created_at * 1000)} by{' '}
<a href={`/u/${data.employer_user?.user_handle}`} className="truncate font-bold text-gray underline">{data.employer_user?.user_nick_name}</a>
</p>

{/* 底部发布者信息 */}
<div className="p-6 border-t border-[#1a1a1a0f]">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2 flex-1 min-w-0">
<Avatar size={24} user={data?.employer_user} />
<div className="text-[14px] leading-[24px] truncate text-[#00000066]">
<span className="text-gray">By {data.employer_user?.user_nick_name}</span>
<span className="mx-1">·</span>
<span>{fromNow(data.created_at * 1000)}</span>
</div>
</div>
</div>
<div>
<ArrowRightLineIcon className="h-6 w-6" />
<ArrowRightLineIcon className="h-5 w-5 flex-shrink-0 -rotate-45" />
</div>
</div>
</Link>
Expand Down
2 changes: 1 addition & 1 deletion src/domain/bounty/views/bounty-list/BountyList.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function BountyListView({
<>
<div
className={clsx(
'mb-9 mt-6 grid gap-5 md:grid-cols-3',
'mb-9 mt-3.5 grid gap-5 md:grid-cols-3',
className
)}
>
Expand Down
33 changes: 12 additions & 21 deletions src/domain/bounty/views/bounty-list/StatusBadge.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,29 @@
const badgeList = [
{
label: 'Recruiting',
emoji: '🧱',
textColor: 'text-[#807DFB]',
bgColor: 'bg-[#807DFB]',
borderColor: 'border-[#807DFB]',
textColor: 'text-[#17C489]',
bgColor: 'bg-[rgba(23,196,137,0.08)]',
borderColor: 'border-[#17C489]',
isMatched: status => status === 3,
},
{
label: 'Building',
emoji: '🔫',
textColor: 'text-[#00C475]',
bgColor: 'bg-[#01DB83]',
borderColor: 'border-[#01DB83]',
textColor: 'text-[#D672EF]',
bgColor: 'bg-[rgba(214,114,239,0.08)]',
borderColor: 'border-[#D672EF]',
isMatched: status => status > 6 && status < 24,
},
{
label: 'Completed',
emoji: '🔚',
textColor: 'text-[#82ADD8]',
bgColor: 'bg-[#82ADD8]',
bgColor: 'bg-[rgba(130,173,216,0.08)]',
borderColor: 'border-[#82ADD8]',
isMatched: status => status === 30,
},
{
label: 'Termination',
emoji: '🔚',
label: 'Closed',
textColor: 'text-[#82ADD8]',
bgColor: 'bg-[#82ADD8]',
bgColor: 'bg-[rgba(130,173,216,0.08)]',
borderColor: 'border-[#82ADD8]',
isMatched: status => status === 24 || status === 20,
},
Expand All @@ -53,14 +49,9 @@ function StatusBadge({ status }) {
const badge = badgeList.find(({ isMatched }) => isMatched(status));

return badge && (
<div className={`inline-flex items-center gap-2 p-[3px] ${badge.bgColor} bg-opacity-10 rounded-full`}>
<span className={`size-6 text-xs rounded-full text-center leading-[22px] border-1 ${badge.borderColor}`}>
{badge.emoji}
</span>
<span className={`text-xs font-semibold ${badge.textColor} font-nunito leading-[12px] text-left pr-2`}>
{badge.label}
</span>
</div>
<span className={`inline-flex items-center px-2 py-1.5 rounded-[6px] text-xs leading-[12px] border ${badge.textColor} ${badge.bgColor} ${badge.borderColor}`}>
{badge.label}
</span>
);
}

Expand Down
2 changes: 1 addition & 1 deletion src/entry/components/basic-search/BasicSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type BasicSearchProps = {

function BasicSearch({ className }: BasicSearchProps) {
return (
<div className={clsx('flex items-center', className)}>
<div className={clsx('flex items-center gap-4 w-full justify-end flex-col md:flex-row', className)}>
<SearchFilter />
<SortFilter />
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/entry/components/basic-search/SearchFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function SearchFilter() {
}, 300);

return (
<div className="max-w-[180px]">
<div className="w-full md:max-w-[360px]">
<Input
defaultValue={searchParams.get('query')?.toString()}
type="search"
Expand Down
2 changes: 1 addition & 1 deletion src/entry/components/basic-search/SortFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function SortFilter() {
return searchParams?.get('order') || null;
}, [searchParams]);
return (
<div className="w-[180px] ml-2">
<div className="w-full md:w-[206px]">
<ReactSelect
isClearable
isSearchable={false}
Expand Down
2 changes: 1 addition & 1 deletion src/entry/layouts/list/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { ArrowRightIcon } from '@/components/Icons';

function Header({ title, desc, link, linkText }) {
return (
<div className="pt-6 pb-6 text-center">
<div className="pt-9 pb-9 text-center">
<h1 className="text-[24px] font-bold leading-[32px] md:text-[36px] md:leading-[42px]">{title}</h1>
<div className="mt-2 flex justify-center flex-col text-[13px] opacity-80 md:flex-row md:items-center md:text-[15px]">
<p>{desc}</p>
Expand Down
8 changes: 6 additions & 2 deletions src/shared/components/Input/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
import type { InputProps } from '@nextui-org/input';

const styles = {
input: [ 'bg-transparent', 'placeholder:opacity-40', 'ml-1' ],
innerWrapper: 'border border-gray-600 hover:border-gray h-12 text-sm px-3 rounded',
input: [ 'bg-transparent', 'placeholder:opacity-40', 'ml-0.5' ],
innerWrapper: 'border border-gray-600 hover:border-gray h-12 text-sm px-4 rounded',
inputWrapper: [ 'shadow-none' ],
};

Expand All @@ -40,6 +40,10 @@
},
});

console.log({
...getInputProps()

Check warning on line 44 in src/shared/components/Input/index.tsx

View workflow job for this annotation

GitHub Actions / lint

Missing trailing comma
})

Check warning on line 45 in src/shared/components/Input/index.tsx

View workflow job for this annotation

GitHub Actions / lint

Missing semicolon

const innerWrapper = React.useMemo(() => {
if (startContent) {
return (
Expand Down
10 changes: 5 additions & 5 deletions src/shared/components/Pagination/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ export function OPagination({ page, pageSize = PAGE_SIZE, total, changeCallback

return total > 0 ? (
<div className="flex justify-end">
<div className="flex mt-5 md:mt-4">
<div className="flex">
{
currentPage > 1 && <Button
variant="light"
className="mr-2 h-9"
variant="text"
className="mr-2 h-9 underline"
disabled={currentPage <= 1}
onClick={() => change(currentPage > 1 && currentPage - 1)}
>
Expand All @@ -80,9 +80,9 @@ export function OPagination({ page, pageSize = PAGE_SIZE, total, changeCallback
onChange={page => change(page)}
/>
<Button
variant="light"
variant="text"
disabled={currentPage >= totalPage}
className="ml-2 h-9"
className="ml-2 h-9 underline"
onClick={() => change(currentPage < totalPage && currentPage + 1)}
>
Next
Expand Down
2 changes: 1 addition & 1 deletion src/shared/styles/_react-select.scss
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
display: none;
}
.react-select__value-container {
padding-left: 8px;
padding-left: 14px;
}
.react-select__dropdown-indicator {
transform: rotate(0deg);
Expand Down
Loading