1 Commits

Author SHA1 Message Date
eec6141af3 commit 2026-08-13 05:13:04 +09:00
38 changed files with 1385 additions and 4279 deletions

2
.gitignore vendored
View File

@@ -1,4 +1,2 @@
dist/
node_modules/
storybook-static/
debug-storybook.log

View File

@@ -1,14 +0,0 @@
/** @type { import('@storybook/react-vite').StorybookConfig } */
const config = {
"stories": [
"../src/**/*.mdx",
"../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"
],
"addons": [
"@storybook/addon-docs"
],
"framework": "@storybook/react-vite"
};
export default config;

View File

@@ -1,21 +0,0 @@
import '../src/styles/reset.css'
import '../src/styles/variables.css'
import '../src/styles/global.css'
import '../src/styles/layout.css'
import '../src/styles/components.css'
/** @type { import('@storybook/react-vite').Preview } */
const preview = {
parameters: {
layout: 'fullscreen',
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
tags: ['autodocs'],
};
export default preview;

3622
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,20 +6,14 @@
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"
"preview": "vite preview"
},
"dependencies": {
"@vitejs/plugin-react": "latest",
"vite": "latest",
"react": "latest",
"react-dom": "latest",
"react-router-dom": "latest",
"vite": "latest"
"react-router-dom": "latest"
},
"devDependencies": {
"@storybook/addon-docs": "^10.5.8",
"@storybook/react-vite": "^10.5.8",
"storybook": "^10.5.8"
}
"devDependencies": {}
}

View File

