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
4 changes: 0 additions & 4 deletions src/i18n/team.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ export const teamI18n = {
wechatFollow: '关注微信公众号',
createLine1: '创造',
createLine2: '正发生',
loadFailed: '团队数据加载失败,请重试。',
retryAction: '重试',
cookieSettings: 'Cookie 设置',
disclaimer: '免责声明 本网站所引用的 AdventureX 商标由杭州宇徐科技有限公司所有,TechCrunch 商标由科技媒体控股国际有限责任公司持有,SegmentFault 商标由武汉复临科技有限公司持有。本网站仅为叙述与说明目的引用上述商标,不用于商业用途,不代表与上述权利人存在任何关联或合作关系。所有商标权利归其各自权利人所有。'
},
Expand All @@ -42,8 +40,6 @@ export const teamI18n = {
wechatFollow: 'Follow us on WeChat',
createLine1: 'Creation',
createLine2: 'is happening.',
loadFailed: 'Failed to load team data. Please try again.',
retryAction: 'Retry',
cookieSettings: 'Cookie Preferences',
disclaimer: 'Disclaimer: The AdventureX trademark referenced on this website is owned by Hangzhou Yuxu Technology Co., Ltd.; the TechCrunch trademark is held by Tech Media Holdings International LLC; the SegmentFault trademark is owned by Wuhan Fulin Technology Co., Ltd. This website references the above trademarks solely for narrative and illustrative purposes, not for commercial use, and does not imply any affiliation or partnership with the rights holders. All trademark rights belong to their respective owners.'
}
Expand Down
57 changes: 6 additions & 51 deletions src/pages/Team.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { useScrollState } from '../hooks/useScrollState';
import { useTeamAnimations } from '../hooks/useRevealAnimations';
import { prefersReducedMotion, scrollToTarget } from '../lib/scroll';
import { teamI18n, type TeamI18nKey } from '../i18n/team';
import teamJson from '../../public/team.json';

interface LocalizedText {
zh: string;
Expand All @@ -36,6 +37,9 @@ interface TeamData {
groups: TeamGroupData[];
}

// 构建时内联自 public/team.json;该文件同时服务旧缓存 bundle 的 fetch('team.json'),缓存过期前勿删
const teamData: TeamData = teamJson;

function sortMembers(members: TeamMemberData[]): TeamMemberData[] {
return [...members].sort((a, b) =>
a.nickname.zh.localeCompare(b.nickname.zh, 'zh-CN')
Expand Down Expand Up @@ -114,56 +118,24 @@ export function Team() {
const { ready } = useLenis();
const { scrolled, showScrollTop } = useScrollState(false);
const [activeMember, setActiveMember] = useState<string | null>(null);
const [teamData, setTeamData] = useState<TeamData>({ groups: [] });
const [dataSettled, setDataSettled] = useState(false);
const [loadError, setLoadError] = useState(false);
const [retryCount, setRetryCount] = useState(0);
const memberCount = teamData.groups.reduce(
(count, group) => count + group.members.length,
0
);
useTeamAnimations(memberCount);

useEffect(() => {
let cancelled = false;
setLoadError(false);
setDataSettled(false);
fetch('team.json')
.then((res) => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
})
.then((data: TeamData) => {
if (!cancelled && Array.isArray(data.groups)) {
setTeamData(data);
setDataSettled(true);
}
})
.catch(() => {
if (!cancelled) {
setLoadError(true);
setDataSettled(true);
}
});
return () => {
cancelled = true;
};
}, [retryCount]);

useEffect(() => {
if (!ready && !prefersReducedMotion) return;
if (!dataSettled) return;
const hash = window.location.hash;
if (!hash || hash === '#') return;
const target = document.querySelector<HTMLElement>(hash);
if (!target) return;
const timer = setTimeout(() => {
// Lenis 的 scrollTo 会自动应用 scroll-margin-top,无需手动补偿;
// refresh=true 确保数据刚渲染后 Lenis 的滚动上限已更新
// Lenis 的 scrollTo 自动应用 scroll-margin-top;refresh=true 确保滚动上限已更新
scrollToTarget(target, 0, true);
}, 120);
return () => clearTimeout(timer);
}, [ready, dataSettled]);
}, [ready]);

const handleToggleLang = () => {
toggleLang();
Expand Down Expand Up @@ -216,23 +188,6 @@ export function Team() {
</div>
</section>

{loadError && (
<section className="team-group section-alt">
<div className="container">
<div className="team-group-header reveal" role="alert">
<p className="team-group-label">{t('loadFailed')}</p>
<button
type="button"
className="team-group-desc"
onClick={() => setRetryCount((c) => c + 1)}
>
{t('retryAction')}
</button>
</div>
</div>
</section>
)}

{teamData.groups.map((group) => {
const keys = groupKeyMap[group.id];
const members = sortMembers(group.members ?? []);
Expand Down
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"skipLibCheck": true,

"moduleResolution": "bundler",
"resolveJsonModule": true,
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
Expand Down
Loading