Skip to content

Commit 56d512a

Browse files
authored
Merge pull request #199 from yyuneu/landing-redesign
landing: 랜딩 페이지 리디자인
2 parents 48ed9a4 + a6a988e commit 56d512a

8 files changed

Lines changed: 1370 additions & 372 deletions

File tree

‎apps/landing/devup.json‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,21 @@
492492
},
493493
null,
494494
null
495-
]
495+
],
496+
"code": {
497+
"fontFamily": "D2Coding",
498+
"fontWeight": 400,
499+
"fontSize": "13px",
500+
"lineHeight": 1.5,
501+
"letterSpacing": "0em"
502+
},
503+
"eyebrow": {
504+
"fontFamily": "D2Coding",
505+
"fontWeight": 400,
506+
"fontSize": "11px",
507+
"lineHeight": 1.4,
508+
"letterSpacing": "0.14em"
509+
}
496510
}
497511
}
498512
}
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
import { Box, Text } from '@devup-ui/react'
2+
3+
import { CodeWindow, HighlightedCode } from './code-window'
4+
5+
export interface CodeExample {
6+
key: string
7+
label: string
8+
file: string
9+
html: string
10+
}
11+
12+
export type CodeExampleQuad = [CodeExample, CodeExample, CodeExample, CodeExample]
13+
14+
// devup-ui extracts `selectors` strings at build time, so each of the 4
15+
// fixed tabs is written out literally rather than generated by a .map()
16+
// over a runtime key — a template-literal selector key can't be statically
17+
// extracted into CSS.
18+
//
19+
// Each target element (label / title / panel) declares its own "when am I
20+
// shown" condition anchored on the checkbox's id (`#code-tab-N:checked ~ *
21+
// &`), rather than the checkbox declaring rules for elements elsewhere in
22+
// the tree. The checkbox's own `:checked` state isn't observable from the
23+
// checkbox's position in isolation, so ownership of the visibility rule
24+
// belongs on the element it affects.
25+
export function CodeTabs({ examples: [a, b, c, d] }: { examples: CodeExampleQuad }) {
26+
return (
27+
<Box>
28+
<Box
29+
as="input"
30+
boxSize="1px"
31+
defaultChecked
32+
id="code-tab-0"
33+
name="code-tab"
34+
opacity="0"
35+
overflow="hidden"
36+
position="absolute"
37+
type="radio"
38+
/>
39+
<Box
40+
as="input"
41+
boxSize="1px"
42+
id="code-tab-1"
43+
name="code-tab"
44+
opacity="0"
45+
overflow="hidden"
46+
position="absolute"
47+
type="radio"
48+
/>
49+
<Box
50+
as="input"
51+
boxSize="1px"
52+
id="code-tab-2"
53+
name="code-tab"
54+
opacity="0"
55+
overflow="hidden"
56+
position="absolute"
57+
type="radio"
58+
/>
59+
<Box
60+
as="input"
61+
boxSize="1px"
62+
id="code-tab-3"
63+
name="code-tab"
64+
opacity="0"
65+
overflow="hidden"
66+
position="absolute"
67+
type="radio"
68+
/>
69+
<CodeWindow
70+
tabs={
71+
<>
72+
<Box
73+
as="label"
74+
border="1px solid transparent"
75+
borderRadius="4px"
76+
color="$caption"
77+
cursor="pointer"
78+
htmlFor="code-tab-0"
79+
px="12px"
80+
py="6px"
81+
selectors={{
82+
'#code-tab-0:checked ~ * &': {
83+
bg: '$containerBackground',
84+
border: '1px solid $border',
85+
color: '$title',
86+
},
87+
'#code-tab-0:focus-visible ~ * &': {
88+
boxShadow: '0 0 0 2px $vespertidePrimary',
89+
},
90+
}}
91+
transition="color .15s, background .15s"
92+
typography="eyebrow"
93+
>
94+
{a.label}
95+
</Box>
96+
<Box
97+
as="label"
98+
border="1px solid transparent"
99+
borderRadius="4px"
100+
color="$caption"
101+
cursor="pointer"
102+
htmlFor="code-tab-1"
103+
px="12px"
104+
py="6px"
105+
selectors={{
106+
'#code-tab-1:checked ~ * &': {
107+
bg: '$containerBackground',
108+
border: '1px solid $border',
109+
color: '$title',
110+
},
111+
'#code-tab-1:focus-visible ~ * &': {
112+
boxShadow: '0 0 0 2px $vespertidePrimary',
113+
},
114+
}}
115+
transition="color .15s, background .15s"
116+
typography="eyebrow"
117+
>
118+
{b.label}
119+
</Box>
120+
<Box
121+
as="label"
122+
border="1px solid transparent"
123+
borderRadius="4px"
124+
color="$caption"
125+
cursor="pointer"
126+
htmlFor="code-tab-2"
127+
px="12px"
128+
py="6px"
129+
selectors={{
130+
'#code-tab-2:checked ~ * &': {
131+
bg: '$containerBackground',
132+
border: '1px solid $border',
133+
color: '$title',
134+
},
135+
'#code-tab-2:focus-visible ~ * &': {
136+
boxShadow: '0 0 0 2px $vespertidePrimary',
137+
},
138+
}}
139+
transition="color .15s, background .15s"
140+
typography="eyebrow"
141+
>
142+
{c.label}
143+
</Box>
144+
<Box
145+
as="label"
146+
border="1px solid transparent"
147+
borderRadius="4px"
148+
color="$caption"
149+
cursor="pointer"
150+
htmlFor="code-tab-3"
151+
px="12px"
152+
py="6px"
153+
selectors={{
154+
'#code-tab-3:checked ~ * &': {
155+
bg: '$containerBackground',
156+
border: '1px solid $border',
157+
color: '$title',
158+
},
159+
'#code-tab-3:focus-visible ~ * &': {
160+
boxShadow: '0 0 0 2px $vespertidePrimary',
161+
},
162+
}}
163+
transition="color .15s, background .15s"
164+
typography="eyebrow"
165+
>
166+
{d.label}
167+
</Box>
168+
</>
169+
}
170+
title={
171+
<>
172+
<Text
173+
as="span"
174+
display="none"
175+
id="code-title-0"
176+
selectors={{ '#code-tab-0:checked ~ * &': { display: 'block' } }}
177+
>
178+
{a.file}
179+
</Text>
180+
<Text
181+
as="span"
182+
display="none"
183+
id="code-title-1"
184+
selectors={{ '#code-tab-1:checked ~ * &': { display: 'block' } }}
185+
>
186+
{b.file}
187+
</Text>
188+
<Text
189+
as="span"
190+
display="none"
191+
id="code-title-2"
192+
selectors={{ '#code-tab-2:checked ~ * &': { display: 'block' } }}
193+
>
194+
{c.file}
195+
</Text>
196+
<Text
197+
as="span"
198+
display="none"
199+
id="code-title-3"
200+
selectors={{ '#code-tab-3:checked ~ * &': { display: 'block' } }}
201+
>
202+
{d.file}
203+
</Text>
204+
</>
205+
}
206+
>
207+
<Box
208+
display="none"
209+
id="code-panel-0"
210+
selectors={{ '#code-tab-0:checked ~ * &': { display: 'block' } }}
211+
>
212+
<HighlightedCode html={a.html} />
213+
</Box>
214+
<Box
215+
display="none"
216+
id="code-panel-1"
217+
selectors={{ '#code-tab-1:checked ~ * &': { display: 'block' } }}
218+
>
219+
<HighlightedCode html={b.html} />
220+
</Box>
221+
<Box
222+
display="none"
223+
id="code-panel-2"
224+
selectors={{ '#code-tab-2:checked ~ * &': { display: 'block' } }}
225+
>
226+
<HighlightedCode html={c.html} />
227+
</Box>
228+
<Box
229+
display="none"
230+
id="code-panel-3"
231+
selectors={{ '#code-tab-3:checked ~ * &': { display: 'block' } }}
232+
>
233+
<HighlightedCode html={d.html} />
234+
</Box>
235+
</CodeWindow>
236+
</Box>
237+
)
238+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { Box, Flex, globalCss, Text } from '@devup-ui/react'
2+
import type { ComponentProps, ReactNode } from 'react'
3+
4+
globalCss({
5+
'.shiki, .shiki span': {
6+
fontFamily: 'D2Coding',
7+
fontSize: '13px',
8+
lineHeight: '1.65',
9+
},
10+
'.shiki': {
11+
background: 'transparent !important',
12+
padding: '0',
13+
margin: '0',
14+
overflowX: 'auto',
15+
},
16+
'[data-theme="dark"] .shiki, [data-theme="dark"] .shiki span': {
17+
color: 'var(--shiki-dark) !important',
18+
backgroundColor: 'transparent !important',
19+
},
20+
})
21+
22+
export function CodeWindow({
23+
title,
24+
tabs,
25+
children,
26+
...props
27+
}: {
28+
title: ReactNode
29+
tabs?: ReactNode
30+
children: ReactNode
31+
} & Omit<ComponentProps<typeof Box<'div'>>, 'title'>) {
32+
return (
33+
<Box
34+
bg="$cardBase"
35+
border="1px solid $border"
36+
borderRadius="$borderRadiusRadius12"
37+
boxShadow="0 30px 60px -30px rgba(0,0,0,.25)"
38+
overflow="hidden"
39+
{...props}
40+
>
41+
<Flex
42+
alignItems="center"
43+
bg="$vespertideBg"
44+
borderBottom="1px solid $border"
45+
gap="10px"
46+
px="14px"
47+
py="10px"
48+
>
49+
<Flex gap="6px">
50+
{Array.from({ length: 3 }, (_, i) => (
51+
<Box
52+
key={i}
53+
bg="$caption"
54+
borderRadius="50%"
55+
boxSize="10px"
56+
opacity="0.5"
57+
/>
58+
))}
59+
</Flex>
60+
<Text
61+
color="$caption"
62+
fontFamily="D2Coding"
63+
fontSize="12px"
64+
ml="4px"
65+
overflow="hidden"
66+
textOverflow="ellipsis"
67+
whiteSpace="nowrap"
68+
>
69+
{title}
70+
</Text>
71+
{tabs && (
72+
<Flex gap="2px" ml="auto">
73+
{tabs}
74+
</Flex>
75+
)}
76+
</Flex>
77+
<Box overflowX="auto" px="22px" py="20px">
78+
{children}
79+
</Box>
80+
</Box>
81+
)
82+
}
83+
84+
export function HighlightedCode({ html }: { html: string }) {
85+
return <div dangerouslySetInnerHTML={{ __html: html }} />
86+
}
87+
88+
export function StaticCodeBlock({
89+
title,
90+
html,
91+
}: {
92+
title: string
93+
html: string
94+
}) {
95+
return (
96+
<CodeWindow title={title}>
97+
<HighlightedCode html={html} />
98+
</CodeWindow>
99+
)
100+
}
101+
102+
export function HeroCodeWrapper({ children }: { children: ReactNode }) {
103+
return (
104+
<Flex justifyContent={[null, null, null, 'flex-end']} w="100%">
105+
{children}
106+
</Flex>
107+
)
108+
}

0 commit comments

Comments
 (0)