Skip to content

Commit ffe001b

Browse files
authored
[랜딩] 유레카키트 한국어 랜딩화면 추가 (#51)
* chore: update rollup-plugin-visualizer * feat: add landing apps * feat: setup tailwind * feat: publish landing page * feat: add radien gradient effect * feat: add go eureka kit gradient spin animation * feat: increase animation speed * feat: add image * feat: add images to landing page
1 parent e09a648 commit ffe001b

23 files changed

Lines changed: 777 additions & 312 deletions

apps/landing/eslint.config.cjs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const nx = require('@nx/eslint-plugin');
2+
const baseConfig = require('../../eslint.config.js');
3+
4+
module.exports = [
5+
...baseConfig,
6+
...nx.configs['flat/react'],
7+
{
8+
files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
9+
// Override or add rules here
10+
rules: {},
11+
},
12+
];

apps/landing/index.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<title>Landing</title>
6+
<base href="/" />
7+
8+
<meta name="viewport" content="width=device-width, initial-scale=1" />
9+
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
10+
<link rel="stylesheet" href="/src/styles.css" />
11+
</head>
12+
<body>
13+
<div id="root"></div>
14+
<script type="module" src="/src/main.tsx"></script>
15+
</body>
16+
</html>

apps/landing/postcss.config.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const { join } = require('path');
2+
3+
// Note: If you use library-specific PostCSS/Tailwind configuration then you should remove the `postcssConfig` build
4+
// option from your application's configuration (i.e. project.json).
5+
//
6+
// See: https://nx.dev/guides/using-tailwind-css-in-react#step-4:-applying-configuration-to-libraries
7+
8+
module.exports = {
9+
plugins: {
10+
tailwindcss: {
11+
config: join(__dirname, 'tailwind.config.js'),
12+
},
13+
autoprefixer: {},
14+
},
15+
};

apps/landing/project.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"name": "landing",
3+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
4+
"sourceRoot": "apps/landing/src",
5+
"projectType": "application",
6+
"tags": [],
7+
"// targets": "to see all targets run: nx show project landing --web",
8+
"targets": {}
9+
}

apps/landing/public/favicon.ico

14.7 KB
Binary file not shown.

