Skip to content

Commit d6d4758

Browse files
Mile-Awayclaude
andcommitted
feat(landing): redesign landing page with i18n support
- Hero: full-screen video bg, constellation canvas, ScienceOL branding - ProductShowcase: modular hardware grid with placeholder cards - Ecosystem: OpenSDL (open source) + Xyzen (AI-driven) cards - Footer: minimal with OSS logo and legal info - Navbar: replace Protium logo with ScienceOL OSS logos - Favicon: use OSS BLogo with dark/light mode support - i18n: add landing namespace (en/zh) for all landing components - i18n: enable nonExplicitSupportedLngs for zh-CN matching Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9931836 commit d6d4758

12 files changed

Lines changed: 666 additions & 523 deletions

File tree

web/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
<link
66
rel="icon"
77
type="image/svg+xml"
8-
href="https://sciol-public.oss-cn-shanghai.aliyuncs.com/BLogo-light.svg"
8+
href="https://storage.sciol.ac.cn/library/BLogo-light.svg"
99
/>
1010
<link
1111
rel="icon"
1212
type="image/svg+xml"
13-
href="https://sciol-public.oss-cn-shanghai.aliyuncs.com/BLogo-dark.svg"
13+
href="https://storage.sciol.ac.cn/library/BLogo-dark.svg"
1414
media="(prefers-color-scheme: dark)"
1515
/>
1616
<link rel="stylesheet" href="./index.css" />

web/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"@radix-ui/react-slot": "^1.2.4",
2424
"@react-three/drei": "^10.7.6",
2525
"@react-three/fiber": "^9.4.0",
26-
"@sciol/xyzen": "^0.4.3",
26+
"@sciol/xyzen": "^0.4.4",
2727
"@tabler/icons-react": "^3.35.0",
2828
"@tailwindcss/postcss": "^4.1.14",
2929
"@tailwindcss/vite": "^4.1.14",
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import { motion } from 'framer-motion';
2+
import { useTranslation } from 'react-i18next';
3+
4+
export default function Ecosystem() {
5+
const { t } = useTranslation();
6+
7+
return (
8+
<section className="relative bg-black py-32 overflow-hidden border-t border-white/[0.04]">
9+
<div className="mx-auto max-w-screen-2xl px-6 lg:px-8">
10+
<motion.div
11+
initial={{ opacity: 0, y: 30 }}
12+
whileInView={{ opacity: 1, y: 0 }}
13+
viewport={{ once: true }}
14+
transition={{ duration: 0.7 }}
15+
>
16+
<p className="font-mono text-xs uppercase tracking-[0.2em] text-white/30">
17+
{t('landing.ecosystem.label')}
18+
</p>
19+
<h2 className="mt-4 text-4xl sm:text-5xl font-bold tracking-tight text-white">
20+
{t('landing.ecosystem.title')}
21+
</h2>
22+
</motion.div>
23+
24+
<div className="mt-20 grid grid-cols-1 gap-6 lg:grid-cols-2">
25+
{/* OpenSDL */}
26+
<motion.a
27+
href="https://github.com/ScienceOL/OpenSDL"
28+
target="_blank"
29+
initial={{ opacity: 0, y: 30 }}
30+
whileInView={{ opacity: 1, y: 0 }}
31+
viewport={{ once: true }}
32+
transition={{ duration: 0.6 }}
33+
className="group relative rounded-2xl bg-white/[0.02] p-8 sm:p-10 ring-1 ring-white/[0.06] transition-all hover:ring-white/[0.12]"
34+
>
35+
<div className="inline-flex items-center gap-2 rounded-full bg-white/[0.05] px-3 py-1 ring-1 ring-white/[0.08]">
36+
<div className="h-1.5 w-1.5 rounded-full bg-emerald-400" />
37+
<span className="font-mono text-[11px] uppercase tracking-wider text-white/50">
38+
{t('landing.ecosystem.opensdl_tag')}
39+
</span>
40+
</div>
41+
42+
<h3 className="mt-6 text-2xl font-bold text-white">OpenSDL</h3>
43+
<p className="mt-3 text-sm leading-relaxed text-white/35 max-w-md">
44+
{t('landing.ecosystem.opensdl_description')}
45+
</p>
46+
47+
<div className="mt-8 flex items-center gap-2 font-mono text-xs text-white/30 group-hover:text-white/50 transition-colors">
48+
<span>github.com/ScienceOL/OpenSDL</span>
49+
<span className="transition-transform group-hover:translate-x-0.5">&rarr;</span>
50+
</div>
51+
</motion.a>
52+
53+
{/* Xyzen */}
54+
<motion.a
55+
href="https://xyzen.cc"
56+
target="_blank"
57+
initial={{ opacity: 0, y: 30 }}
58+
whileInView={{ opacity: 1, y: 0 }}
59+
viewport={{ once: true }}
60+
transition={{ duration: 0.6, delay: 0.1 }}
61+
className="group relative rounded-2xl bg-white/[0.02] p-8 sm:p-10 ring-1 ring-white/[0.06] transition-all hover:ring-white/[0.12]"
62+
>
63+
<div className="inline-flex items-center gap-2 rounded-full bg-white/[0.05] px-3 py-1 ring-1 ring-white/[0.08]">
64+
<div className="h-1.5 w-1.5 rounded-full bg-blue-400" />
65+
<span className="font-mono text-[11px] uppercase tracking-wider text-white/50">
66+
{t('landing.ecosystem.xyzen_tag')}
67+
</span>
68+
</div>
69+
70+
<h3 className="mt-6 text-2xl font-bold text-white">Xyzen</h3>
71+
<p className="mt-3 text-sm leading-relaxed text-white/35 max-w-md">
72+
{t('landing.ecosystem.xyzen_description')}
73+
</p>
74+
75+
<div className="mt-8 flex items-center gap-2 font-mono text-xs text-white/30 group-hover:text-white/50 transition-colors">
76+
<span>xyzen.cc</span>
77+
<span className="transition-transform group-hover:translate-x-0.5">&rarr;</span>
78+
</div>
79+
</motion.a>
80+
</div>
81+
82+
<motion.div
83+
initial={{ opacity: 0 }}
84+
whileInView={{ opacity: 1 }}
85+
viewport={{ once: true }}
86+
transition={{ duration: 1, delay: 0.3 }}
87+
className="mt-16 flex items-center justify-center gap-4"
88+
>
89+
<div className="h-px flex-1 bg-gradient-to-r from-transparent to-white/[0.06]" />
90+
<p className="font-mono text-[11px] text-white/20 uppercase tracking-[0.15em] whitespace-nowrap px-4">
91+
{t('landing.ecosystem.flow')}
92+
</p>
93+
<div className="h-px flex-1 bg-gradient-to-l from-transparent to-white/[0.06]" />
94+
</motion.div>
95+
</div>
96+
</section>
97+
);
98+
}

web/src/app/landscape/Footer.tsx

Lines changed: 33 additions & 218 deletions
Original file line numberDiff line numberDiff line change
@@ -1,228 +1,43 @@
1-
import { BiliBiliIcon, IoLogoWechat } from '@/assets/SocialIcons';
2-
import { EnvelopeIcon } from '@heroicons/react/24/solid';
1+
import { useTranslation } from 'react-i18next';
32

4-
import { RiZhihuLine } from 'react-icons/ri';
5-
6-
import Logo from '@/assets/Logo';
7-
import type React from 'react';
8-
9-
const navigation = {
10-
about: [
11-
{ name: 'About', href: '/about' },
12-
{ name: 'Manifesto', href: '/manifesto' },
13-
{ name: 'Join us', href: '/about#joinus' },
14-
],
15-
project: [
16-
// { name: 'Pricing', href: '#' },
17-
{ name: 'Protium', href: '#' },
18-
{ name: 'Xyzen', href: '#' },
19-
{ name: 'Anti', href: '#' },
20-
{ name: 'LabOS', href: '#' },
21-
],
22-
community: [
23-
{ name: 'Articles', href: '/articles' },
24-
{ name: 'Spaces', href: '/spaces' },
25-
],
26-
legal: [
27-
{ name: 'Claim', href: '#' },
28-
{ name: 'Privacy', href: '#' },
29-
{ name: 'Terms', href: '#' },
30-
],
31-
social: [
32-
{
33-
name: 'Email',
34-
href: 'mailto:Protium@Protium.com',
35-
icon: (props: React.SVGProps<SVGSVGElement>) => (
36-
<EnvelopeIcon className="h-6 w-6" {...props} />
37-
),
38-
},
39-
{
40-
name: 'GitHub',
41-
href: 'https://github.com/Protium',
42-
icon: (props: React.SVGProps<SVGSVGElement>) => (
43-
<svg fill="currentColor" viewBox="0 0 24 24" {...props}>
44-
<path
45-
fillRule="evenodd"
46-
d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
47-
clipRule="evenodd"
48-
/>
49-
</svg>
50-
),
51-
},
52-
{
53-
name: 'Twitter',
54-
href: 'https://twitter.com/Protium',
55-
icon: (props: React.SVGProps<SVGSVGElement>) => (
56-
<svg fill="currentColor" viewBox="0 0 24 24" {...props}>
57-
<path d="M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0022 5.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.072 4.072 0 012.8 9.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 012 18.407a11.616 11.616 0 006.29 1.84" />
58-
</svg>
59-
),
60-
},
61-
{
62-
name: 'WeChat',
63-
href: 'https://open.weixin.qq.com/qr/code?username=deepmd',
64-
icon: (props: React.SVGProps<SVGSVGElement>) => (
65-
<IoLogoWechat className="h-6 w-6" {...props} />
66-
),
67-
},
68-
69-
{
70-
name: 'Zhihu',
71-
href: 'https://www.zhihu.com/org/shen-du-shi-neng-deep-potential',
72-
icon: (props: React.SVGProps<SVGSVGElement>) => (
73-
<RiZhihuLine className="h-6 w-6" {...props} />
74-
),
75-
},
76-
{
77-
name: 'Bilibili',
78-
href: 'https://space.bilibili.com/626179751/',
79-
icon: (props: React.SVGProps<SVGSVGElement>) => (
80-
<BiliBiliIcon className="h-6 w-6" {...props} />
81-
),
82-
},
83-
],
84-
};
3+
const links = [
4+
{ nameKey: null, name: 'OpenSDL', href: 'https://github.com/ScienceOL/OpenSDL' },
5+
{ nameKey: null, name: 'Xyzen', href: 'https://xyzen.cc' },
6+
{ nameKey: null, name: 'GitHub', href: 'https://github.com/ScienceOL' },
7+
{ nameKey: 'landing.footer.about', name: 'About', href: '/about' },
8+
];
859

