Skip to content
Merged
105 changes: 105 additions & 0 deletions app/components/CommunityNetwork.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
"use client";

import Image from "next/image";
import { ArrowUpRight } from "lucide-react";
import { motion, useReducedMotion } from "motion/react";
import { cn } from "@/lib/utils";

type Outpost = {
key: string;
callsign: string;
title: string;
desc: string;
href: string;
live?: boolean;
};

/**
* 首页"社区网络"版块:三个生态前哨(monitor / mc / openInvest)做成全宽波段,
* 滚动进入视口时错峰升起,hover 时墨色从左漫过整条(反色 wipe)。
* reduced-motion 时跳过入场动画,直接渲染最终可见状态。
*/
export function CommunityNetwork({
label,
outposts,
}: {
label: string;
outposts: Outpost[];
}) {
const reduce = useReducedMotion();
const animate = !reduce;

return (
<div className="mt-16 border-t-4 border-[var(--foreground)] transition-colors duration-300">
<div className="flex items-center gap-2 py-4 font-mono text-xs uppercase tracking-widest border-b border-[var(--foreground)] text-[var(--foreground)]">
<Image
src="/friends/ailumao.png"
alt=""
width={22}
height={22}
className="[image-rendering:pixelated]"
/>
{label}
</div>

<ul>
{outposts.map((o, i) => (
<motion.li
key={o.key}
initial={animate ? { opacity: 0, y: 26 } : false}
whileInView={animate ? { opacity: 1, y: 0 } : undefined}
viewport={{ once: true, amount: 0.4 }}
transition={{
duration: 0.55,
delay: i * 0.12,
ease: [0.22, 1, 0.36, 1],
}}
className={cn(
"group relative overflow-hidden border-[var(--foreground)]",
i < outposts.length - 1 && "border-b",
)}
>
{/* 墨色 wipe 层:hover 时从左漫满整条 */}
<span
aria-hidden
className="pointer-events-none absolute inset-0 origin-left scale-x-0 bg-[var(--foreground)] transition-transform duration-500 ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:scale-x-100 motion-reduce:transition-none"
/>

<a
href={o.href}
target="_blank"
rel="noopener noreferrer"
className="relative flex flex-col gap-3 py-9 px-6 transition-colors duration-500 group-hover:text-[var(--background)] md:flex-row md:items-center md:gap-8"
data-umami-event="community_click"
data-umami-event-target={o.key}
data-umami-event-location="hero"
>
{/* 呼号 */}
<span className="flex w-28 shrink-0 items-center gap-2 font-mono text-[11px] uppercase tracking-[0.2em] text-neutral-400 group-hover:text-[var(--background)]">
{o.live && (
<span className="relative flex h-1.5 w-1.5">
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-[#CC0000] opacity-75 motion-reduce:hidden" />
<span className="relative inline-flex h-1.5 w-1.5 rounded-full bg-[#CC0000]" />
</span>
)}
{o.callsign}
</span>

{/* 站名(超大衬线,编辑体信号) */}
<span className="font-serif text-3xl font-bold uppercase leading-none tracking-tight text-[var(--foreground)] group-hover:text-[var(--background)] md:text-4xl">
{o.title}
</span>

{/* 描述 */}
<span className="font-body text-sm leading-relaxed text-neutral-600 group-hover:text-[var(--background)] dark:text-neutral-300 md:ml-auto md:max-w-xs md:text-right">
{o.desc}
</span>

<ArrowUpRight className="hidden h-6 w-6 shrink-0 text-neutral-400 transition-transform duration-300 group-hover:translate-x-1 group-hover:-translate-y-1 group-hover:text-[var(--background)] md:block" />
</a>
</motion.li>
))}
</ul>
</div>
);
}
32 changes: 32 additions & 0 deletions app/components/Hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Link from "next/link";
import { Suspense } from "react";
import { getTranslations } from "next-intl/server";
import ZoteroFeedLazy from "@/app/components/ZoteroFeedLazy";
import { CommunityNetwork } from "@/app/components/CommunityNetwork";
import { Contribute } from "@/app/components/Contribute";
import { ShareLink } from "@/app/components/ShareLink";
import Image from "next/image";
Expand Down Expand Up @@ -41,6 +42,31 @@ export async function Hero() {
},
];

const communitySites = [
{
key: "monitor",
callsign: "Live Ops",
title: t("community.monitor.title"),
desc: t("community.monitor.desc"),
href: "https://monitor.involutionhell.com/",
live: true,
},
{
key: "mc",
callsign: "Game Node",
title: t("community.mc.title"),
desc: t("community.mc.desc"),
href: "https://mc.involutionhell.com/",
},
{
key: "invest",
callsign: "AI Lab",
title: t("community.invest.title"),
desc: t("community.invest.desc"),
href: "https://openinvest.involutionhell.com/",
},
];

return (
<section className="relative pt-32 pb-16 newsprint-texture transition-colors duration-300">
<div className="container relative mx-auto px-6">
Expand Down Expand Up @@ -120,6 +146,12 @@ export async function Hero() {
</div>
</div>

{/* Community Network - IH 生态站点(滚动揭示 + 反色 wipe,见 CommunityNetwork) */}
<CommunityNetwork
label={t("community.label")}
outposts={communitySites}
/>

{/* Top-level directories - Grid with shared borders */}
<div className="mt-16 border-t-4 border-[var(--foreground)] transition-colors duration-300">
<div className="py-4 font-mono text-xs uppercase tracking-widest border-b border-[var(--foreground)] text-[var(--foreground)]">
Expand Down
15 changes: 15 additions & 0 deletions messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,21 @@
"title": "Community Posts",
"desc": "Articles written by community members — published instantly, no PR review needed. Topics range from dev notes to technical deep-dives."
}
},
"community": {
"label": "Community Network · Our Ecosystem",
"monitor": {
"title": "Server Status",
"desc": "Live health, load & cert monitoring for every service — guarded by Ailumao."
},
"mc": {
"title": "Minecraft Server",
"desc": "Our self-hosted MC survival server. Hop in and build together."
},
"invest": {
"title": "openInvest",
"desc": "Open-source experiment — a multi-asset AI committee for research. Not investment advice."
}
}
},
"footer": {
Expand Down
15 changes: 15 additions & 0 deletions messages/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,21 @@
"title": "群友创作",
"desc": "群友随手写的文章,不用等 PR review,发完即在。选题自由,从踩坑记录到技术思考都有。"
}
},
"community": {
"label": "社区网络 · 我们的生态",
"monitor": {
"title": "服务器状态",
"desc": "实时监控全部服务健康、负载与证书,由艾露猫看守。"
},
"mc": {
"title": "Minecraft 服务器",
"desc": "内卷地狱自建 MC 生存服,加入一起联机开荒。"
},
"invest": {
"title": "openInvest",
"desc": "开源实验项目:多资产 AI 投资委员会,4 角色辩论。仅供研究,非投资建议。"
}
}
},
"footer": {
Expand Down
Binary file added public/friends/ailumao.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading