Skip to content

Commit 08679b3

Browse files
committed
Add Pages deployment and refine interactions
1 parent 9b1df90 commit 08679b3

4 files changed

Lines changed: 197 additions & 38 deletions

File tree

.github/workflows/pages.yml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: Deploy to GitHub Pages
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: read
11+
pages: write
12+
id-token: write
13+
14+
concurrency:
15+
group: pages
16+
cancel-in-progress: false
17+
18+
jobs:
19+
build:
20+
runs-on: ubuntu-latest
21+
steps:
22+
- name: Checkout
23+
uses: actions/checkout@v4
24+
25+
- name: Setup Node
26+
uses: actions/setup-node@v4
27+
with:
28+
node-version: 22
29+
cache: npm
30+
31+
- name: Install dependencies
32+
run: npm ci
33+
34+
- name: Build
35+
run: npm run build
36+
env:
37+
GITHUB_PAGES: "true"
38+
39+
- name: Upload artifact
40+
uses: actions/upload-pages-artifact@v3
41+
with:
42+
path: dist
43+
44+
deploy:
45+
environment:
46+
name: github-pages
47+
url: ${{ steps.deployment.outputs.page_url }}
48+
runs-on: ubuntu-latest
49+
needs: build
50+
steps:
51+
- name: Deploy to GitHub Pages
52+
id: deployment
53+
uses: actions/deploy-pages@v4

src/App.tsx