8610
export default function Footer() {
11+
const { t } = useTranslation();
12+
8713
return (
88-
<footer
89-
className="bg-white dark:bg-neutral-900"
90-
aria-labelledby="footer-heading"
91-
>
92-
<h2 id="footer-heading" className="sr-only">
93-
Footer
94-
</h2>
95-
<div className="mx-auto max-w-8xl px-6 pb-8 pt-16 sm:pt-24 lg:px-8 lg:pt-32 2xl:max-w-screen-2xl">
96-
<div className="xl:grid xl:grid-cols-3 xl:gap-8">
97-
<Logo className="h-8 w-8 fill-indigo-800 dark:fill-white" />
98-
<div className="mt-16 grid grid-cols-2 gap-8 xl:col-span-2 xl:mt-0">
99-
<div className="md:grid md:grid-cols-2 md:gap-8">
100-
<div>
101-
<h3 className="text-sm font-semibold leading-6 text-neutral-900 dark:text-neutral-50">
102-
About
103-
</h3>
104-
<ul role="list" className="mt-6 space-y-4">
105-
{navigation.about.map((item) => (
106-
<li key={item.name}>
107-
<a
108-
href={item.href}
109-
className="text-sm leading-6 text-neutral-600 hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-neutral-50"
110-
>
111-
{item.name}
112-
</a>
113-
</li>
114-
))}
115-
</ul>
116-
</div>
117-
<div className="mt-10 md:mt-0">
118-
<h3 className="text-sm font-semibold leading-6 text-neutral-900 dark:text-neutral-50">
119-
Project
120-
</h3>
121-
<ul role="list" className="mt-6 space-y-4">
122-
{navigation.project.map((item) => (
123-
<li key={item.name}>
124-
<a
125-
href={item.href}
126-
className="text-sm leading-6 text-neutral-600 hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-neutral-50"
127-
>
128-
{item.name}
129-
</a>
130-
</li>
131-
))}
132-
</ul>
133-
</div>
134-
</div>
135-
<div className="md:grid md:grid-cols-2 md:gap-8">
136-
<div>
137-
<h3 className="text-sm font-semibold leading-6 text-neutral-900 dark:text-neutral-50">
138-
Community
139-
</h3>
140-
<ul role="list" className="mt-6 space-y-4">
141-
{navigation.community.map((item) => (
142-
<li key={item.name}>
143-
<a
144-
href={item.href}
145-
className="text-sm leading-6 text-neutral-600 hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-neutral-50"
146-
>
147-
{item.name}
148-
</a>
149-
</li>
150-
))}
151-
</ul>
152-
</div>
153-
<div className="mt-10 md:mt-0">
154-
<h3 className="text-sm font-semibold leading-6 text-neutral-900 dark:text-neutral-50">
155-
Legal
156-
</h3>
157-
<ul role="list" className="mt-6 space-y-4">
158-
{navigation.legal.map((item) => (
159-
<li key={item.name}>
160-
<a
161-
href={item.href}
162-
className="text-sm leading-6 text-neutral-600 hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-neutral-50"
163-
>
164-
{item.name}
165-
</a>
166-
</li>
167-
))}
168-
</ul>
169-
</div>
170-
</div>
171-
</div>
172-
</div>
173-
<div className="mt-16 border-t border-neutral-900/10 pt-8 dark:border-neutral-50/10 sm:mt-20 lg:mt-24 lg:flex lg:items-center lg:justify-between">
174-
<div>
175-
<h3 className="text-sm font-semibold leading-6 text-neutral-900 dark:text-neutral-50">
176-
Subscribe to our Newsletter
177-
</h3>
178-
<p className="mt-2 text-sm leading-6 text-neutral-600 dark:text-neutral-400">
179-
The latest news, articles, and resources, sent to your inbox
180-
weekly.
181-
</p>
182-
</div>
183-
<form className="mt-6 sm:flex sm:max-w-md lg:mt-0">
184-
<label htmlFor="email-address" className="sr-only">
185-
Email address
186-
</label>
187-
<input
188-
type="email"
189-
name="email-address"
190-
id="email-address"
191-
autoComplete="email"
192-
required
193-
className="w-full min-w-0 appearance-none rounded-md border-0 bg-white px-3 py-1.5 text-base text-neutral-900 shadow-sm ring-1 ring-inset ring-neutral-300 placeholder:text-neutral-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 dark:bg-neutral-900 dark:text-white dark:ring-neutral-600 sm:w-56 sm:text-sm sm:leading-6"
194-
placeholder="Enter your email"
14+
<footer className="bg-black border-t border-white/[0.06]">
15+
<div className="mx-auto max-w-screen-2xl px-6 py-10 lg:px-8">
16+
<div className="flex flex-col items-center gap-6 sm:flex-row sm:justify-between">
17+
<div className="flex items-center gap-6">
18+
<img
19+
src="https://storage.sciol.ac.cn/library/BLogo-dark.svg"
20+
alt="ScienceOL"
21+
className="h-5 w-5 opacity-40"
19522
/>
196-
<div className="mt-4 sm:ml-4 sm:mt-0 sm:flex-shrink-0">
197-
<button
198-
type="submit"
199-
className="flex w-full items-center justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold
200-
text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
201-
>
202-
Subscribe
203-
</button>
23+
<div className="flex flex-wrap items-center gap-4">
24+
{links.map((link) => (
25+
<a
26+
key={link.href}
27+
href={link.href}
28+
target={link.href.startsWith('http') ? '_blank' : undefined}
29+
className="text-xs text-white/30 transition-colors hover:text-white/60 font-mono"
30+
>
31+
{link.nameKey ? t(link.nameKey) : link.name}
32+
</a>
33+
))}
20434
</div>
205-
</form>
206-
</div>
207-
<div className="mt-8 border-t border-neutral-900/10 pt-8 dark:border-neutral-50/10 md:flex md:items-center md:justify-between">
208-
<div className="flex space-x-6 md:order-2">
209-
{navigation.social.map((item) => (
210-
<a
211-
key={item.name}
212-
target="_blank"
213-
href={item.href}
214-
className="fill-neutral-400 text-neutral-400 hover:fill-neutral-500 hover:text-neutral-500
215-
dark:hover:fill-neutral-300 dark:hover:text-neutral-300"
216-
>
217-
<span className="sr-only">{item.name}</span>
218-
<item.icon className="h-6 w-6" aria-hidden="true" />
219-
</a>
220-
))}
22135
</div>
222-
<p className="mt-8 text-xs leading-5 text-neutral-500 md:order-1 md:mt-0">
223-
&copy; {new Date().getFullYear()} Protium. All rights reserved.
224-
<a href="https://beian.miit.gov.cn" className="ml-2 text-[11px]">
225-
浙ICP备2022009106号-3
36+
37+
<p className="text-[11px] text-white/20 font-mono text-center sm:text-right">
38+
&copy; {new Date().getFullYear()} 奇迹物语(上海)智能科技有限公司
39+
<a href="https://beian.miit.gov.cn" className="ml-2 hover:text-white/40">
40+
沪ICP备2026012508号
22641
</a>
22742
</p>
22843
</div>

0 commit comments

Comments
 (0)