apps/landing/src/app/app.tsx

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
import { useEffect, useRef } from 'react';
2+
3+
import { ChevronRight } from 'lucide-react';
4+
5+
import { Images } from '@lemon/assets';
6+
import { Button } from '@lemon/ui-kit/components/ui/button';
7+
import { cn } from '@lemon/ui-kit/lib/utils';
8+
9+
import { RadialGradient } from './components';
10+
11+
export function App() {
12+
const ref = useRef<HTMLDivElement>(null);
13+
14+
useEffect(() => {
15+
let angle = 0;
16+
let frameId: number;
17+
18+
const animate = () => {
19+
angle = (angle + 1) % 360;
20+
if (ref.current) {
21+
ref.current.style.setProperty('--angle', `${angle}deg`);
22+
}
23+
frameId = requestAnimationFrame(animate);
24+
};
25+
26+
animate();
27+
return () => cancelAnimationFrame(frameId);
28+
}, []);
29+
30+
return (
31+
<div className="text-background flex flex-col items-center bg-[#0F0F10]">
32+
<div className="relative flex h-[720px] w-full flex-col items-center justify-center gap-10 overflow-x-hidden bg-[#1B1B1B]/50">
33+
<div className="absolute top-4 flex h-[60px] w-full max-w-[1180px] items-center rounded-lg bg-[#1b1b1b] px-4">
34+
<img src={Images.eurekaCodesLogo} className="h-6" />
35+
<button className="ml-auto h-6">
36+
<img src={Images.globe} />
37+
</button>
38+
</div>
39+
<p className="flex flex-col text-center text-[52px] leading-tight">
40+
<span>
41+
<strong className="text-[86px]">EurekaKit</strong> 는 앱과 백엔드 코드를 제공해
42+
</span>
43+
<span>MVP 개발을 빠르게 도와줍니다.</span>
44+
</p>
45+
<p className="flex flex-col text-center text-[24px]">
46+
<span>React Native 앱으로 최적화 제품을 빠르게 구축할 수 있도록 지원해주며</span>
47+
<span>개발자가 아닌 사람도 맞춤형 서비스를 쉽게 구현할 수 있습니다.</span>
48+
</p>
49+
<RadialGradient
50+
radius={300}
51+
colorStops={[
52+
{ position: '0%', color: 'rgba(19, 46, 180, 0.3)' },
53+
{ position: '30%', color: 'rgba(19, 46, 180, 0.2)' },
54+
{ position: '60%', color: 'rgba(19, 46, 180, 0.1)' },
55+
{ position: '90%', color: 'rgba(19, 46, 180, 0)' },
56+
]}
57+
className="absolute -left-10 -top-32 opacity-50"
58+
/>
59+
<RadialGradient
60+
radius={300}
61+
colorStops={[
62+
{ position: '0%', color: 'rgba(167, 65, 255, 0.5)' },
63+
{ position: '30%', color: 'rgba(143, 25, 246, 0.2)' },
64+
{ position: '60%', color: 'rgba(143, 25, 246, 0.1)' },
65+
{ position: '90%', color: 'rgba(143, 25, 246, 0)' },
66+
]}
67+
className="absolute -top-10 opacity-20"
68+
/>
69+
<RadialGradient
70+
radius={300}
71+
colorStops={[
72+
{ position: '1%', color: 'rgba(255, 200, 19, 0.3)' },
73+
{ position: '51%', color: 'rgba(255, 200, 19, 0.2)' },
74+
{ position: '60%', color: 'rgba(255, 200, 19, 0.1)' },
75+
{ position: '90%', color: 'rgba(255, 200, 19, 0)' },
76+
]}
77+
className="absolute -right-32 -top-44 opacity-20"
78+
/>
79+
</div>
80+
<div className="mt-24 flex max-w-[1180px] flex-col gap-12">
81+
<p className="flex flex-col text-[44px] leading-tight">
82+
<span>EurekaKit를 이용하려면</span>
83+
<span>
84+
<strong className="text-[58px]">EurekaCodes</strong>를 먼저 사용해 주세요
85+
</span>
86+
</p>
87+
<div className="grid grid-cols-2 grid-rows-2 gap-4">
88+
<p className="relative col-span-2 flex h-[682px] flex-col gap-8 overflow-hidden rounded-3xl bg-white/[0.03] px-24 pt-24">
89+
<span className="text-4xl">기본 워크스페이스와 프로젝트를 제공해줘요</span>
90+
<span>기본으로 제공되는 워크스페이스와 프로젝트로 유레카코즈를 이용해볼 수 있어요</span>
91+
<img src={Images.landingBannder1} className="absolute bottom-0 w-4/5" />
92+
<RadialGradient
93+
radius={300}
94+
colorStops={[
95+
{ position: '0%', color: 'rgba(19, 46, 180, 0.3)' },
96+
{ position: '30%', color: 'rgba(19, 46, 180, 0.2)' },
97+
{ position: '60%', color: 'rgba(19, 46, 180, 0.1)' },
98+
{ position: '90%', color: 'rgba(19, 46, 180, 0)' },
99+
]}
100+
className="absolute -left-40 -top-32 opacity-50"
101+
/>
102+
<RadialGradient
103+
radius={300}
104+
colorStops={[
105+
{ position: '0%', color: 'rgba(167, 65, 255, 0.5)' },
106+
{ position: '30%', color: 'rgba(143, 25, 246, 0.2)' },
107+
{ position: '60%', color: 'rgba(143, 25, 246, 0.1)' },
108+
{ position: '90%', color: 'rgba(143, 25, 246, 0)' },
109+
]}
110+
className="absolute -bottom-48 -right-44 opacity-20"
111+
/>
112+
<RadialGradient
113+
radius={300}
114+
colorStops={[
115+
{ position: '1%', color: 'rgba(255, 200, 19, 0.3)' },
116+
{ position: '51%', color: 'rgba(255, 200, 19, 0.2)' },
117+
{ position: '60%', color: 'rgba(255, 200, 19, 0.1)' },
118+
{ position: '90%', color: 'rgba(255, 200, 19, 0)' },
119+
]}
120+
className="absolute -right-40 -top-48 opacity-10"
121+
/>
122+
</p>
123+
<p className="relative flex h-[682px] flex-col gap-8 overflow-hidden rounded-3xl bg-white/[0.03] px-16 pt-16">
124+
<span className="text-4xl">
125+
카탈로그에서 EurekaKit
126+
<br />
127+
서비스를 신청해보세요
128+
</span>
129+
<span>
130+
다양한 서비스 중 나에게 필요한
131+
<br />
132+
서비스를 찾아 신청할 수 있어요
133+
</span>
134+
<img src={Images.landingBannder2} className="absolute bottom-0 right-0 w-10/12" />
135+
<RadialGradient
136+
radius={240}
137+
colorStops={[
138+
{ position: '0%', color: 'rgba(167, 65, 255, 0.5)' },
139+
{ position: '30%', color: 'rgba(143, 25, 246, 0.2)' },
140+
{ position: '60%', color: 'rgba(143, 25, 246, 0.1)' },
141+
{ position: '90%', color: 'rgba(143, 25, 246, 0)' },
142+
]}
143+
className="absolute -left-48 -top-48 opacity-20"
144+
/>
145+
<RadialGradient
146+
radius={240}
147+
colorStops={[
148+
{ position: '1%', color: 'rgba(255, 200, 19, 0.3)' },
149+
{ position: '51%', color: 'rgba(255, 200, 19, 0.2)' },
150+
{ position: '60%', color: 'rgba(255, 200, 19, 0.1)' },
151+
{ position: '90%', color: 'rgba(255, 200, 19, 0)' },
152+
]}
153+
className="absolute -bottom-48 -right-40 opacity-10"
154+
/>
155+
</p>
156+
<p className="relative flex h-[682px] flex-col gap-8 overflow-hidden break-words rounded-3xl bg-white/[0.03] px-16 pt-16">
157+
<span className="text-4xl">
158+
EurekaKit 서비스를
159+
<br />
160+
쉽게 사용해 보세요
161+
</span>
162+
<span>
163+
React Native 앱으로 신청 후 더욱 빠르게
164+
<br />
165+
제품을 구축하고 맞춤형으로 사용할 수 있습니다.
166+
</span>
167+
<img src={Images.landingBannder3} className="absolute bottom-0 right-0 w-10/12" />
168+
<RadialGradient
169+
radius={240}
170+
colorStops={[
171+
{ position: '1%', color: 'rgba(255, 200, 19, 0.3)' },
172+
{ position: '51%', color: 'rgba(255, 200, 19, 0.2)' },
173+
{ position: '60%', color: 'rgba(255, 200, 19, 0.1)' },
174+
{ position: '90%', color: 'rgba(255, 200, 19, 0)' },
175+
]}
176+
className="absolute -right-40 -top-48 opacity-10"
177+
/>
178+
<RadialGradient
179+
radius={240}
180+
colorStops={[
181+
{ position: '0%', color: 'rgba(255, 255, 255, 0.5)' },
182+
{ position: '30%', color: 'rgba(255, 255, 255, 0.1)' },
183+
{ position: '50%', color: 'rgba(255, 255, 255, 0.05)' },
184+
{ position: '90%', color: 'rgba(255, 255, 255, 0)' },
185+
]}
186+
className="absolute -left-96 bottom-0 opacity-20"
187+
/>
188+
</p>
189+
</div>
190+
<div className="flex h-[426px] items-end justify-center">
191+
<div
192+
ref={ref}
193+
className={cn(
194+
'relative flex w-[954px] items-center rounded-full p-[2px]',
195+
'rotating-gradient',
196+
'after:absolute after:h-full after:w-full after:rounded-full',
197+
'after:z-0 after:bg-gradient-to-br after:from-[#FFE015]/40 after:from-20% after:via-[#FF8432]/40 after:via-40% after:to-[#B313E9]/40 after:to-80% after:opacity-20 after:blur-xl'
198+
)}
199+
>
200+
<div className="z-10 flex w-[954px] items-center rounded-full bg-[#161617] py-5 pl-10 pr-5">
201+
<span className="text-[30px]">EurekaKit를 신청하고 사용해 보세요</span>
202+
<Button className="ml-auto rounded-full bg-white/[0.07] py-8 pl-8 pr-5 text-[24px] hover:bg-white/10">
203+
<span>Kit 신청하러 가기</span>
204+
<ChevronRight className="!h-auto !w-auto" size={24} />
205+
</Button>
206+
</div>
207+
</div>
208+
</div>
209+
<div className="text-muted-foreground flex h-[638px] flex-col items-center justify-center gap-8">
210+
<div className="h-8">
211+
<img src={Images.eurekaCodesLogo} className="h-full" />
212+
</div>
213+
<div className="flex flex-col items-center gap-2">
214+
<span>© 2025 LemonCloud, Inc. All rights reserved.</span>
215+
<span>Privacy & Terms</span>
216+
</div>
217+
</div>
218+
</div>
219+
</div>
220+
);
221+
}
222+
223+
export default App;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './radial-gradient';
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { cn } from '@lemon/ui-kit/lib/utils';
2+
3+
import type { ClassNameValue } from 'tailwind-merge';
4+
5+
type ColorStop = {
6+
position: string;
7+
color: string;
8+
};
9+
10+
type RadialGradientProps = {
11+
radius: number;
12+
colorStops: ColorStop[];
13+
style?: React.CSSProperties;
14+
className?: ClassNameValue;
15+
};
16+
17+
export const RadialGradient: React.FC<RadialGradientProps> = ({ radius, colorStops, style, className }) => {
18+
const gradientStops = colorStops.map(({ position, color }) => `${color} ${position}`).join(', ');
19+
20+
const gradient = `radial-gradient(circle, ${gradientStops})`;
21+
22+
const gradientStyle: React.CSSProperties = {
23+
width: radius * 2,
24+
height: radius * 2,
25+
borderRadius: '50%',
26+
background: gradient,
27+
pointerEvents: 'none',
28+
...style,
29+
};
30+
31+
return <div style={gradientStyle} className={cn(className)} />;
32+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './RadialGradient';

apps/landing/src/main.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { StrictMode } from 'react';
2+
import { BrowserRouter } from 'react-router-dom';
3+
4+
import * as ReactDOM from 'react-dom/client';
5+
6+
import App from './app/app';
7+
8+
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
9+
10+
root.render(
11+
<StrictMode>
12+
<BrowserRouter>
13+
<App />
14+
</BrowserRouter>
15+
</StrictMode>
16+
);

0 commit comments

Comments
 (0)