Lines changed: 72 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { motion } from "motion/react";
77
import {
88
ArrowRight,
99
Github,
10-
MessageSquare,
1110
Cpu,
1211
BrainCircuit,
1312
Network,
@@ -19,7 +18,7 @@ import {
1918
Star,
2019
X
2120
} from "lucide-react";
22-
import { useState } from "react";
21+
import { useEffect, useRef, useState } from "react";
2322
import logoUrl from "./assets/logo.svg";
2423

2524
const LANGUAGES = {
@@ -200,12 +199,19 @@ export default function App() {
200199
const [view, setViewState] = useState<View>("HOME");
201200
const [activePostSlug, setActivePostSlug] = useState<string | null>(null);
202201
const [showWechatQr, setShowWechatQr] = useState(false);
202+
const [wechatQrLoaded, setWechatQrLoaded] = useState(false);
203+
const jellyBodyRef = useRef<HTMLDivElement | null>(null);
203204

204205
const setView = (nextView: View) => {
205206
setViewState(nextView);
206207
setActivePostSlug(null);
207208
};
208209

210+
const openWechatQr = () => {
211+
setWechatQrLoaded(false);
212+
setShowWechatQr(true);
213+
};
214+
209215
const t = {
210216
ZH: {
211217
name: "WalkingLabs",
@@ -319,6 +325,34 @@ export default function App() {
319325
const blogPosts = BLOG_POSTS[lang];
320326
const activePost = activePostSlug ? blogPosts.find((post) => post.slug === activePostSlug) : null;
321327

328+
useEffect(() => {
329+
const body = jellyBodyRef.current;
330+
if (!body) return;
331+
332+
const randomizeJelly = () => {
333+
const points = Array.from({ length: 8 }, () => `${Math.round(36 + Math.random() * 30)}%`);
334+
const x1 = (0.98 + Math.random() * 0.055).toFixed(3);
335+
const y1 = (0.98 + Math.random() * 0.055).toFixed(3);
336+
const x2 = (0.98 + Math.random() * 0.055).toFixed(3);
337+
const y2 = (0.98 + Math.random() * 0.055).toFixed(3);
338+
const r1 = `${(Math.random() * 1.4 - 0.7).toFixed(2)}deg`;
339+
const r2 = `${(Math.random() * 1.4 - 0.7).toFixed(2)}deg`;
340+
341+
body.style.setProperty("--jelly-r1", `${points[0]} ${points[1]} ${points[2]} ${points[3]} / ${points[4]} ${points[5]} ${points[6]} ${points[7]}`);
342+
body.style.setProperty("--jelly-r2", `${points[3]} ${points[2]} ${points[1]} ${points[0]} / ${points[7]} ${points[6]} ${points[5]} ${points[4]}`);
343+
body.style.setProperty("--jelly-sx1", x1);
344+
body.style.setProperty("--jelly-sy1", y1);
345+
body.style.setProperty("--jelly-sx2", x2);
346+
body.style.setProperty("--jelly-sy2", y2);
347+
body.style.setProperty("--jelly-rot1", r1);
348+
body.style.setProperty("--jelly-rot2", r2);
349+
};
350+
351+
randomizeJelly();
352+
body.addEventListener("animationiteration", randomizeJelly);
353+
return () => body.removeEventListener("animationiteration", randomizeJelly);
354+
}, []);
355+
322356
return (
323357
<div className="min-h-screen selection:bg-brand-blue/20">
324358
{/* Navigation */}
@@ -402,10 +436,10 @@ export default function App() {
402436
</h1>
403437

404438
<div className="flex flex-col sm:flex-row flex-wrap gap-4 sm:gap-5">
405-
<button className="btn-primary">
439+
<button className="btn-primary" onClick={() => setView("PROJECTS")}>
406440
Explore Projects <ArrowRight className="w-5 h-5" />
407441
</button>
408-
<button className="btn-secondary" onClick={() => setShowWechatQr(true)}>
442+
<button className="btn-secondary" onClick={openWechatQr}>
409443
<Smile className="w-5 h-5" /> Join Community
410444
</button>
411445
</div>
@@ -418,13 +452,13 @@ export default function App() {
418452
style={{ willChange: "transform" }}
419453
animate={{
420454
y: [0, -15, 0],
421-
rotate: [-1, 1, -1]
455+
rotate: [-0.5, 0.5, -0.5]
422456
}}
423457
transition={{ duration: 6, repeat: Infinity, ease: "easeInOut" }}
424458
>
425-
<div className="absolute inset-0 bg-gradient-to-br from-violet-600 to-indigo-400 rounded-[45%_55%_65%_35%/35%_55%_45%_65%] shadow-2xl opacity-90" />
459+
<div ref={jellyBodyRef} className="jelly-body absolute inset-0 bg-gradient-to-br from-violet-600 to-indigo-400 shadow-2xl opacity-90" />
426460

427-
<div className="absolute inset-0 flex flex-col items-center justify-start pt-32 md:pt-36">
461+
<div className="jelly-face absolute inset-0 flex flex-col items-center justify-start pt-32 md:pt-36">
428462
<div className="flex gap-12 md:gap-16">
429463
<motion.div
430464
className="w-3.5 h-7 md:w-5 md:h-12 bg-white rounded-full shadow-sm"
@@ -501,32 +535,15 @@ export default function App() {
501535
))}
502536

503537
{/* Community Bento Cell */}
504-
<div className="bento-item bg-ink text-bg-paper col-span-1 md:col-span-2 lg:col-span-3">
505-
<div className="flex flex-col md:flex-row gap-12 items-center">
506-
<div className="flex-1">
507-
<h3 className="text-3xl mb-4 font-serif italic text-brand-blue">Build with us.</h3>
508-
<p className="text-zinc-400 mb-8 max-w-md">
509-
Join our WeChat Group to discuss Agentic AI, RL, and more. Become part of a long-term, rigorous technical community.
510-
</p>
511-
<div className="flex gap-4">
512-
<button onClick={() => setShowWechatQr(true)} className="bg-white text-ink px-6 py-3 rounded-full font-medium flex items-center gap-2">
513-
<MessageSquare className="w-5 h-5" /> WeChat Group
514-
</button>
515-
<a href="https://github.com/walkinglabs" target="_blank" rel="noreferrer" className="border border-white/20 px-6 py-3 rounded-full font-medium">
516-
Join GitHub
517-
</a>
518-
</div>
519-
</div>
520-
<div className="w-48 h-48 bg-white p-4 rounded-3xl flex flex-col items-center justify-center gap-2">
521-
<div className="w-full h-full bg-zinc-100 rounded-xl flex items-center justify-center border-2 border-dashed border-zinc-300">
522-
<span className="text-zinc-400 text-[10px] uppercase font-bold text-center px-4">
523-
QR Code Placeholder
524-
</span>
525-
</div>
526-
<span className="text-[10px] text-ink/60 font-mono">SCAN TO JOIN</span>
527-
</div>
528-
</div>
529-
</div>
538+
<button
539+
onClick={openWechatQr}
540+
className="bento-item bg-ink text-bg-paper col-span-1 md:col-span-2 lg:col-span-3 text-left hover:bg-zinc-950 transition-colors"
541+
>
542+
<h3 className="text-3xl mb-4 font-serif italic text-brand-blue">Build with us.</h3>
543+
<p className="text-zinc-400 max-w-md">
544+
Join our WeChat Group to discuss Agentic AI, RL, and more. Become part of a long-term, rigorous technical community.
545+
</p>
546+
</button>
530547
</div>
531548
</div>
532549
</section>
@@ -607,11 +624,11 @@ export default function App() {
607624
style={{ willChange: "transform, opacity" }}
608625
className="flex flex-col w-fit mx-auto"
609626
>
610-
<span className="text-[18vw] lg:text-[220px] font-bold leading-[0.85] tracking-tighter block select-none text-black">
627+
<span className="text-[20vw] lg:text-[250px] font-bold leading-[0.85] tracking-tighter block select-none text-black">
611628
WALKING
612629
</span>
613-
<div className="flex justify-end -mt-[5vw] lg:-mt-16">
614-
<span className="text-[14vw] lg:text-[180px] font-bold serif-italic text-violet-600 leading-none tracking-tighter block select-none">
630+
<div className="flex justify-end -mt-[5.5vw] lg:-mt-20">
631+
<span className="text-[16vw] lg:text-[210px] font-bold serif-italic text-violet-600 leading-none tracking-tighter block select-none">
615632
LABS
616633
</span>
617634
</div>
@@ -1066,13 +1083,30 @@ export default function App() {
10661083
<p className="text-sm text-zinc-500 mb-6">
10671084
{lang === "EN" ? "Scan the QR code to join the WalkingLabs community." : "扫码加入 WalkingLabs 社区。"}
10681085
</p>
1069-
<div className="rounded-3xl border border-zinc-100 bg-zinc-50 p-4">
1086+
<div className="relative rounded-3xl border border-zinc-100 bg-zinc-50 p-4 min-h-[320px] flex items-center justify-center">
1087+
{!wechatQrLoaded && (
1088+
<div className="absolute inset-0 flex flex-col items-center justify-center gap-4 text-zinc-400">
1089+
<div className="qr-spinner" />
1090+
<span className="text-xs font-bold uppercase tracking-widest">
1091+
{lang === "EN" ? "Loading QR" : "加载二维码"}
1092+
</span>
1093+
</div>
1094+
)}
10701095
<img
10711096
src={WECHAT_QR_URL}
10721097
alt={lang === "EN" ? "WalkingLabs WeChat QR code" : "WalkingLabs 微信二维码"}
1073-
className="w-full rounded-2xl bg-white"
1098+
onLoad={() => setWechatQrLoaded(true)}
1099+
className={`w-full rounded-2xl bg-white transition-opacity duration-300 ${wechatQrLoaded ? "opacity-100" : "opacity-0"}`}
10741100
/>
10751101
</div>
1102+
<a
1103+
href={WECHAT_QR_URL}
1104+
target="_blank"
1105+
rel="noreferrer"
1106+
className="mt-4 inline-block text-xs text-zinc-400 hover:text-violet-700 transition-colors underline underline-offset-4"
1107+
>
1108+
{lang === "EN" ? "If it keeps loading, open the GitHub QR image." : "长时间加载不出,可到 GitHub 页面获取二维码。"}
1109+
</a>
10761110
</div>
10771111
</motion.div>
10781112
</div>

src/index.css

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,77 @@
3737
padding-right: clamp(1.25rem, 4vw, 4rem);
3838
}
3939

40+
.jelly-body {
41+
--jelly-r1: 52% 48% 58% 42% / 42% 48% 52% 58%;
42+
--jelly-r2: 39% 61% 50% 50% / 52% 43% 57% 48%;
43+
--jelly-sx1: 1.025;
44+
--jelly-sy1: 0.985;
45+
--jelly-sx2: 0.99;
46+
--jelly-sy2: 1.02;
47+
--jelly-rot1: 0.6deg;
48+
--jelly-rot2: -0.5deg;
49+
border-radius: 45% 55% 65% 35% / 35% 55% 45% 65%;
50+
transform-origin: 50% 58%;
51+
animation: jelly-breathe 12s ease-in-out infinite;
52+
will-change: border-radius, transform;
53+
}
54+
55+
.jelly-face {
56+
animation: jelly-face-drift 12s ease-in-out infinite;
57+
will-change: transform;
58+
}
59+
60+
.qr-spinner {
61+
width: 2.75rem;
62+
height: 2.75rem;
63+
border: 3px solid #e4e4e7;
64+
border-top-color: #6d28d9;
65+
border-radius: 999px;
66+
animation: qr-spin 0.9s linear infinite;
67+
}
68+
69+
@keyframes qr-spin {
70+
to {
71+
transform: rotate(360deg);
72+
}
73+
}
74+
75+
@keyframes jelly-breathe {
76+
0%,
77+
100% {
78+
border-radius: 45% 55% 65% 35% / 35% 55% 45% 65%;
79+
transform: scale(1) rotate(0deg);
80+
}
81+
22% {
82+
border-radius: var(--jelly-r1);
83+
transform: scale(var(--jelly-sx1), var(--jelly-sy1)) rotate(var(--jelly-rot1));
84+
}
85+
48% {
86+
border-radius: var(--jelly-r2);
87+
transform: scale(var(--jelly-sx2), var(--jelly-sy2)) rotate(var(--jelly-rot2));
88+
}
89+
73% {
90+
border-radius: var(--jelly-r1);
91+
transform: scale(var(--jelly-sy1), var(--jelly-sx1)) rotate(calc(var(--jelly-rot1) * -0.6));
92+
}
93+
}
94+
95+
@keyframes jelly-face-drift {
96+
0%,
97+
100% {
98+
transform: translate3d(0, 0, 0) scale(1);
99+
}
100+
22% {
101+
transform: translate3d(6px, -3px, 0) scale(0.985, 1.02);
102+
}
103+
48% {
104+
transform: translate3d(-5px, 5px, 0) scale(1.01, 0.99);
105+
}
106+
73% {
107+
transform: translate3d(4px, 3px, 0) scale(0.995, 1.01);
108+
}
109+
}
110+
40111
.bento-grid {
41112
display: grid;
42113
@apply grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-[1px] bg-zinc-200 border-t border-zinc-200;

vite.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {defineConfig, loadEnv} from 'vite';
66
export default defineConfig(({mode}) => {
77
const env = loadEnv(mode, '.', '');
88
return {
9+
base: process.env.GITHUB_PAGES === 'true' ? '/homepage/' : '/',
910
plugins: [react(), tailwindcss()],
1011
define: {
1112
'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY),

0 commit comments

Comments
 (0)