Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
af78882
chore: make env sync explicit
luojiyin1987 Apr 21, 2026
ebf6972
docs: document explicit env sync
luojiyin1987 Apr 21, 2026
7d82b01
fix: stabilize hackathon detail hydration
luojiyin1987 Apr 21, 2026
14d64e9
fix: suppress product card hydration mismatch
luojiyin1987 Apr 21, 2026
f194794
i18n: add hackathon team showcase label in en-US
luojiyin1987 Apr 21, 2026
f30369f
i18n: add hackathon team showcase label in zh-CN
luojiyin1987 Apr 21, 2026
d00122b
i18n: add hackathon team showcase label in zh-TW
luojiyin1987 Apr 21, 2026
cab62c1
feat: add hackathon team page styles
luojiyin1987 Apr 21, 2026
6e4f39e
feat: redesign hackathon team detail page
luojiyin1987 Apr 21, 2026
8c12e16
refactor: extract hackathon countdown resolver
luojiyin1987 Apr 21, 2026
8ed3e06
refactor: use shared hackathon user helper
luojiyin1987 Apr 21, 2026
1c7d4d8
refactor: simplify hackathon detail countdown
luojiyin1987 Apr 21, 2026
e00e2eb
refactor: simplify hackathon team countdown
luojiyin1987 Apr 21, 2026
e565a66
refactor: clarify hackathon countdown reference time
luojiyin1987 Apr 21, 2026
67c97d9
refactor: rename hero countdown client clock
luojiyin1987 Apr 21, 2026
e31bfea
refactor: rename hackathon agenda reference time
luojiyin1987 Apr 21, 2026
1b47f1a
refactor: rename team agenda reference time
luojiyin1987 Apr 21, 2026
ba6607f
fix: align hackathon hero fallback action
luojiyin1987 Apr 21, 2026
1e5b881
fix: align team hero fallback action
luojiyin1987 Apr 21, 2026
dc8ee07
fix: avoid epoch fallback for missing hackathon times
luojiyin1987 Apr 22, 2026
02fd7aa
fix: normalize hackathon time parsing
luojiyin1987 Apr 22, 2026
01f3472
feat: add live hackathon countdown state hook
luojiyin1987 Apr 22, 2026
aa5f4a6
fix: compute hackathon detail countdown on client
luojiyin1987 Apr 22, 2026
180ce0e
fix: compute hackathon team countdown on client
luojiyin1987 Apr 22, 2026
fb28d94
fix: remove public creator email links
luojiyin1987 Apr 22, 2026
e4d5075
fix: normalize hackathon rich text extraction
luojiyin1987 Apr 22, 2026
3351ccb
fix: guard hackathon detail schema access
luojiyin1987 Apr 22, 2026
f85c138
fix: harden hackathon team public access
luojiyin1987 Apr 22, 2026
0c45861
fix: localize hackathon team breadcrumb label
luojiyin1987 Apr 22, 2026
b5a70ed
feat: add english breadcrumb translation
luojiyin1987 Apr 22, 2026
729455e
feat: add simplified chinese breadcrumb translation
luojiyin1987 Apr 22, 2026
7ca1d72
feat: add traditional chinese breadcrumb translation
luojiyin1987 Apr 22, 2026
8d7649e
fix: stabilize live countdown refresh callback
luojiyin1987 Apr 22, 2026
26a42d2
fix: return standard hackathon detail notFound
luojiyin1987 Apr 22, 2026
72b77bf
fix: return standard hackathon team notFound
luojiyin1987 Apr 22, 2026
d30960b
fix: support string product timestamps
luojiyin1987 Apr 22, 2026
eb20e2d
fix: sort hackathon detail agenda safely
luojiyin1987 Apr 22, 2026
236fee5
fix: sort hackathon team agenda safely
luojiyin1987 Apr 22, 2026
79c8b39
refactor: clarify hackathon countdown fallback logic
luojiyin1987 Apr 22, 2026
ba51623
fix: require valid hackathon detail form links
luojiyin1987 Apr 22, 2026
2fd23a2
fix: require valid hackathon team form links
luojiyin1987 Apr 22, 2026
dc2661a
fix: ignore empty product timestamps
luojiyin1987 Apr 22, 2026
0e5e716
refactor: reuse hackathon time parsing
luojiyin1987 Apr 22, 2026
d14dde3
fix: use grouped hackathon forms consistently
luojiyin1987 Apr 22, 2026
e7e5249
fix: require shareable hackathon team forms
luojiyin1987 Apr 22, 2026
e8f504f
fix: del no use import
luojiyin1987 Apr 22, 2026
f5c705c
fix: ignore boolean hackathon text values
luojiyin1987 Apr 22, 2026
7759941
refactor: focus hackathon team page on team content
luojiyin1987 Apr 23, 2026
00f8e86
style: compact hackathon team hero layout
luojiyin1987 Apr 23, 2026
cb7340e
fix: normalize hackathon countdown target
luojiyin1987 Apr 23, 2026
7416884
fix: normalize hackathon team project queries
luojiyin1987 Apr 23, 2026
2cbc9ef
fix: restore automatic env sync on install
luojiyin1987 Apr 28, 2026
ef8ec5f
fix: restore countdown state naming
luojiyin1987 Apr 28, 2026
6ffb732
fix: restore hackathon route param assumption
luojiyin1987 Apr 28, 2026
bcea1fa
refactor: use bootstrap utilities in hackathon team page
luojiyin1987 Apr 28, 2026
bbe4ff9
refactor: simplify hackathon team less rules
luojiyin1987 Apr 28, 2026
848345f
[refactor] simplify AI codes
TechQuery Apr 28, 2026
f057917
[optimize] simplify AI codes
TechQuery Apr 28, 2026
6edd8e0
[fix] Prettier formatting bug of LESS mixin
TechQuery Apr 28, 2026
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
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@
## 开始