@@ -7,6 +7,8 @@ import NotFound from "./pages/NotFound";
import Project01 from "./pages/projects/Project01";
import Project02 from "./pages/projects/Project02";
import Project03 from "./pages/projects/Project03";
import Project04 from "./pages/projects/Project04";
import Project05 from "./pages/projects/Project05";
export default function App() {
return (
@@ -19,6 +21,8 @@ export default function App() {
<Route path="/works/project-01" element={<Project01 />} />
<Route path="/works/project-02" element={<Project02 />} />
<Route path="/works/project-03" element={<Project03 />} />
<Route path="/works/project-04" element={<Project04 />} />
<Route path="/works/project-05" element={<Project05 />} />
<Route path="*" element={<NotFound />} />
</Routes>
</main>

View File

@@ -1,8 +0,0 @@
import Footer from './Footer'
export default {
title: 'Layout/Footer',
component: Footer,
}
export const Default = {}

View File

@@ -1,10 +0,0 @@
import { MemoryRouter } from 'react-router-dom'
import Header from './Header'
export default {
title: 'Layout/Header',
component: Header,
decorators: [(Story) => <MemoryRouter initialEntries={['/']}><Story /></MemoryRouter>],
}
export const Default = {}

View File

@@ -1,18 +0,0 @@
import { MemoryRouter } from 'react-router-dom'
import ProjectCard from './ProjectCard'
export default {
title: 'Projects/ProjectCard',
component: ProjectCard,
decorators: [(Story) => <MemoryRouter><Story /></MemoryRouter>],
args: {
number: '01',
title: 'Project One',
category: 'UX Case Study',
year: '2025',
image: 'https://images.unsplash.com/photo-1558655146-d09347e92766?auto=format&fit=crop&w=1400&q=80',
to: '/works/project-01',
},
}
export const Default = {}

View File

@@ -1,11 +1,50 @@
import ProjectCard from './ProjectCard'
import ProjectCard from "./ProjectCard";
export const projects = [
{ number: '01', title: 'Project One', category: 'UX Case Study', year: '2025', image: 'https://images.unsplash.com/photo-1558655146-d09347e92766?auto=format&fit=crop&w=1400&q=80', to: '/works/project-01' },
{ number: '02', title: 'Project Two', category: 'Editorial Interface', year: '2024', image: 'https://images.unsplash.com/photo-1559028012-481c04fa702d?auto=format&fit=crop&w=1400&q=80', to: '/works/project-02' },
{ number: '03', title: 'Project Three', category: 'Visual Direction', year: '2024', image: 'https://images.unsplash.com/photo-1550745165-9bc0b252726f?auto=format&fit=crop&w=1400&q=80', to: '/works/project-03' },
]
{
number: "01",
title: "Project One",
category: "UX Case Study",
year: "2025",
image:
"https://images.unsplash.com/photo-1558655146-d09347e92766?auto=format&fit=crop&w=1400&q=80",
to: "/works/project-01",
},
{
number: "02",
title: "Project Two",
category: "Editorial Interface",
year: "2024",
image:
"https://images.unsplash.com/photo-1559028012-481c04fa702d?auto=format&fit=crop&w=1400&q=80",
to: "/works/project-02",
},
{
number: "03",
title: "Project Three",
category: "Visual Direction",
year: "2024",
image:
"https://images.unsplash.com/photo-1550745165-9bc0b252726f?auto=format&fit=crop&w=1400&q=80",
to: "/works/project-03",
},
{
number: "04",
title: "Project Four",
category: "Visual Direction",
year: "2024",
image:
"https://images.unsplash.com/photo-1550745165-9bc0b252726f?auto=format&fit=crop&w=1400&q=80",
to: "/works/project-04",
},
];
export default function ProjectGrid() {
return <div className="project-grid">{projects.map((project) => <ProjectCard key={project.number} {...project} />)}</div>
return (
<div className="project-grid">
{projects.map((project) => (
<ProjectCard key={project.number} {...project} />
))}
</div>
);
}

View File

@@ -1,19 +0,0 @@
import ProjectHero from './ProjectHero'
export default {
title: 'Projects/ProjectHero',
component: ProjectHero,
args: {
number: '01',
category: 'UX Case Study · 2025',
title: 'Project One',
description: 'A clear, end-to-end case study layout for showing how a design decision moves from question to outcome.',
image: 'https://images.unsplash.com/photo-1558655146-d09347e92766?auto=format&fit=crop&w=1800&q=80',
},
}
export const WithImage = {}
export const WithoutImage = {
args: { image: undefined },
}

View File

@@ -1,13 +0,0 @@
import Section from './Section'
export default {
title: 'Content/Section',
component: Section,
args: {
eyebrow: '01 / Introduction',
title: 'A thoughtful section heading.',
children: <p style={{ maxWidth: '32rem' }}>Use sections to give each part of a case study a clear rhythm and hierarchy.</p>,
},
}
export const Default = {}

View File

@@ -1,11 +1,47 @@
import { Link } from 'react-router-dom'
import Section from '../components/Section'
import ProjectGrid from '../components/ProjectGrid'
import { Link } from "react-router-dom";
import Section from "../components/Section";
import ProjectGrid from "../components/ProjectGrid";
export default function Home() {
return <>
<section className="home-hero container"><p className="eyebrow">UX / UI Designer & Visual Thinker</p><h1>Making space<br />for <em>better ideas.</em></h1><p className="lede">A starter portfolio for documenting thoughtful digital experiences, experiments, and everything in between.</p><Link className="text-link" to="/about">More about me <span></span></Link></section>
<Section eyebrow="01 / Intro" title="I turn questions into clear, useful experiences."><div className="intro-copy"><p>Use this space to introduce your point of view. Replace this placeholder with a short statement about what you care about, how you work, or what you are currently exploring.</p><p className="muted">Currently available for selected projects · Seoul, KR</p></div></Section>
<Section eyebrow="02 / Selected works" title="A few things Ive made." className="works-section"><ProjectGrid /></Section>
return (
<>
<section className="home-hero container">
<p className="eyebrow">UX / UI Designer & Visual Thinker</p>
<h1>
Making space
<br />
for <em>better ideas.</em>
</h1>
<p className="lede">
A starter portfolio for documenting thoughtful digital experiences,
experiments, and everything in between.
</p>
<Link className="text-link" to="/about">
More about me <span></span>
</Link>
</section>
<Section
eyebrow="01 / Intro"
title="I turn questions into clear, useful experiences."
>
<div className="intro-copy">
<p>
Use this space to introduce your point of view. Replace this
placeholder with a short statement about what you care about, how
you work, or what you are currently exploring.
</p>
<p className="muted">
Currently available for selected projects · Seoul, KR
</p>
</div>
</Section>
<Section
eyebrow="02 / Selected works"
title="A few things Ive made."
className="works-section"
>
<ProjectGrid />
</Section>
</>
);
}

View File

@@ -1,5 +1,44 @@
import Section from '../../components/Section'
import ProjectHero from '../../components/ProjectHero'
import ProjectNavigation from '../../components/ProjectNavigation'
const image = 'https://images.unsplash.com/photo-1550745165-9bc0b252726f?auto=format&fit=crop&w=2200&q=85'
export default function Project03() { return <article className="project-page visual-project"><ProjectHero number="03" category="Visual Direction · 2024" title="Project Three" description="A visual-first project page where images do most of the talking." image={image} /><div className="visual-stack container"><div className="visual-image" style={{ backgroundImage: `url(${image})` }} /><div className="visual-caption"><p className="eyebrow">A visual system in motion</p><p>Keep the words minimal when the work can carry the story. Add your own images to the public/images folder and update this page.</p></div><div className="visual-image tall" style={{ backgroundImage: `url(https://images.unsplash.com/photo-1558655146-d09347e92766?auto=format&fit=crop&w=1800&q=80)` }} /></div><Section eyebrow="Notes" title="Make room for the unexpected."><p className="narrow-copy">This template is a starting point. Change the visual language, layout, and interaction until it feels like you.</p></Section><ProjectNavigation current="03" /></article> }
import Section from "../../components/Section";
import ProjectHero from "../../components/ProjectHero";
import ProjectNavigation from "../../components/ProjectNavigation";
const image =
"https://images.unsplash.com/photo-1550745165-9bc0b252726f?auto=format&fit=crop&w=2200&q=85";
export default function Project03() {
return (
<article className="project-page visual-project">
<ProjectHero
number="03"
category="Visual Direction · 2024"
title="Project Three"
description="A visual-first project page where images do most of the talking."
image={image}
/>
<div className="visual-stack container">
<div
className="visual-image"
style={{ backgroundImage: `url(${image})` }}
/>
<div className="visual-caption">
<p className="eyebrow">A visual system in motion</p>
<p>
Keep the words minimal when the work can carry the story. Add your
own images to the public/images folder and update this page.
</p>
</div>
<div
className="visual-image tall"
style={{
backgroundImage: `url(https://images.unsplash.com/photo-1558655146-d09347e92766?auto=format&fit=crop&w=1800&q=80)`,
}}
/>
</div>
<Section eyebrow="Notes" title="Make room for the unexpected.">
<p className="narrow-copy">
This template is a starting point. Change the visual language, layout,
and interaction until it feels like you.
</p>
</Section>
<ProjectNavigation current="03" />
</article>
);
}

View File

@@ -0,0 +1,320 @@
import "../../styles/project04.css";
const assets = {
logo: "https://www.figma.com/api/mcp/asset/cad898eb-d97c-4f72-aa0b-ce0dd80249b3.svg",
background:
"https://www.figma.com/api/mcp/asset/c6f558f3-e758-4a9c-a15e-fd593c117399.png",
research:
"https://www.figma.com/api/mcp/asset/de3b0a7f-dfd1-476e-b815-0dc84523784a.png",
twitter:
"https://www.figma.com/api/mcp/asset/b1bb5468-0fcf-4873-9c84-f0a84ce43ac1.png",
data: "https://www.figma.com/api/mcp/asset/aa7a4652-e2bf-4f74-a913-eb224af4bb59.png",
cases:
"https://www.figma.com/api/mcp/asset/070c000e-6945-4224-8883-6423c83c2404.png",
persona:
"https://www.figma.com/api/mcp/asset/5884f613-5caa-4029-836f-724b9de9ab7e.png",
flow: "https://www.figma.com/api/mcp/asset/23699d5e-e1e5-4f48-b170-85646137c599.png",
};
const features = [
[
"MAIN FEATURES 01",
"티켓은 판매 전에 AI가 먼저 검증해요",
"위조 티켓과 동일 티켓의 중복 등록으로 발생하는 사기를 예방하기 위해 판매자가 예매 내역을 등록하면 AI가 위조 여부와 중복 등록 여부를 자동으로 검사합니다. 사기가 발생한 뒤 환불하는 것이 아니라 거래가 시작되기 전에 미리 차단하는 방식으로 검증을 통과한 티켓만 판매할 수 있도록 했습니다.",
],
[
"MAIN FEATURES 02",
"X(트위터)를 떠나지 않아도 안전하게 거래할 수 있어요",
"안전한 거래를 위해 새로운 앱으로 이동해야 하는 불편함을 해결하고자 X(트위터)에서 바로 이용할 수 있는 SaaS형 안전결제 플랫폼을 설계했습니다. 게시글에 안전결제 링크를 연결하여 판매와 구매 모두 X(트위터)에서 가능하며 사용자는 익숙한 SNS 환경을 벗어나지 않고도 안전하게 거래할 수 있습니다.",
],
[
"MAIN FEATURES 03",
"돈은 티켓을 받을 때까지 안전하게 보관돼요",
"공연 직전까지 티켓을 받지 못하거나 판매자가 잠적하는 문제를 해결하기 위해 안전결제를 도입했습니다. 결제 금액은 중간에서 보관하고, 판매자에게 티켓 전송 기한을 두어 거래를 관리합니다. 구매자가 수령 확인과 구매 확정을 완료해야만 정산이 이루어지며 문제가 발생하면 자동으로 환불됩니다.",
],
];
function Label({ children }) {
return <p className="p04-label">{children}</p>;
}
function TextBlock({ label, title, children, className = "" }) {
return (
<div className={`p04-copy ${className}`}>
<Label>{label}</Label>
{title && <h2>{title}</h2>}
{typeof children === "string" ? <p>{children}</p> : children}
</div>
);
}
function ImagePanel({ src, alt = "", className = "" }) {
return (
<div className={`p04-image-panel ${className}`}>
<img src={src} alt={alt} />
</div>
);
}
export default function Project04() {
return (
<main className="project04">
<header className="p04-header">
<a href="#top" className="p04-logo">
<img src={assets.logo} alt="Yeonsu Kim" />
</a>
<nav>
<a href="#overview">WORK</a>
<a href="#empathize">ABOUT</a>
<a href="#takeaways">RESUME</a>
</nav>
</header>
<section className="p04-hero" id="top">
<h1>AI 티켓 사기 예방 패싱</h1>
<div className="p04-hero-art">
<div className="p04-phone p04-phone-back" />
<div className="p04-phone">
<div className="p04-phone-screen">
<b>PASSING</b>
<span>안전한 티켓 거래</span>
<i>AI VERIFIED</i>
</div>
</div>
</div>
<div className="p04-overview" id="overview">
<TextBlock label="OVERVIEW" className="p04-overview-copy">
티켓 사기는 환불을 받더라도 이미 지나간 공연은 다시 없다는
때문에 사전 예방이 가장 중요합니다. 점에 주목해 사기가 빈번한
X(트위터) 티켓 양도 거래 환경의 한계를 보완하고자 사전 AI 이미지
검증을 도입하여 사용자가 익숙한 SNS 환경을 떠나지 않고도 안전하게
거래할 있도록 설계했습니다.
</TextBlock>
<div className="p04-meta">
{[
["Project type", "1인 프로젝트"],
["Duration", "8주"],
[
"Tools",
<>
Figma,
<br />
Figjam,
<br />
FigmaMake,
<br />
Claude,
<br />
Lovable
</>,
],
[
"Role",
<>
리서치,
<br />
UIUX디자인,
<br />
프로토타입,
<br />
사용성 테스트
</>,
],
].map(([label, value]) => (
<div key={label}>
<Label>{label}</Label>
<p>{value}</p>
</div>
))}
</div>
</div>
</section>
<section className="p04-section p04-background">
<div className="p04-row">
<TextBlock
label="BACKGROUND"
title="티켓 사기는 다른 P2P 거래와 무엇이 다를까?"
>
평소 X(트위터)에서 티켓 양도 거래가 활발하고 사기도 많다는 것은 알고
있었으나 문득 이상한 점이 눈에 들어왔습니다. 티켓은 다른 P2P 거래와
달리 환불을 받더라도 이미 지나간 공연은 다시 없다는
점이었습니다. 또한 현장수령, 모바일 티켓은 거래 방식과 예매
형태에 따라 고려해야 변수가 일반적인 P2P 안전장치만으로는 한계가
있다고 생각했습니다.
</TextBlock>
<ImagePanel src={assets.background} alt="티켓 거래 리서치" />
</div>
</section>
<section className="p04-section p04-features">
{features.map(([label, title, copy], index) => (
<div
className={`p04-feature ${index % 2 ? "reverse" : ""}`}
key={label}
>
<TextBlock label={label} title={title}>
{copy}
</TextBlock>
<div className="p04-feature-visual">
<div className="p04-ui-card">
<span>AI TICKET CHECK</span>
<strong>
{index === 0
? "검증 완료"
: index === 1
? "안전결제 연결"
: "결제금액 보관 중"}
</strong>
<small>
{index === 0
? "판매 전 티켓 정보를 확인했어요"
: index === 1
? "X에서 바로 거래를 시작하세요"
: "티켓 수령 후 판매자에게 정산돼요"}
</small>
</div>
</div>
</div>
))}
</section>
<section className="p04-statement" id="empathize">
<Label>EMPATHIZE</Label>
<h2>
Why do users keep trading Tickets on x(Twitter) despite the risk of
scams?
</h2>
<p>
사용자는 '사기 위험' 알면서도 X(트위터)에서의 티켓 거래를 멈추지
못할까?
</p>
</section>
<section className="p04-section p04-research">
<TextBlock label="DESK RESEARCH" title="왜 티켓인가?">
먼저 어떤 품목의 사기 피해가 가장 큰지 확인하고자 뉴스 17건과 학술
연구 6건을 분석했습니다. 결과 티켓·상품권이 사기 피해 1위였고, 20
피해가 가장 많았으며 10 피해도 늘고 있었습니다. 티켓류 상품권과
이용권은 사후 환불로 해결이 가능해 제외했습니다. 환불로도 공연이
돌아오지 않는 점에서 티켓만 최종 대상으로 남겼습니다.
</TextBlock>
<ImagePanel src={assets.research} />
<TextBlock label="" title="왜 X(트위터)인가?">
품목을 티켓으로 좁힌 뒤에는 X(트위터)에서 티켓 사기가 실제로 많은지
검증했습니다. 더치트의 실제 티켓 사기 사례를 분석한 결과, 대부분이
X(트위터) 거래였습니다. 자체 안전거래 시스템 없이 DM으로 거래가
이루어져 구조적으로 사기를 막기 어렵다는 점도 확인했습니다.
</TextBlock>
<ImagePanel src={assets.twitter} />
<ImagePanel src={assets.data} className="p04-dark-panel" />
</section>
<section className="p04-section p04-research">
<TextBlock
label="CASESTUDY ANALYSIS"
title="위험한데도 왜 계속 X(트위터)를 쓸까?"
>
구조적으로 위험하다는 점을 확인한 , 안전장치가 부족한데도
사용자들은 여전히 X(트위터)에서 거래하는지를 알고자 했습니다. 더치트
사기 후기와 커뮤니티 사례, 피해자 인터뷰 방송을 통해 가짜 예매 내역
인증, 조급한 입금 유도 반복되는 사기 패턴을 확인했습니다.
</TextBlock>
<ImagePanel src={assets.cases} />
</section>
<section className="p04-section p04-insight">
<TextBlock
label="DEFINE"
title="“P2P trust gaps lead to fraud, while current solutions focus on compensation.”"
>
P2P 거래 특성상 개인 신뢰에 의존해 사기 위험이 높으며 기존 서비스는
예방이 아닌 피해 이후 보상에 집중되어 있다.
</TextBlock>
<ImagePanel src={assets.persona} />
</section>
<section className="p04-statement p04-ideate">
<Label>IDEATE</Label>
<h2>How might we make ticket trading safe and easy on X(Twitter)?</h2>
<p>
어떻게 하면 익숙한 X(트위터) 환경은 유지하면서 구매자는 안전하고
판매자는 간편하게 티켓을 거래할 있을까?
</p>
</section>
<section className="p04-section p04-process">
<TextBlock
label="BRAIN STORMING"
title="X(트위터)의 편리함은 유지하면서 거래 위험을 예방하는 31가지 AI 기반 아이디어"
>
사기 예방부터 거래 편의성 개선까지 다양한 아이디어를 도출했습니다.
이후 별도의 노력을 들이지 않아도 거래 과정 안에서 자연스럽게 안전성을
확보할 있도록 사전 검증과 신뢰 형성에 집중하는 방향으로 아이디어를
발전시켰습니다.
</TextBlock>
<ImagePanel src={assets.flow} />
</section>
<section className="p04-section p04-prototype">
<TextBlock
label="PROTOTYPE"
title="“Do Buyers Feel Safe and Can Sellers Trade Easily?”"
>
구매자는 실제로 안전하다고 느끼고, 판매자는 쉽게 거래할 있는가?
</TextBlock>
<div className="p04-prototype-grid">
<div>
WIREFRAME
<br />
<b>핵심 기능 구현을 위한 화면 구조 설계</b>
</div>
<div>
USER FLOW
<br />
<b>AI 기반 티켓 검증 프로세스 설계</b>
</div>
<div>
USABILITY TEST
<br />
<b>구매자 신뢰와 판매자 편의성 검증</b>
</div>
</div>
</section>
<section className="p04-section p04-takeaways" id="takeaways">
<TextBlock label="TAKEAWAYS" title="배운 점">
<ol>
<li>
<b>요청 뒤의 진짜 문제 찾기</b> 사용자가 말한 요청이 가리키는 진짜
불안을 찾아내는 법을 배웠습니다.
</li>
<li>
<b>안전과 이탈 없음 사이의 균형</b> 안전장치를 더하는 것과
사용자를 지치게 하지 않는 사이의 균형을 배웠습니다.
</li>
<li>
<b>기술적 한계 안에서 설계하기</b> 좋은 디자인은 한계를 인정하고
안에서 최선의 답을 찾는 것입니다.
</li>
</ol>
</TextBlock>
</section>
<footer className="p04-footer">
<Label>MORE PROJECTS</Label>
<div>
<a href="#">
<b>카카오 T</b>
<span>AI 기반 이동 경험</span>
</a>
<a href="#">
<b>현대 자동차</b>
<span>새로운 모빌리티 경험</span>
</a>
</div>
<small>© 2026 Designed by Yeonsu Kim</small>
</footer>
</main>
);
}

View File

@@ -0,0 +1,486 @@
import "../../styles/project05.css";
const A = {
logo: "https://www.figma.com/api/mcp/asset/97e7b6d8-e3ac-4f5e-8d77-21818d31af38.svg",
hero: "https://www.figma.com/api/mcp/asset/45adf8d9-495e-42a3-82f4-0fda162686e0.png",
background:
"https://www.figma.com/api/mcp/asset/7e55f203-3089-4ab6-8997-146f4e2ff579.png",
research:
"https://www.figma.com/api/mcp/asset/c61f38f4-f170-4004-8f08-5ee7a37d1f2a.png",
cases:
"https://www.figma.com/api/mcp/asset/cd0ef1ff-90b3-4cbe-a80f-2e78a9d7618c.png",
competitor:
"https://www.figma.com/api/mcp/asset/a18f5395-d29c-447c-b2e3-802c1cc99d6f.png",
interview:
"https://www.figma.com/api/mcp/asset/d74cb172-7da5-422c-b6e0-56d0c9fb0a2d.png",
affinity:
"https://www.figma.com/api/mcp/asset/41f58ba5-6259-4b88-a3da-7ae178b1b692.png",
interviewBoard:
"https://www.figma.com/api/mcp/asset/b8c9ec4d-4ab3-49c0-93c1-0e2abb3fdfae.png",
personaBuyer:
"https://www.figma.com/api/mcp/asset/34cf4b9a-d636-43ea-abd9-18a6124762ca.png",
personaSeller:
"https://www.figma.com/api/mcp/asset/8518e1ae-baaa-4249-946a-4aef179cdce6.png",
brainstorming:
"https://www.figma.com/api/mcp/asset/042dacd1-c8ef-4dad-8ed1-c8a293c935f3.png",
moscow:
"https://www.figma.com/api/mcp/asset/99c40f9c-75c9-405e-b255-c6ec1c16696b.png",
storyboard:
"https://www.figma.com/api/mcp/asset/7ff96de8-b753-470d-aaa4-aa24c0bec2cf.png",
flow: "https://www.figma.com/api/mcp/asset/fad06698-bbb7-43cc-a1e4-53be7ee53315.png",
sketches:
"https://www.figma.com/api/mcp/asset/ff32a8c9-690e-42f0-af36-e4b7b26ac97c.png",
buyerFlow:
"https://www.figma.com/api/mcp/asset/d69f3d9e-649a-4334-9b8a-2a9394f4cdab.png",
sellerFlow:
"https://www.figma.com/api/mcp/asset/5f35801a-2fa4-4dde-bcc9-4add23fd0ca8.png",
designSystem:
"https://www.figma.com/api/mcp/asset/7092254c-69ae-4575-a718-b8f4d9f671d9.png",
prototype:
"https://www.figma.com/api/mcp/asset/d863589e-0bc2-4a64-ae7f-59fe249283aa.png",
utTasks:
"https://www.figma.com/api/mcp/asset/70b7e8ba-f355-4052-9a3e-3431aae09f95.png",
sus: "https://www.figma.com/api/mcp/asset/b5a2f888-ecc7-4f43-aedf-ac4ff2b2226b.png",
};
function Label({ children }) {
return <p className="p05-label">{children}</p>;
}
function Copy({ label, title, children, className = "" }) {
return (
<div className={`p05-copy ${className}`}>
<Label>{label}</Label>
{title && <h2>{title}</h2>}
<p>{children}</p>
</div>
);
}
function Media({ src, alt = "", className = "" }) {
return (
<figure className={`p05-media ${className}`}>
<img src={src} alt={alt} />
</figure>
);
}
const features = [
[
"MAIN FEATURES 01",
"티켓은 판매 전에 AI가 먼저 검증해요",
"위조 티켓과 동일 티켓의 중복 등록으로 발생하는 사기를 예방하기 위해 판매자가 예매 내역을 등록하면 AI가 위조 여부와 중복 등록 여부를 자동으로 검사합니다. 사기가 발생한 뒤 환불하는 것이 아니라 거래가 시작되기 전에 미리 차단하는 방식으로 검증을 통과한 티켓만 판매할 수 있도록 했습니다.",
],
[
"MAIN FEATURES 02",
"X(트위터)를 떠나지 않아도 안전하게 거래할 수 있어요",
"안전한 거래를 위해 새로운 앱으로 이동해야 하는 불편함을 해결하고자 X(트위터)에서 바로 이용할 수 있는 SaaS형 안전결제 플랫폼을 설계했습니다. 게시글에 안전결제 링크를 연결하여 판매와 구매 모두 X(트위터)에서 가능하며 사용자는 익숙한 SNS 환경을 벗어나지 않고도 안전하게 거래할 수 있습니다.",
],
[
"MAIN FEATURES 03",
"돈은 티켓을 받을 때까지 안전하게 보관돼요",
"공연 직전까지 티켓을 받지 못하거나 판매자가 잠적하는 문제를 해결하기 위해 안전결제를 도입했습니다. 결제 금액은 중간에서 보관하고, 판매자에게 티켓 전송 기한을 두어 거래를 관리합니다. 구매자가 수령 확인과 구매 확정을 완료해야만 정산이 이루어지며 문제가 발생하면 자동으로 환불됩니다.",
],
];
export default function Project05() {
return (
<article className="project05" id="top">
<header className="p05-header">
<a href="#top">
<img src={A.logo} alt="Yeonsu Kim" />
</a>
<nav>
<a href="#overview">WORK</a>
<a href="#empathize">ABOUT</a>
<a href="#takeaways">RESUME</a>
</nav>
</header>
<section className="p05-hero">
<h1>카카오T with 시니어 맞춤 AI 보이스 에이전트</h1>
<div className="p05-hero-art">
<img src={A.hero} alt="카카오T AI 보이스 에이전트 화면" />
</div>
<div className="p05-overview" id="overview">
<Copy label="OVERVIEW">
티켓 사기는 환불을 받더라도 이미 지나간 공연은 다시 없다는
때문에 사전 예방이 가장 중요합니다. 점에 주목해 사기가 빈번한
X(트위터) 티켓 양도 거래 환경의 한계를 보완하고자 사전 AI 이미지
검증을 도입하여 사용자가 익숙한 SNS 환경을 떠나지 않고도 안전하게
거래할 있도록 설계했습니다.
</Copy>
<div className="p05-meta">
{[
["Project type", "2인 프로젝트(70%)"],
["Duration", "8주"],
[
"Tools",
<>
Figma,
<br />
Figjam,
<br />
FigmaMake,
<br />
Claude
</>,
],
[
"Role",
<>
리서치,
<br />
UIUX디자인,
<br />
프로토타입,
<br />
사용성 테스트
</>,
],
].map(([label, value]) => (
<div key={label}>
<Label>{label}</Label>
<p>{value}</p>
</div>
))}
</div>
</div>
</section>
<section className="p05-content">
<div className="p05-split">
<Copy
label="BACKGROUND"
title="티켓 사기는 다른 P2P 거래와 무엇이 다를까?"
>
평소 X(트위터)에서 티켓 양도 거래가 활발하고 사기도 많다는 것은 알고
있었으나 문득 이상한 점이 눈에 들어왔습니다. 티켓은 다른 P2P 거래와
달리 환불을 받더라도 이미 지나간 공연은 다시 없다는
점이었습니다. 또한 현장수령,모바일 티켓은 거래 방식과 예매 형태에
따라 고려해야 변수가 일반적인 P2P 안전장치만으로는 한계가 있다고
생각했습니다. 저는 차이에 주목했고, 티켓 사기는 티켓 거래에
특화된 방식으로 접근해야 한다고 생각해 프로젝트를 시작하게
되었습니다.
</Copy>
<Media
src={A.background}
alt="티켓 거래 배경 리서치"
className="p05-small-media"
/>
</div>
<div className="p05-features">
{features.map(([label, title, body], index) => (
<div
className={`p05-feature ${index === 1 ? "reverse" : ""}`}
key={label}
>
<Copy label={label} title={title}>
{body}
</Copy>
<div className="p05-device">
<div className="p05-device-card">
<small>
{index === 0
? "AI TICKET CHECK"
: index === 1
? "SAFE ON X"
: "ESCROW PAYMENT"}
</small>
<strong>
{index === 0
? "검증 완료"
: index === 1
? "안전결제 연결"
: "결제금액 보관 중"}
</strong>
<span>
{index === 0
? "판매 전 티켓 정보를 확인했어요"
: index === 1
? "익숙한 환경에서 거래하세요"
: "티켓 수령 후 정산돼요"}
</span>
</div>
</div>
</div>
))}
</div>
</section>
<section className="p05-quote" id="empathize">
<Label>EMPATHIZE</Label>
<h2>
Why do users keep trading Tickets on x(Twitter) despite the risk of
scams?
</h2>
<p>
사용자는 '사기 위험' 알면서도 X(트위터)에서의 티켓 거래를 멈추지
못할까?
</p>
</section>
<section className="p05-content p05-research">
<Copy label="DESK RESEARCH" title="왜 티켓인가?">
먼저 어떤 품목의 사기 피해가 가장 큰지 확인하고자 뉴스 17건과 학술
연구 6건을 분석했습니다. 결과 티켓·상품권이 사기 피해 1위였고, 20
피해가 가장 많았으며 10 피해도 늘고 있었습니다. 젊은 층도 쉽게
피해를 입을 만큼 사기 수법이 교묘해지고 있다는 점에서 반드시 풀어야
문제라고 판단했습니다. 티켓류 상품권과 이용권은 사후 환불로 해결이
가능해 제외했습니다. 환불로도 공연이 돌아오지 않는 점에서 티켓만 최종
대상으로 남겼습니다.
</Copy>
<Media
src={A.research}
alt="티켓 사기 피해 리서치"
className="p05-wide-media"
/>
<Copy
label="CASESTUDY ANALYSIS"
title="위험한데도 왜 계속 X(트위터)를 쓸까?"
>
구조적으로 위험하다는 점을 확인한 , 안전장치가 부족한데도
사용자들은 여전히 X(트위터)에서 거래하는지를 알고자 했습니다. 더치트
사기 후기와 커뮤니티 사례, 피해자 인터뷰 방송을 통해 가짜 예매 내역
인증, 조급한 입금 유도 반복되는 사기 패턴을 확인했고, 실시간으로
많은 매물량과 팬덤 중심의 높은 접근성 때문에 사용자들이 위험을
감수하면서도 X(트위터) 이용할 수밖에 없다는 이유를 발견했습니다.
</Copy>
<Media
src={A.cases}
alt="X 트위터 티켓 사기 사례"
className="p05-tall-media"
/>
<Copy
label="COMPETITOR ANALYSIS"
title="기존 티켓 거래 서비스는 안전한 거래를 어떻게 만들고 있을까?"
>
시장 조사를 위해 이미 안전장치를 갖춘 경쟁사도 함께 분석했습니다.
티켓 전문 거래 플랫폼은 사기 발생 100% 환불을 제공하고 있었지만
공연일까지 기다리다가 판매자가 무단 취소하는 문제가 있었습니다. 이를
통해 기존 서비스는 사후 보상에는 대응하고 있지만 거래 과정에서
발생하는 위험을 사전에 줄이는 데에는 한계가 있음을 확인했습니다.
</Copy>
<Media
src={A.competitor}
alt="경쟁사 분석"
className="p05-tall-media"
/>
</section>
<section className="p05-content p05-interviews">
<Copy
label="USER INTERVIEWS"
title="검증한 X(트위터)를 떠나지 못하는 이유’"
>
앞선 리서치를 바탕으로 1, 일반 관람객 2명을 대상으로 인터뷰를
진행했습니다. 사용자들은 예상대로 X(트위터) 위험성을 알고 있었지만
티켓을 빠르게 찾을 있다는 이유로 계속 이용하기도 했습니다. 새로운
문제를 발견하기보다는 앞서 확인한 위험을 알면서도 떠나지 못하는
이유 검증하는 과정이었습니다.
</Copy>
<div className="p05-image-grid">
<Media src={A.interview} alt="인터뷰 결과지" />
<Media src={A.affinity} alt="어피니티 매핑" />
</div>
<Media
src={A.interviewBoard}
alt="인터뷰 인사이트 보드"
className="p05-tall-media"
/>
</section>
<section className="p05-quote p05-define">
<Label>DEFINE</Label>
<h2>
P2P trust gaps lead to fraud, while current solutions focus on
compensation.
</h2>
<p>
P2P 거래 특성상 개인 신뢰에 의존해 사기 위험이 높으며 기존 서비스는
예방이 아닌 피해 이후 보상에 집중되어 있다.
</p>
</section>
<section className="p05-content">
<Copy label="PERSONA" title="서로 다른 두 사용자의 거래 니즈 분석">
인터뷰를 통해 도출한 인사이트를 바탕으로 구매자와 판매자 퍼소나를
제작했습니다. 구매자는 사기 위험에 대한 불안과 원하는 티켓을 빠르게
구해야 하는 부담이 있었고, 판매자는 티켓 등록 과정과 반복적인 채팅의
번거로움을 경험하고 있었습니다.
</Copy>
<div className="p05-image-grid p05-personas">
<Media src={A.personaBuyer} alt="구매자 퍼소나" />
<Media src={A.personaSeller} alt="판매자 퍼소나" />
</div>
</section>
<section className="p05-quote p05-ideate">
<Label>IDEATE</Label>
<h2>How might we make ticket trading safe and easy on X(Twitter)?</h2>
<p>
어떻게 하면 익숙한 X(트위터) 환경은 유지하면서 구매자는 안전하고
판매자는 간편하게 티켓을 거래할 있을까?
</p>
</section>
<section className="p05-content p05-process">
<Copy
label="BRAIN STORMING"
title="X(트위터)의 편리함은 유지하면서 거래 위험을 예방하는 31가지 AI 기반 아이디어"
>
사기 예방부터 거래 편의성 개선까지 31가지의 다양한 아이디어를
도출했습니다. 이후 사용자가 익숙한 거래 환경은 유지하면서 별도의
노력을 들이지 않아도 거래 과정 안에서 자연스럽게 안전성을 확보할
있도록 사전 검증과 신뢰 형성에 집중하는 방향으로 아이디어를
발전시켰습니다.
</Copy>
<Media
src={A.brainstorming}
alt="브레인스토밍"
className="p05-wide-media"
/>
<Copy
label="MOSCOW PRIOTIZATION"
title="사기 예방을 위한 핵심 기능 우선순위 선정"
>
도출한 아이디어는 MoSCoW Matrix를 활용해 우선순위를 정리했습니다. 특히
Must Have는 해당 기능이 없을 경우 사기 예방이라는 서비스의 핵심
가치가 무너지는가 안전한 거래 환경 구축에 필수적인가 기준으로
선정했습니다.
</Copy>
<Media
src={A.moscow}
alt="MoSCoW 우선순위"
className="p05-tall-media"
/>
<Copy
label="STORY BOARD"
title="불안한 티켓 거래를 안전한 경험으로 바꾸다"
>
사기를 걱정하면서도 원하는 티켓을 위해 X(트위터) 사용할 수밖에 없던
사용자가 AI 검증과 안전장치를 통해 안심하고 X(트위터)에서 거래하는
과정을 스토리보드로 제작했습니다.
</Copy>
<Media src={A.storyboard} alt="스토리보드" className="p05-tall-media" />
<Copy label="USER FLOW" title="AI 기반 티켓 검증 프로세스 설계">
판매 단계에 예매 내역 이미지 기반 AI 검증을 적용해 구매자의 진위
확인 부담을 줄였습니다. 또한 티켓 유형별 판매 절차를 구분해 판매자는
쉽게 등록하고, 구매자는 검증된 정보를 바탕으로 거래할 있도록
설계했습니다.
</Copy>
<Media src={A.flow} alt="사용자 플로우" className="p05-tall-media" />
</section>
<section className="p05-content p05-prototype">
<Copy label="SKETCHES" title="사기 예방을 위한 핵심 기능 우선순위 선정">
도출한 아이디어는 MoSCoW Matrix를 활용해 우선순위를 정리했습니다. 특히
Must Have는 안전한 거래 환경 구축에 필수적인지를 기준으로
선정했습니다.
</Copy>
<div className="p05-image-grid">
<Media src={A.sketches} alt="구매자 모스코우" />
<Media src={A.buyerFlow} alt="판매자 모스코우" />
</div>
<div className="p05-prototype-title">
<Label>PROTOTYPE</Label>
<h2>Do Buyers Feel Safe and Can Sellers Trade Easily?</h2>
<p>
구매자는 실제로 안전하다고 느끼고, 판매자는 쉽게 거래할 있는가?
</p>
</div>
<Copy label="WIREFRAME" title="핵심 기능 구현을 위한 화면 구조 설계">
정의한 사용자 흐름과 기능 구조를 바탕으로 와이어프레임을 제작했습니다.
시각적 요소보다 화면 연결과 주요 기능의 배치를 검토하는 집중하고
아이디어를 빠르게 시각화하려 했습니다.
</Copy>
<div className="p05-image-grid">
<Media src={A.sellerFlow} alt="와이어프레임" />
<Media src={A.flow} alt="화면 흐름" />
</div>
<Copy
label="DESIGN SYSTEM"
title="사용자 경험 검증을 위한 프로토타입 제작"
>
사용자 경험을 시뮬레이션하고 디자인 솔루션을 검증하기 위해
프로토타입을 제작했습니다.
</Copy>
<Media
src={A.designSystem}
alt="디자인 시스템"
className="p05-tall-media"
/>
<Copy
label="PROTOTYPE"
title="사용자 경험을 시뮬레이션하고 디자인 솔루션을 검증하기 위해 프로토타입을 제작했습니다."
>
구매자와 판매자 각각의 흐름을 실제 서비스처럼 연결해 핵심 기능의
이해도와 거래 경험을 확인했습니다.
</Copy>
<Media
src={A.prototype}
alt="프로토타입 화면"
className="p05-tall-media"
/>
</section>
<section className="p05-content p05-usability">
<Copy label="USABILITY TEST" title="구매자 신뢰와 판매자 편의성 검증">
마지막으로 확인하고 싶었던 화면이 작동하는지가 아니라 구매자가
실제로 안심을 느끼는지와 판매자는 판매 흐름이 쉽고 자연스러운지
여부였습니다. 그래서 2명의 사용자에게 과업을 주고 따로 관찰하는 사용성
테스트를 진행했습니다.
</Copy>
<p className="p05-result">
테스트 결과, 구매자는 AI 검증과 안전결제를 통해 거래에 대한 신뢰를
느꼈으며 에스크로 구조도 별도 설명 없이도 쉽게 이해했습니다. 판매자는
복잡한 절차 없이 간편하게 등록할 있다는 점에서 긍정적인 반응을
보였습니다. SUS 점수 또한 평균 86.3점으로 우수한 사용성 평가를
받았습니다.
</p>
<div className="p05-image-grid">
<Media src={A.utTasks} alt="UT Tasks" />
<Media src={A.sus} alt="SUS 점수" />
</div>
</section>
<section className="p05-content p05-takeaways" id="takeaways">
<Copy label="TAKEAWAYS" title="배운 점">
<ol>
<li>
<b>요청 뒤의 진짜 문제 찾기</b> 사용자가 말한 요청을 그대로 만들지
않고, 요청이 가리키는 진짜 불안을 찾아내는 법을 배웠습니다.
</li>
<li>
<b>안전과 이탈 없음 사이의 균형</b> 안전장치를 더하는 것과
사용자를 지치게 하지 않는 사이에서 균형을 잡는 진짜 설계라는
배웠습니다.
</li>
<li>
<b>기술적 한계 안에서 설계하기</b> 예매처 API가 공개되지 않아
없는 일이 많았습니다. 좋은 디자인은 한계를 인정하고
안에서 최선의 답을 찾는 것입니다.
</li>
</ol>
</Copy>
</section>
<footer className="p05-footer">
<Label>MORE PROJECTS</Label>
<div className="p05-more">
<a href="#">
<b>AI 티켓 사기 예방 패싱</b>
<span>
SNS 티켓 거래의 사기 취약점을 해결해 사후 환불로도 되돌릴 없는
공연 경험을 AI 사전 검증으로 보호하는 티켓 거래 플랫폼
</span>
</a>
<a href="#">
<b>현대 자동차</b>
<span>미수령시 30 100% 자동 환불</span>
</a>
</div>
<div className="p05-footer-bottom">
<img src={A.logo} alt="Yeonsu Kim" />
<small>© 2026 Designed by Yeonsu Kim</small>
</div>
</footer>
</article>
);
}

View File

@@ -1,388 +0,0 @@
import { Meta } from "@storybook/addon-docs/blocks";
import Github from "./assets/github.svg";
import Discord from "./assets/discord.svg";
import Youtube from "./assets/youtube.svg";
import Tutorials from "./assets/tutorials.svg";
import Styling from "./assets/styling.png";
import Context from "./assets/context.png";
import Assets from "./assets/assets.png";
import Docs from "./assets/docs.png";
import Share from "./assets/share.png";
import FigmaPlugin from "./assets/figma-plugin.png";
import Testing from "./assets/testing.png";
import Accessibility from "./assets/accessibility.png";
import Theming from "./assets/theming.png";
import AddonLibrary from "./assets/addon-library.png";
export const RightArrow = () => <svg
viewBox="0 0 14 14"
width="8px"
height="14px"
style={{
marginLeft: '4px',
display: 'inline-block',
shapeRendering: 'inherit',
verticalAlign: 'middle',
fill: 'currentColor',
'path fill': 'currentColor'
}}
>
<path d="m11.1 7.35-5.5 5.5a.5.5 0 0 1-.7-.7L10.04 7 4.9 1.85a.5.5 0 1 1 .7-.7l5.5 5.5c.2.2.2.5 0 .7Z" />
</svg>
<Meta title="Configure your project" />
<div className="sb-container">
<div className='sb-section-title'>
# Configure your project
Because Storybook works separately from your app, you'll need to configure it for your specific stack and setup. Below, explore guides for configuring Storybook with popular frameworks and tools. If you get stuck, learn how you can ask for help from our community.
</div>
<div className="sb-section">
<div className="sb-section-item">
<img
src={Styling}
alt="A wall of logos representing different styling technologies"
/>
<h4 className="sb-section-item-heading">Add styling and CSS</h4>
<p className="sb-section-item-paragraph">Like with web applications, there are many ways to include CSS within Storybook. Learn more about setting up styling within Storybook.</p>
<a
className="sb-action-link"
href="https://storybook.js.org/docs/configure/styling-and-css/?renderer={{renderer}}&ref=configure"
target="_blank"
>Learn more<RightArrow /></a>
</div>
<div className="sb-section-item">
<img
src={Context}
alt="An abstraction representing the composition of data for a component"
/>
<h4 className="sb-section-item-heading">Provide context and mocking</h4>
<p className="sb-section-item-paragraph">Often when a story doesn't render, it's because your component is expecting a specific environment or context (like a theme provider) to be available.</p>
<a
className="sb-action-link"
href="https://storybook.js.org/docs/writing-stories/decorators/?renderer={{renderer}}&ref=configure#context-for-mocking"
target="_blank"
>Learn more<RightArrow /></a>
</div>
<div className="sb-section-item">
<img src={Assets} alt="A representation of typography and image assets" />
<div>
<h4 className="sb-section-item-heading">Load assets and resources</h4>
<p className="sb-section-item-paragraph">To link static files (like fonts) to your projects and stories, use the
`staticDirs` configuration option to specify folders to load when
starting Storybook.</p>
<a
className="sb-action-link"
href="https://storybook.js.org/docs/configure/images-and-assets/?renderer={{renderer}}&ref=configure"
target="_blank"
>Learn more<RightArrow /></a>
</div>
</div>
</div>
</div>
<div className="sb-container">
<div className='sb-section-title'>
# Do more with Storybook
Now that you know the basics, let's explore other parts of Storybook that will improve your experience. This list is just to get you started. You can customise Storybook in many ways to fit your needs.
</div>
<div className="sb-section">
<div className="sb-features-grid">
<div className="sb-grid-item">
<img src={Docs} alt="A screenshot showing the autodocs tag being set, pointing a docs page being generated" />
<h4 className="sb-section-item-heading">Autodocs</h4>
<p className="sb-section-item-paragraph">Auto-generate living,
interactive reference documentation from your components and stories.</p>
<a
className="sb-action-link"
href="https://storybook.js.org/docs/writing-docs/autodocs/?renderer={{renderer}}&ref=configure"
target="_blank"
>Learn more<RightArrow /></a>
</div>
<div className="sb-grid-item">
<img src={Share} alt="A browser window showing a Storybook being published to a chromatic.com URL" />
<h4 className="sb-section-item-heading">Publish to Chromatic</h4>
<p className="sb-section-item-paragraph">Publish your Storybook to review and collaborate with your entire team.</p>
<a
className="sb-action-link"
href="https://storybook.js.org/docs/sharing/publish-storybook/?renderer={{renderer}}&ref=configure#publish-storybook-with-chromatic"
target="_blank"
>Learn more<RightArrow /></a>
</div>
<div className="sb-grid-item">
<img src={FigmaPlugin} alt="Windows showing the Storybook plugin in Figma" />
<h4 className="sb-section-item-heading">Figma Plugin</h4>
<p className="sb-section-item-paragraph">Embed your stories into Figma to cross-reference the design and live
implementation in one place.</p>
<a
className="sb-action-link"
href="https://storybook.js.org/docs/sharing/design-integrations/?renderer={{renderer}}&ref=configure#embed-storybook-in-figma-with-the-plugin"
target="_blank"
>Learn more<RightArrow /></a>
</div>
<div className="sb-grid-item">
<img src={Testing} alt="Screenshot of tests passing and failing" />
<h4 className="sb-section-item-heading">Testing</h4>
<p className="sb-section-item-paragraph">Use stories to test a component in all its variations, no matter how
complex.</p>
<a
className="sb-action-link"
href="https://storybook.js.org/docs/writing-tests/?renderer={{renderer}}&ref=configure"
target="_blank"
>Learn more<RightArrow /></a>
</div>
<div className="sb-grid-item">
<img src={Accessibility} alt="Screenshot of accessibility tests passing and failing" />
<h4 className="sb-section-item-heading">Accessibility</h4>
<p className="sb-section-item-paragraph">Automatically test your components for a11y issues as you develop.</p>
<a
className="sb-action-link"
href="https://storybook.js.org/docs/writing-tests/accessibility-testing/?renderer={{renderer}}&ref=configure"
target="_blank"
>Learn more<RightArrow /></a>
</div>
<div className="sb-grid-item">
<img src={Theming} alt="Screenshot of Storybook in light and dark mode" />
<h4 className="sb-section-item-heading">Theming</h4>
<p className="sb-section-item-paragraph">Theme Storybook's UI to personalize it to your project.</p>
<a
className="sb-action-link"
href="https://storybook.js.org/docs/configure/theming/?renderer={{renderer}}&ref=configure"
target="_blank"
>Learn more<RightArrow /></a>
</div>
</div>
</div>
</div>
<div className='sb-addon'>
<div className='sb-addon-text'>
<h4>Addons</h4>
<p className="sb-section-item-paragraph">Integrate your tools with Storybook to connect workflows.</p>
<a
className="sb-action-link"
href="https://storybook.js.org/addons/?ref=configure"
target="_blank"
>Discover all addons<RightArrow /></a>
</div>
<div className='sb-addon-img'>
<img src={AddonLibrary} alt="Integrate your tools with Storybook to connect workflows." />
</div>
</div>
<div className="sb-section sb-socials">
<div className="sb-section-item">
<img src={Github} alt="Github logo" className="sb-explore-image"/>
Join our contributors building the future of UI development.
<a
className="sb-action-link"
href="https://github.com/storybookjs/storybook"
target="_blank"
>Star on GitHub<RightArrow /></a>
</div>
<div className="sb-section-item">
<img src={Discord} alt="Discord logo" className="sb-explore-image"/>
<div>
Get support and chat with frontend developers.
<a
className="sb-action-link"
href="https://discord.gg/storybook"
target="_blank"
>Join Discord server<RightArrow /></a>
</div>
</div>
<div className="sb-section-item">
<img src={Youtube} alt="Youtube logo" className="sb-explore-image"/>
<div>
Watch tutorials, feature previews and interviews.
<a
className="sb-action-link"
href="https://www.youtube.com/@chromaticui"
target="_blank"
>Watch on YouTube<RightArrow /></a>
</div>
</div>
<div className="sb-section-item">
<img src={Tutorials} alt="A book" className="sb-explore-image"/>
<p>Follow guided walkthroughs on for key workflows.</p>
<a
className="sb-action-link"
href="https://storybook.js.org/tutorials/?ref=configure"
target="_blank"
>Discover tutorials<RightArrow /></a>
</div>
</div>
<style>
{`
.sb-container {
margin-bottom: 48px;
}
.sb-section {
width: 100%;
display: flex;
flex-direction: row;
gap: 20px;
}
img {
object-fit: cover;
}
.sb-section-title {
margin-bottom: 32px;
}
.sb-section a:not(h1 a, h2 a, h3 a) {
font-size: 14px;
}
.sb-section-item, .sb-grid-item {
flex: 1;
display: flex;
flex-direction: column;
}
.sb-section-item-heading {
padding-top: 20px !important;
padding-bottom: 5px !important;
margin: 0 !important;
}
.sb-section-item-paragraph {
margin: 0;
padding-bottom: 10px;
}
.sb-action-link {
text-decoration: none;
}
.sb-action-link:hover, .sb-action-link:focus {
text-decoration: underline;
text-decoration-thickness: 0.03125rem;
text-underline-offset: 0.11em;
}
.sb-chevron {
margin-left: 5px;
}
.sb-features-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: 32px 20px;
}
.sb-socials {
display: grid;
grid-template-columns: repeat(4, 1fr);
}
.sb-socials p {
margin-bottom: 10px;
}
.sb-explore-image {
max-height: 32px;
align-self: flex-start;
}
.sb-addon {
width: 100%;
display: flex;
align-items: center;
position: relative;
background-color: #EEF3F8;
border-radius: 5px;
border: 1px solid rgba(0, 0, 0, 0.05);
background: #EEF3F8;
height: 180px;
margin-bottom: 48px;
overflow: hidden;
}
.sb-addon-text {
padding-left: 48px;
max-width: 240px;
}
.sb-addon-text h4 {
padding-top: 0px;
}
.sb-addon-img {
position: absolute;
left: 345px;
top: 0;
height: 100%;
width: 200%;
overflow: hidden;
}
.sb-addon-img img {
width: 650px;
transform: rotate(-15deg);
margin-left: 40px;
margin-top: -72px;
box-shadow: 0 0 1px rgba(255, 255, 255, 0);
backface-visibility: hidden;
}
@media screen and (max-width: 800px) {
.sb-addon-img {
left: 300px;
}
}
@media screen and (max-width: 600px) {
.sb-section {
flex-direction: column;
}
.sb-features-grid {
grid-template-columns: repeat(1, 1fr);
}
.sb-socials {
grid-template-columns: repeat(2, 1fr);
}
.sb-addon {
height: 280px;
align-items: flex-start;
padding-top: 32px;
overflow: hidden;
}
.sb-addon-text {
padding-left: 24px;
}
.sb-addon-img {
right: 0;
left: 0;
top: 130px;
bottom: 0;
overflow: hidden;
height: auto;
width: 124%;
}
.sb-addon-img img {
width: 1200px;
transform: rotate(-12deg);
margin-left: 0;
margin-top: 48px;
margin-bottom: -40px;
margin-left: -24px;
}
}
`}
</style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none" viewBox="0 0 48 48"><title>Accessibility</title><circle cx="24.334" cy="24" r="24" fill="#A849FF" fill-opacity=".3"/><path fill="#A470D5" fill-rule="evenodd" d="M27.8609 11.585C27.8609 9.59506 26.2497 7.99023 24.2519 7.99023C22.254 7.99023 20.6429 9.65925 20.6429 11.585C20.6429 13.575 22.254 15.1799 24.2519 15.1799C26.2497 15.1799 27.8609 13.575 27.8609 11.585ZM21.8922 22.6473C21.8467 23.9096 21.7901 25.4788 21.5897 26.2771C20.9853 29.0462 17.7348 36.3314 17.3325 37.2275C17.1891 37.4923 17.1077 37.7955 17.1077 38.1178C17.1077 39.1519 17.946 39.9902 18.9802 39.9902C19.6587 39.9902 20.253 39.6293 20.5814 39.0889L20.6429 38.9874L24.2841 31.22C24.2841 31.22 27.5529 37.9214 27.9238 38.6591C28.2948 39.3967 28.8709 39.9902 29.7168 39.9902C30.751 39.9902 31.5893 39.1519 31.5893 38.1178C31.5893 37.7951 31.3639 37.2265 31.3639 37.2265C30.9581 36.3258 27.698 29.0452 27.0938 26.2771C26.8975 25.4948 26.847 23.9722 26.8056 22.7236C26.7927 22.333 26.7806 21.9693 26.7653 21.6634C26.7008 21.214 27.0231 20.8289 27.4097 20.7005L35.3366 18.3253C36.3033 18.0685 36.8834 16.9773 36.6256 16.0144C36.3678 15.0515 35.2722 14.4737 34.3055 14.7305C34.3055 14.7305 26.8619 17.1057 24.2841 17.1057C21.7062 17.1057 14.456 14.7947 14.456 14.7947C13.4893 14.5379 12.3937 14.9873 12.0715 15.9502C11.7493 16.9131 12.3293 18.0044 13.3604 18.3253L21.2873 20.7005C21.674 20.8289 21.9318 21.214 21.9318 21.6634C21.9174 21.9493 21.9053 22.2857 21.8922 22.6473Z" clip-rule="evenodd"/></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 456 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 829 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="33" height="32" fill="none" viewBox="0 0 33 32"><g clip-path="url(#clip0_10031_177575)"><mask id="mask0_10031_177575" style="mask-type:luminance" width="33" height="25" x="0" y="4" maskUnits="userSpaceOnUse"><path fill="#fff" d="M32.5034 4.00195H0.503906V28.7758H32.5034V4.00195Z"/></mask><g mask="url(#mask0_10031_177575)"><path fill="#5865F2" d="M27.5928 6.20817C25.5533 5.27289 23.3662 4.58382 21.0794 4.18916C21.0378 4.18154 20.9962 4.20057 20.9747 4.23864C20.6935 4.73863 20.3819 5.3909 20.1637 5.90358C17.7042 5.53558 15.2573 5.53558 12.8481 5.90358C12.6299 5.37951 12.307 4.73863 12.0245 4.23864C12.003 4.20184 11.9614 4.18281 11.9198 4.18916C9.63431 4.58255 7.44721 5.27163 5.40641 6.20817C5.38874 6.21578 5.3736 6.22848 5.36355 6.24497C1.21508 12.439 0.078646 18.4809 0.636144 24.4478C0.638667 24.477 0.655064 24.5049 0.677768 24.5227C3.41481 26.5315 6.06609 27.7511 8.66815 28.5594C8.70979 28.5721 8.75392 28.5569 8.78042 28.5226C9.39594 27.6826 9.94461 26.7968 10.4151 25.8653C10.4428 25.8107 10.4163 25.746 10.3596 25.7244C9.48927 25.3945 8.66058 24.9922 7.86343 24.5354C7.80038 24.4986 7.79533 24.4084 7.85333 24.3653C8.02108 24.2397 8.18888 24.109 8.34906 23.977C8.37804 23.9529 8.41842 23.9478 8.45249 23.963C13.6894 26.3526 19.359 26.3526 24.5341 23.963C24.5682 23.9465 24.6086 23.9516 24.6388 23.9757C24.799 24.1077 24.9668 24.2397 25.1358 24.3653C25.1938 24.4084 25.19 24.4986 25.127 24.5354C24.3298 25.0011 23.5011 25.3945 22.6296 25.7232C22.5728 25.7447 22.5476 25.8107 22.5754 25.8653C23.0559 26.7955 23.6046 27.6812 24.2087 28.5213C24.234 28.5569 24.2794 28.5721 24.321 28.5594C26.9357 27.7511 29.5869 26.5315 32.324 24.5227C32.348 24.5049 32.3631 24.4783 32.3656 24.4491C33.0328 17.5506 31.2481 11.5584 27.6344 6.24623C27.6256 6.22848 27.6105 6.21578 27.5928 6.20817ZM11.1971 20.8146C9.62043 20.8146 8.32129 19.3679 8.32129 17.5913C8.32129 15.8146 9.59523 14.368 11.1971 14.368C12.8115 14.368 14.0981 15.8273 14.0729 17.5913C14.0729 19.3679 12.7989 20.8146 11.1971 20.8146ZM21.8299 20.8146C20.2533 20.8146 18.9541 19.3679 18.9541 17.5913C18.9541 15.8146 20.228 14.368 21.8299 14.368C23.4444 14.368 24.7309 15.8273 24.7057 17.5913C24.7057 19.3679 23.4444 20.8146 21.8299 20.8146Z"/></g></g><defs><clipPath id="clip0_10031_177575"><rect width="32" height="32" fill="#fff" transform="translate(0.5)"/></clipPath></defs></svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="none" viewBox="0 0 32 32"><path fill="#161614" d="M16.0001 0C7.16466 0 0 7.17472 0 16.0256C0 23.1061 4.58452 29.1131 10.9419 31.2322C11.7415 31.3805 12.0351 30.8845 12.0351 30.4613C12.0351 30.0791 12.0202 28.8167 12.0133 27.4776C7.56209 28.447 6.62283 25.5868 6.62283 25.5868C5.89499 23.7345 4.8463 23.2419 4.8463 23.2419C3.39461 22.2473 4.95573 22.2678 4.95573 22.2678C6.56242 22.3808 7.40842 23.9192 7.40842 23.9192C8.83547 26.3691 11.1514 25.6609 12.0645 25.2514C12.2081 24.2156 12.6227 23.5087 13.0803 23.1085C9.52648 22.7032 5.7906 21.3291 5.7906 15.1886C5.7906 13.4389 6.41563 12.0094 7.43916 10.8871C7.27303 10.4834 6.72537 8.85349 7.59415 6.64609C7.59415 6.64609 8.93774 6.21539 11.9953 8.28877C13.2716 7.9337 14.6404 7.75563 16.0001 7.74953C17.3599 7.75563 18.7297 7.9337 20.0084 8.28877C23.0623 6.21539 24.404 6.64609 24.404 6.64609C25.2749 8.85349 24.727 10.4834 24.5608 10.8871C25.5868 12.0094 26.2075 13.4389 26.2075 15.1886C26.2075 21.3437 22.4645 22.699 18.9017 23.0957C19.4756 23.593 19.9869 24.5683 19.9869 26.0634C19.9869 28.2077 19.9684 29.9334 19.9684 30.4613C19.9684 30.8877 20.2564 31.3874 21.0674 31.2301C27.4213 29.1086 32 23.1037 32 16.0256C32 7.17472 24.8364 0 16.0001 0ZM5.99257 22.8288C5.95733 22.9084 5.83227 22.9322 5.71834 22.8776C5.60229 22.8253 5.53711 22.7168 5.57474 22.6369C5.60918 22.5549 5.7345 22.5321 5.85029 22.587C5.9666 22.6393 6.03284 22.7489 5.99257 22.8288ZM6.7796 23.5321C6.70329 23.603 6.55412 23.5701 6.45291 23.4581C6.34825 23.3464 6.32864 23.197 6.40601 23.125C6.4847 23.0542 6.62937 23.0874 6.73429 23.1991C6.83895 23.3121 6.85935 23.4605 6.7796 23.5321ZM7.31953 24.4321C7.2215 24.5003 7.0612 24.4363 6.96211 24.2938C6.86407 24.1513 6.86407 23.9804 6.96422 23.9119C7.06358 23.8435 7.2215 23.905 7.32191 24.0465C7.41968 24.1914 7.41968 24.3623 7.31953 24.4321ZM8.23267 25.4743C8.14497 25.5712 7.95818 25.5452 7.82146 25.413C7.68156 25.2838 7.64261 25.1004 7.73058 25.0035C7.81934 24.9064 8.00719 24.9337 8.14497 25.0648C8.28381 25.1938 8.3262 25.3785 8.23267 25.4743ZM9.41281 25.8262C9.37413 25.9517 9.19423 26.0088 9.013 25.9554C8.83203 25.9005 8.7136 25.7535 8.75016 25.6266C8.78778 25.5003 8.96848 25.4408 9.15104 25.4979C9.33174 25.5526 9.45044 25.6985 9.41281 25.8262ZM10.7559 25.9754C10.7604 26.1076 10.6067 26.2172 10.4165 26.2196C10.2252 26.2238 10.0704 26.1169 10.0683 25.9868C10.0683 25.8534 10.2185 25.7448 10.4098 25.7416C10.6001 25.7379 10.7559 25.8441 10.7559 25.9754ZM12.0753 25.9248C12.0981 26.0537 11.9658 26.1862 11.7769 26.2215C11.5912 26.2554 11.4192 26.1758 11.3957 26.0479C11.3726 25.9157 11.5072 25.7833 11.6927 25.7491C11.8819 25.7162 12.0512 25.7937 12.0753 25.9248Z"/></svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="33" height="32" fill="none" viewBox="0 0 33 32"><g clip-path="url(#clip0_10031_177597)"><path fill="#B7F0EF" fill-rule="evenodd" d="M17 7.87059C17 6.48214 17.9812 5.28722 19.3431 5.01709L29.5249 2.99755C31.3238 2.64076 33 4.01717 33 5.85105V22.1344C33 23.5229 32.0188 24.7178 30.6569 24.9879L20.4751 27.0074C18.6762 27.3642 17 25.9878 17 24.1539L17 7.87059Z" clip-rule="evenodd" opacity=".7"/><path fill="#87E6E5" fill-rule="evenodd" d="M1 5.85245C1 4.01857 2.67623 2.64215 4.47507 2.99895L14.6569 5.01848C16.0188 5.28861 17 6.48354 17 7.87198V24.1553C17 25.9892 15.3238 27.3656 13.5249 27.0088L3.34311 24.9893C1.98119 24.7192 1 23.5242 1 22.1358V5.85245Z" clip-rule="evenodd"/><path fill="#61C1FD" fill-rule="evenodd" d="M15.543 5.71289C15.543 5.71289 16.8157 5.96289 17.4002 6.57653C17.9847 7.19016 18.4521 9.03107 18.4521 9.03107C18.4521 9.03107 18.4521 25.1106 18.4521 26.9629C18.4521 28.8152 19.3775 31.4174 19.3775 31.4174L17.4002 28.8947L16.2575 31.4174C16.2575 31.4174 15.543 29.0765 15.543 27.122C15.543 25.1674 15.543 5.71289 15.543 5.71289Z" clip-rule="evenodd"/></g><defs><clipPath id="clip0_10031_177597"><rect width="32" height="32" fill="#fff" transform="translate(0.5)"/></clipPath></defs></svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="none" viewBox="0 0 32 32"><path fill="#ED1D24" d="M31.3313 8.44657C30.9633 7.08998 29.8791 6.02172 28.5022 5.65916C26.0067 5.00026 16 5.00026 16 5.00026C16 5.00026 5.99333 5.00026 3.4978 5.65916C2.12102 6.02172 1.03665 7.08998 0.668678 8.44657C0 10.9053 0 16.0353 0 16.0353C0 16.0353 0 21.1652 0.668678 23.6242C1.03665 24.9806 2.12102 26.0489 3.4978 26.4116C5.99333 27.0703 16 27.0703 16 27.0703C16 27.0703 26.0067 27.0703 28.5022 26.4116C29.8791 26.0489 30.9633 24.9806 31.3313 23.6242C32 21.1652 32 16.0353 32 16.0353C32 16.0353 32 10.9053 31.3313 8.44657Z"/><path fill="#fff" d="M12.7266 20.6934L21.0902 16.036L12.7266 11.3781V20.6934Z"/></svg>

Before

Width:  |  Height:  |  Size: 716 B

View File

@@ -1,30 +0,0 @@
.storybook-button {
display: inline-block;
cursor: pointer;
border: 0;
border-radius: 3em;
font-weight: 700;
line-height: 1;
font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.storybook-button--primary {
background-color: #555ab9;
color: white;
}
.storybook-button--secondary {
box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;
background-color: transparent;
color: #333;
}
.storybook-button--small {
padding: 10px 16px;
font-size: 12px;
}
.storybook-button--medium {
padding: 11px 20px;
font-size: 14px;
}
.storybook-button--large {
padding: 12px 24px;
font-size: 16px;
}

View File

@@ -1,32 +0,0 @@
.storybook-header {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
padding: 15px 20px;
font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.storybook-header svg {
display: inline-block;
vertical-align: top;
}
.storybook-header h1 {
display: inline-block;
vertical-align: top;
margin: 6px 0 6px 10px;
font-weight: 700;
font-size: 20px;
line-height: 1;
}
.storybook-header button + button {
margin-left: 10px;
}
.storybook-header .welcome {
margin-right: 10px;
color: #333;
font-size: 14px;
}

View File

@@ -1,68 +0,0 @@
.storybook-page {
margin: 0 auto;
padding: 48px 20px;
max-width: 600px;
color: #333;
font-size: 14px;
line-height: 24px;
font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.storybook-page h2 {
display: inline-block;
vertical-align: top;
margin: 0 0 4px;
font-weight: 700;
font-size: 32px;
line-height: 1;
}
.storybook-page p {
margin: 1em 0;
}
.storybook-page a {
color: inherit;
}
.storybook-page ul {
margin: 1em 0;
padding-left: 30px;
}
.storybook-page li {
margin-bottom: 8px;
}
.storybook-page .tip {
display: inline-block;
vertical-align: top;
margin-right: 10px;
border-radius: 1em;
background: #e7fdd8;
padding: 4px 12px;
color: #357a14;
font-weight: 700;
font-size: 11px;
line-height: 12px;
}
.storybook-page .tip-wrapper {
margin-top: 40px;
margin-bottom: 40px;
font-size: 13px;
line-height: 20px;
}
.storybook-page .tip-wrapper svg {
display: inline-block;
vertical-align: top;
margin-top: 3px;
margin-right: 4px;
width: 12px;
height: 12px;
}
.storybook-page .tip-wrapper svg path {
fill: #1ea7fd;
}

432
src/styles/project04.css Normal file
View File

@@ -0,0 +1,432 @@
@import url("https://fonts.googleapis.com/css2?family=DM+Mono:wght@400&family=Noto+Sans+KR:wght@400;500;700&display=swap");
.project04 {
--blue: #dee4f2;
--ink: #212121;
--muted: #757575;
background: var(--blue);
color: var(--ink);
font-family: "Noto Sans KR", Arial, sans-serif;
line-height: 1.48;
overflow: hidden;
}
.project04 * {
box-sizing: border-box;
}
.project04 a {
color: inherit;
text-decoration: none;
}
.p04-header {
height: 76px;
padding: 18px 68px;
display: flex;
align-items: center;
justify-content: space-between;
background: rgba(222, 228, 242, 0.9);
position: sticky;
top: 0;
z-index: 20;
backdrop-filter: blur(10px);
}
.p04-logo img {
display: block;
width: 61px;
height: 40px;
}
.p04-header nav {
display: flex;
gap: 72px;
font:
24px/1 "DM Mono",
monospace;
}
.p04-hero {
padding: 130px 40px 100px;
}
.p04-hero > h1 {
max-width: 1840px;
margin: 0 auto 100px;
font-size: clamp(44px, 4.58vw, 88px);
font-weight: 500;
line-height: 1.1;
letter-spacing: -0.07em;
}
.p04-hero-art {
height: min(824px, 43vw);
max-width: 1840px;
margin: auto;
background: #030305;
border-radius: 10px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.p04-hero-art:before {
content: "";
position: absolute;
width: 1000px;
height: 1000px;
border-radius: 50%;
background: radial-gradient(
circle,
#354267 0,
rgba(38, 47, 78, 0.45) 34%,
transparent 68%
);
filter: blur(5px);
}
.p04-phone {
width: 260px;
height: 535px;
border: 10px solid #151a25;
border-radius: 42px;
background: #0c1019;
box-shadow: 0 22px 60px #000;
transform: rotate(8deg);
position: relative;
z-index: 1;
padding: 9px;
}
.p04-phone-back {
position: absolute;
transform: translate(-150px, 30px) rotate(-13deg);
opacity: 0.55;
width: 245px;
height: 505px;
}
.p04-phone-screen {
height: 100%;
border-radius: 30px;
background: linear-gradient(145deg, #f8f9ff, #a6b5db);
display: flex;
flex-direction: column;
justify-content: flex-end;
padding: 28px 22px;
gap: 8px;
color: #151a26;
}
.p04-phone-screen b {
font:
28px/1 "DM Mono",
monospace;
}
.p04-phone-screen span {
font-size: 14px;
}
.p04-phone-screen i {
background: #3d55ad;
color: #fff;
border-radius: 99px;
padding: 6px 10px;
align-self: flex-start;
font:
11px "DM Mono",
monospace;
font-style: normal;
}
.p04-overview {
max-width: 1200px;
margin: 100px auto 0;
display: flex;
justify-content: space-between;
gap: 80px;
}
.p04-copy {
max-width: 665px;
}
.p04-label {
margin: 0;
color: var(--muted);
font:
16px/1.1 "DM Mono",
monospace;
letter-spacing: 0.02em;
text-transform: uppercase;
}
.p04-copy h2 {
font-size: 24px;
line-height: 1.38;
margin: 16px 0;
font-weight: 700;
letter-spacing: -0.04em;
}
.p04-copy > p {
font-size: 18px;
margin: 0;
}
.p04-overview-copy {
max-width: 409px;
}
.p04-meta {
display: grid;
grid-template-columns: repeat(4, 180px);
gap: 0;
}
.p04-meta > div {
font-size: 18px;
}
.p04-meta .p04-label {
margin-bottom: 10px;
}
.p04-section {
max-width: 1200px;
margin: 0 auto;
padding: 40px 0;
}
.p04-row {
display: flex;
justify-content: space-between;
gap: 70px;
align-items: flex-start;
}
.p04-image-panel {
border-radius: 10px;
overflow: hidden;
background: #d4d4d4;
width: 100%;
margin-top: 40px;
min-height: 300px;
}
.p04-image-panel img {
display: block;
width: 100%;
height: 100%;
min-height: inherit;
object-fit: cover;
}
.p04-background .p04-image-panel {
width: 464px;
height: 301px;
margin: 0;
flex: 0 0 auto;
}
.p04-features {
padding-top: 0;
}
.p04-feature {
min-height: 775px;
padding: 40px 0;
display: flex;
gap: 140px;
align-items: flex-start;
}
.p04-feature.reverse {
flex-direction: row-reverse;
}
.p04-feature .p04-copy {
width: 510px;
flex: 0 0 510px;
}
.p04-feature-visual {
width: 378px;
height: 695px;
border-radius: 30px;
background: linear-gradient(155deg, #2a2d40, #ccd3e2 72%, #eef2fc);
padding: 42px 25px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: inset 0 0 0 8px #f3f5fb;
}
.p04-ui-card {
width: 100%;
background: #fff;
border-radius: 18px;
box-shadow: 0 15px 35px #23304c33;
padding: 25px 18px;
display: flex;
flex-direction: column;
gap: 15px;
}
.p04-ui-card span {
font:
11px "DM Mono",
monospace;
color: #6371a7;
}
.p04-ui-card strong {
font-size: 25px;
}
.p04-ui-card small {
color: #777;
font-size: 13px;
}
.p04-statement {
padding: 120px max(40px, calc((100vw - 1200px) / 2));
text-align: center;
}
.p04-statement h2 {
font:
clamp(36px, 3.65vw, 70px)/1.05 "DM Mono",
monospace;
margin: 18px auto 12px;
letter-spacing: -0.06em;
}
.p04-statement > p {
font-size: 20px;
margin: 0;
}
.p04-research,
.p04-insight,
.p04-process {
padding-top: 40px;
}
.p04-research > .p04-copy,
.p04-insight > .p04-copy,
.p04-process > .p04-copy {
margin-bottom: 50px;
}
.p04-research > .p04-copy:nth-of-type(2) {
margin-top: 40px;
}
.p04-research .p04-image-panel {
height: 524px;
}
.p04-research .p04-image-panel:nth-of-type(2) {
height: 525px;
}
.p04-research .p04-dark-panel {
height: 562px;
background: #302658;
}
.p04-insight .p04-image-panel {
height: 550px;
}
.p04-ideate {
padding-top: 140px;
padding-bottom: 140px;
}
.p04-process .p04-image-panel {
height: 500px;
}
.p04-prototype {
padding-top: 130px;
padding-bottom: 130px;
}
.p04-prototype-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
margin-top: 80px;
}
.p04-prototype-grid > div {
min-height: 250px;
border-top: 1px solid #777;
padding: 18px 0;
font:
15px "DM Mono",
monospace;
color: #757575;
}
.p04-prototype-grid b {
display: block;
color: var(--ink);
font: 700 20px "Noto Sans KR";
margin-top: 45px;
}
.p04-takeaways {
padding: 120px 0;
}
.p04-takeaways ol {
padding-left: 22px;
margin: 30px 0 0;
font-size: 18px;
}
.p04-takeaways li {
padding: 9px 0;
}
.p04-footer {
padding: 100px max(40px, calc((100vw - 1200px) / 2)) 40px;
}
.p04-footer > div {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin: 35px 0 100px;
}
.p04-footer a {
padding: 22px 0;
border-top: 1px solid #707070;
display: flex;
justify-content: space-between;
}
.p04-footer b {
font-size: 22px;
}
.p04-footer span {
color: var(--muted);
}
.p04-footer small {
color: var(--muted);
}
@media (max-width: 900px) {
.p04-header {
padding: 16px 20px;
}
.p04-header nav {
gap: 20px;
font-size: 14px;
}
.p04-hero {
padding: 70px 20px;
}
.p04-hero > h1 {
margin-bottom: 50px;
}
.p04-hero-art {
height: 600px;
}
.p04-overview,
.p04-row,
.p04-feature,
.p04-feature.reverse {
display: flex;
flex-direction: column;
gap: 40px;
}
.p04-overview {
margin-top: 60px;
}
.p04-meta {
grid-template-columns: repeat(2, 1fr);
gap: 30px;
width: 100%;
}
.p04-section {
padding: 40px 20px;
}
.p04-background .p04-image-panel {
width: 100%;
height: 260px;
}
.p04-feature {
min-height: 0;
}
.p04-feature .p04-copy,
.p04-feature-visual {
width: 100%;
flex-basis: auto;
}
.p04-feature-visual {
height: 560px;
}
.p04-statement {
padding: 90px 20px;
}
.p04-statement h2 {
font-size: 34px;
}
.p04-prototype-grid,
.p04-footer > div {
grid-template-columns: 1fr;
}
.p04-footer {
padding: 80px 20px 30px;
}
.p04-footer > div {
margin-bottom: 70px;
}
}

4
src/styles/project05.css Normal file
View File

@@ -0,0 +1,4 @@
@import url('https://fonts.googleapis.com/css2?family=DM+Mono&family=Noto+Sans+KR:wght@400;500;700&display=swap');
.project05{--bg:#dee4f2;--ink:#212121;--muted:#757575;background:var(--bg);color:var(--ink);font-family:'Noto Sans KR',Arial,sans-serif;line-height:1.48;overflow:hidden}.project05 *{box-sizing:border-box}.project05 a{color:inherit;text-decoration:none}.p05-header{height:76px;padding:18px 68px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:20;background:rgba(222,228,242,.9);backdrop-filter:blur(10px)}.p05-header img,.p05-footer-bottom img{display:block;width:61px;height:40px}.p05-header nav{display:flex;gap:72px;font:24px/1 'DM Mono',monospace}.p05-hero{padding:130px 40px 100px}.p05-hero h1{max-width:1840px;margin:0 auto 100px;font-size:clamp(40px,4.58vw,88px);font-weight:500;line-height:1.1;letter-spacing:-.07em;white-space:nowrap}.p05-hero-art{height:min(824px,43vw);max-width:1840px;margin:auto;overflow:hidden;border-radius:10px;background:#050506;display:flex;align-items:center;justify-content:center}.p05-hero-art img{width:min(1125px,72%);height:auto;object-fit:cover}.p05-overview{max-width:1200px;margin:100px auto 0;display:flex;justify-content:space-between;gap:70px}.p05-copy{max-width:665px}.p05-label{margin:0;color:var(--muted);font:16px/1.1 'DM Mono',monospace;letter-spacing:.01em;text-transform:uppercase}.p05-copy h2{margin:16px 0;font-size:24px;line-height:1.38;letter-spacing:-.04em}.p05-copy>p{margin:0;font-size:18px}.p05-overview>.p05-copy{width:409px}.p05-meta{display:grid;grid-template-columns:repeat(4,180px);width:720px}.p05-meta>div{font-size:18px}.p05-meta .p05-label{margin-bottom:10px}.p05-content{width:1200px;max-width:calc(100% - 40px);margin:auto;padding:40px 0}.p05-split{display:flex;gap:70px;justify-content:space-between;align-items:flex-start}.p05-small-media{width:440px;height:262px;flex:none;margin:0}.p05-media{padding:0;margin:40px 0;overflow:hidden;border-radius:10px;background:#d4d4d4}.p05-media img{width:100%;height:100%;display:block;object-fit:cover}.p05-wide-media{height:499px}.p05-tall-media{height:671px}.p05-features{width:100%}.p05-feature{display:flex;gap:140px;align-items:flex-start;min-height:775px;padding:40px 0}.p05-feature.reverse{flex-direction:row-reverse}.p05-feature>.p05-copy{width:510px;flex:none}.p05-device{width:378px;height:695px;flex:none;border-radius:30px;background:linear-gradient(155deg,#2d3042,#cbd4e5 70%,#eff2fb);padding:38px 24px;display:flex;align-items:center;box-shadow:inset 0 0 0 8px #f5f6fb}.p05-device-card{background:#fff;padding:24px 18px;border-radius:18px;box-shadow:0 16px 32px #29365038;display:flex;flex-direction:column;gap:13px}.p05-device-card small{font:11px 'DM Mono',monospace;color:#6170a1}.p05-device-card strong{font-size:25px}.p05-device-card span{font-size:13px;color:#777}.p05-quote{padding:120px 40px;text-align:center}.p05-quote h2{max-width:1300px;margin:18px auto 12px;font:clamp(34px,3.65vw,70px)/1.05 'DM Mono',monospace;letter-spacing:-.06em}.p05-quote>p{font-size:20px;margin:0}.p05-research>.p05-copy,.p05-interviews>.p05-copy,.p05-process>.p05-copy{margin-bottom:50px}.p05-image-grid{display:grid;grid-template-columns:1fr 1fr;gap:24px}.p05-image-grid .p05-media{height:440px;margin:40px 0}.p05-interviews .p05-image-grid .p05-media{height:310px;background:#e8e8f6}.p05-personas .p05-media{height:424px}.p05-define{padding-top:140px;padding-bottom:140px}.p05-ideate{padding-top:140px;padding-bottom:140px}.p05-process .p05-tall-media{height:766px}.p05-prototype-title{padding:110px 0 80px}.p05-prototype-title h2{font:clamp(32px,3vw,56px)/1.1 'DM Mono',monospace;letter-spacing:-.05em}.p05-prototype-title p{font-size:20px}.p05-prototype .p05-tall-media{height:703px}.p05-usability{padding-top:100px}.p05-result{font-size:18px;max-width:1200px;margin:55px 0 0}.p05-takeaways{padding:120px 0}.p05-takeaways ol{margin:30px 0 0;padding-left:22px;font-size:18px}.p05-takeaways li{padding:9px 0}.p05-footer{padding:150px max(40px,calc((100vw - 1200px)/2)) 40px}.p05-more{display:grid;grid-template-columns:1fr 1fr;gap:24px;margin:35px 0 100px}.p05-more a{border-top:1px solid #757575;padding-top:18px;display:flex;flex-direction:column;gap:8px}.p05-more b{font-size:22px}.p05-more span{font-size:16px}.p05-footer-bottom{border-top:1px solid #757575;padding-top:40px;display:flex;align-items:center;justify-content:space-between}.p05-footer-bottom small{color:var(--muted);font-size:16px}
@media(max-width:1000px){.p05-header{padding:16px 20px}.p05-header nav{gap:22px;font-size:14px}.p05-hero{padding:70px 20px}.p05-hero h1{white-space:normal;margin-bottom:50px}.p05-hero-art{height:480px}.p05-hero-art img{width:90%}.p05-overview,.p05-split,.p05-feature,.p05-feature.reverse{display:flex;flex-direction:column;gap:40px}.p05-overview{margin-top:60px}.p05-overview>.p05-copy,.p05-feature>.p05-copy,.p05-device{width:100%;flex:none}.p05-meta{width:100%;grid-template-columns:repeat(2,1fr);gap:30px}.p05-content{max-width:calc(100% - 40px)}.p05-small-media{width:100%;height:260px}.p05-feature{min-height:0}.p05-device{height:560px}.p05-quote{padding:90px 20px}.p05-quote h2{font-size:34px}.p05-image-grid,.p05-more{grid-template-columns:1fr}.p05-wide-media,.p05-tall-media,.p05-process .p05-tall-media,.p05-prototype .p05-tall-media{height:400px}.p05-footer{padding:90px 20px 30px}.p05-footer-bottom{align-items:flex-start;gap:20px;flex-direction:column}}