```bash
pnpm run sync-env
pnpm install
pnpm dev
```

`pnpm run sync-env` 会在你显式执行时,从 `Open-Source-Bazaar/key-vault` 同步当前项目所需的私有环境文件。出于安全考虑,仓库不会在 `pnpm install` 阶段自动下载 `.env.local`。
Comment thread
luojiyin1987 marked this conversation as resolved.
Outdated

可访问 http://localhost:3000.

[1]: https://github.com/idea2app/Lark-Next-Bootstrap-ts
Expand Down
136 changes: 75 additions & 61 deletions components/Activity/ProductCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,68 +10,82 @@ import styles from '../../styles/Hackathon.module.less';
export type ProductCardProps = Product & Omit<CardProps, 'id' | 'title'>;

export const ProductCard: FC<ProductCardProps> = observer(
({ className = '', id, createdAt, name, sourceLink, link = sourceLink, summary, ...props }) => (
<Card className={`${styles.projectCard} ${className}`} {...props}>
<Card.Body className="d-flex flex-column">
<Card.Title
as="a"
className="text-dark fw-bold"
title={name as string}
target="_blank"
href={link as string}
>
{(name || link) as string}
</Card.Title>
<p className="text-dark opacity-75 mb-3">{summary as string}</p>
<div className="flex-fill mb-3">
<FilePreview className="w-100" path={link as string} />
</div>
({ className = '', id, createdAt, name, sourceLink, link = sourceLink, summary, ...props }) => {
const createdAtValue = Number(createdAt);
const createdAtISO = Number.isFinite(createdAtValue)
? new Date(createdAtValue).toJSON()
: undefined;
const createdAtText = Number.isFinite(createdAtValue) ? formatDate(createdAtValue) : '';
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

{sourceLink && (
<div className="d-flex flex-wrap gap-2 mb-3">
<Button
variant="dark"
size="sm"
href={sourceLink as string}
target="_blank"
rel="noreferrer"
>
GitHub
</Button>
<Button
variant="primary"
size="sm"
href={`https://github.dev/${(sourceLink as string).replace('https://github.com/', '')}`}
target="_blank"
rel="noreferrer"
>
GitHub.dev
</Button>
<Button
variant="dark"
size="sm"
href={`https://codespaces.new/${(sourceLink as string).replace('https://github.com/', '')}`}
target="_blank"
rel="noreferrer"
>
Codespaces
</Button>
<Button
variant="warning"
size="sm"
href={`https://gitpod.io/#${sourceLink as string}`}
target="_blank"
rel="noreferrer"
>
GitPod
</Button>
return (
<Card className={`${styles.projectCard} ${className}`} {...props}>
<Card.Body className="d-flex flex-column">
<Card.Title
as="a"
className="text-dark fw-bold"
title={name as string}
target="_blank"
href={link as string}
>
{(name || link) as string}
</Card.Title>
<p className="text-dark opacity-75 mb-3">{summary as string}</p>
<div className="flex-fill mb-3">
<FilePreview className="w-100" path={link as string} />
</div>
)}

<time className="text-dark opacity-75 small" dateTime={new Date(createdAt as number).toJSON()}>
📅 {formatDate(createdAt as number)}
</time>
</Card.Body>
</Card>
),
{sourceLink && (
<div className="d-flex flex-wrap gap-2 mb-3">
<Button
variant="dark"
size="sm"
href={sourceLink as string}
target="_blank"
rel="noreferrer"
>
GitHub
</Button>
<Button
variant="primary"
size="sm"
href={`https://github.dev/${(sourceLink as string).replace('https://github.com/', '')}`}
target="_blank"
rel="noreferrer"
>
GitHub.dev
</Button>
<Button
variant="dark"
size="sm"
href={`https://codespaces.new/${(sourceLink as string).replace('https://github.com/', '')}`}
target="_blank"
rel="noreferrer"
>
Codespaces
</Button>
<Button
variant="warning"
size="sm"
href={`https://gitpod.io/#${sourceLink as string}`}
target="_blank"
rel="noreferrer"
>
GitPod
</Button>
</div>
)}

{createdAtISO && (
<time
suppressHydrationWarning
className="text-dark opacity-75 small"
dateTime={createdAtISO}
>
📅 {createdAtText}
</time>
)}
</Card.Body>
</Card>
);
},
);
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"private": true,
"scripts": {
"prepare": "husky",
"install": "pnpx git-utility download https://github.com/Open-Source-Bazaar/key-vault main Open-Source-Bazaar.github.io || true",
"sync-env": "pnpx git-utility download https://github.com/Open-Source-Bazaar/key-vault main Open-Source-Bazaar.github.io",
"postinstall": "next typegen",
"dev": "next dev --webpack",
"build": "next build --webpack",
Expand Down
6 changes: 4 additions & 2 deletions pages/hackathon/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ interface HackathonDetailProps {
projects: Project[];
templates: Template[];
};
renderedAt: number;
}

export const getServerSideProps = compose<{ id: string }>(
Expand Down Expand Up @@ -99,12 +100,13 @@ export const getServerSideProps = compose<{ id: string }>(
props: {
activity,
hackathon: { people, organizations, agenda, prizes, templates, projects },
renderedAt: Date.now(),
},
};
},
);

const HackathonDetail: FC<HackathonDetailProps> = observer(({ activity, hackathon }) => {
const HackathonDetail: FC<HackathonDetailProps> = observer(({ activity, hackathon, renderedAt }) => {
const i18n = useContext(I18nContext);
const { t } = i18n;
const {
Expand Down Expand Up @@ -182,7 +184,7 @@ const HackathonDetail: FC<HackathonDetailProps> = observer(({ activity, hackatho
};
})
.filter(({ date, label }) => Boolean(date && label));
const now = Date.now();
const now = renderedAt;
const nextAgendaItem = agendaItems.find(({ startedAt, endedAt }) => {
const started = new Date((startedAt as string) || 0).getTime();
const ended = new Date((endedAt as string) || 0).getTime();
Expand Down
Loading
Loading