
Security News
GitHub Actions Checkout Now Blocks Risky pull_request_target Checkouts
GitHub Actions checkout now blocks risky pull_request_target checkouts by default to help prevent pwn request supply chain attacks.
Deprecated. Use tailwind-variants and next-themes: https://ilokesto.ayden94.com/ko/migrate/neato
neato is deprecated.
tailwind-variants for variants.next-themes for theming.Legacy reference is kept below for existing users only.
Language : English | 한국어
Tailwind CSS를 위한 완전한 스타일링 솔루션 - 클래스 관리부터 테마까지 모든 것을 하나로
npm install neato
yarn add neato
pnpm add neato
neato는 색상 변환을 위한 강력한 CLI 도구를 포함하고 있습니다.
라이트모드 색상을 다크모드에 적합한 색상으로 자동 변환:
npx neato toDark 3b82f6 ef4444 10b981
# 출력:
# #4d5fb8
# #b83c3c
# #0d8a5f
원하는 색상을 구현하는 CSS 필터를 계산:
npx neato toFilter 3b82f6
# 출력:
# Input Color: #3b82f6
# Filter: filter: invert(32%) sepia(77%) saturate(2815%) hue-rotate(217deg) brightness(101%) contrast(101%);
# Loss: 0.89
색상을 다크모드로 변환한 후 CSS 필터까지 생성:
npx neato toDarkFilter 3b82f6
# 출력:
# Input Color: #3b82f6
# Light Filter: filter: invert(32%) sepia(77%) saturate(2815%) hue-rotate(217deg) brightness(101%) contrast(101%);
# Light Filter Loss: 0.89
# Dark Mode Color: #4d5fb8
# Dark Filter: filter: invert(36%) sepia(41%) saturate(1042%) hue-rotate(211deg) brightness(95%) contrast(96%);
# Dark Filter Loss: 1.23
이러한 CLI 도구들은 디자인 시스템에서 일관된 색상 팔레트를 구축하고, 아이콘이나 SVG 요소에 동적 색상을 적용할 때 특히 유용합니다.
## 🛠️ Tailwind CSS IntelliSense 연동
Tailwind CSS 자동완성(IntelliSense)을 neato/neatoVariants 함수에서 사용하려면, 프로젝트 루트의 `.vscode/settings.json` 또는 VS Code의 전역 설정(`Ctrl/Cmd + ,` → `settings.json`)에 아래 설정을 추가하세요:
```jsonc
{
"tailwindCSS.experimental.classRegex": [
["neatoVariants\\(([^)]*)\\)", "[\"'`]([^\"'`]*)[\"'`]"] ,
["neato\\(([^)]*)\\)", "[\"'`]([^\"'`]*)[\"'`]"]
]
}
import { neato } from 'neato';
// 간단한 클래스 병합
const className = neato(
'px-4 py-2 rounded',
'bg-blue-500 text-white',
isActive && 'ring-2 ring-blue-300',
disabled && 'opacity-50 cursor-not-allowed'
);
// Tailwind 충돌 자동 해결
neato('px-2 px-4'); // → 'px-4' (나중 값이 우선)
neato('text-lg text-sm'); // → 'text-sm'
재사용 가능하고 타입 안전한 컴포넌트 스타일 생성:
import { neatoVariants } from 'neato';
const buttonStyles = neatoVariants({
base: 'inline-flex items-center justify-center rounded-md font-medium transition-colors focus:outline-none',
variants: {
variant: {
primary: 'bg-blue-600 text-white hover:bg-blue-700',
secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300',
outline: 'border border-gray-300 bg-transparent hover:bg-gray-50',
ghost: 'bg-transparent hover:bg-gray-100'
},
size: {
sm: 'h-8 px-3 text-sm',
md: 'h-10 px-4 text-base',
lg: 'h-12 px-6 text-lg'
}
},
compoundVariants: [
{
variant: 'outline',
size: 'lg',
className: 'border-2'
}
],
defaultVariants: {
variant: 'primary',
size: 'md'
}
});
// React에서 사용
function Button({ variant, size, className, ...props }) {
return (
<button
className={buttonStyles({ variant, size, className })}
{...props}
/>
);
}
// IntelliSense와 함께 완전한 타입 지원
<Button variant="secondary" size="lg" />
neato는 React 애플리케이션에서 쉽게 사용할 수 있는 완전한 테마 관리 시스템을 제공합니다.
import { ThemeProvider } from 'neato/theme';
import { createThemeScript } from 'neato/theme-script';
// 1. 앱 최상단에 Provider 설정
function App() {
return (
<ThemeProvider>
<YourComponents />
</ThemeProvider>
);
}
// 2. FOUC 방지를 위해 HTML head에 스크립트 추가 (Next.js 예시)
export default function RootLayout({ children }) {
return (
<html>
<head>
<script
dangerouslySetInnerHTML={{
__html: createThemeScript()
}}
/>
</head>
<body>
<ThemeProvider>
{children}
</ThemeProvider>
</body>
</html>
);
}
테마 시스템과 함께 사용하려면 다음과 같이 설정하세요:
Tailwind CSS v4 사용시:
global.css 또는 메인 CSS 파일에 다음을 추가:
@custom-variant dark (&:where(.dark, .dark *));
Tailwind CSS v3 사용시:
tailwind.config.js에 다음 설정을 추가:
module.exports = {
darkMode: ['class'],
content: [
'./src/**/*.{js,ts,jsx,tsx}',
// 다른 경로들...
],
theme: {
extend: {
// 커스텀 스타일 확장...
}
},
plugins: [
// 다른 플러그인들...
]
};
import { useTheme } from 'neato/theme';
function ThemeToggle() {
const { theme, setTheme, effectiveTheme, isHydrated } = useTheme();
return (
<div>
<button onClick={() => setTheme('light')}>
라이트 모드
</button>
<button onClick={() => setTheme('dark')}>
다크 모드
</button>
<button onClick={() => setTheme('system')}>
시스템 설정
</button>
<p>현재 테마: {theme}</p>
<p>적용된 테마: {effectiveTheme}</p>
</div>
);
}
// Tailwind CSS의 dark: modifier와 함께 사용
const cardStyles = neatoVariants({
base: 'p-6 rounded-lg border transition-colors',
variants: {
variant: {
default: 'bg-white border-gray-200 dark:bg-gray-800 dark:border-gray-700',
elevated: 'bg-white border-gray-200 shadow-lg dark:bg-gray-800 dark:border-gray-700'
}
}
});
function Card({ variant = 'default', children }) {
return (
<div className={cardStyles({ variant })}>
{children}
</div>
);
}
import { useTheme } from 'neato/theme';
function AdvancedThemeToggle() {
const { theme, setTheme, effectiveTheme } = useTheme();
const cycleTheme = () => {
if (theme === 'light') setTheme('dark');
else if (theme === 'dark') setTheme('system');
else setTheme('light');
};
const getIcon = () => {
if (theme === 'system') return '🌓';
return effectiveTheme === 'dark' ? '🌙' : '☀️';
};
const getLabel = () => {
if (theme === 'system') return '시스템';
return theme === 'dark' ? '다크' : '라이트';
};
return (
<button
onClick={cycleTheme}
className="flex items-center gap-2 px-3 py-2 rounded-lg bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors"
>
<span>{getIcon()}</span>
<span>{getLabel()}</span>
</button>
);
}
useTheme()테마 상태와 제어 함수를 반환합니다.
theme: 현재 설정된 테마 ('light' | 'dark' | 'system')
'light' - 라이트 모드 선택'dark' - 다크 모드 선택'system' - 시스템 설정을 따르도록 선택setTheme: 테마를 변경하는 함수
(theme: NeatoTheme) => voidsetTheme('dark'), setTheme('light'), setTheme('system')effectiveTheme: 실제로 적용된 테마 ('light' | 'dark')
theme이 'system'이고 사용자 OS가 다크모드인 경우 → effectiveTheme은 'dark'theme이 'light'인 경우 → effectiveTheme은 'light'isHydrated: 클라이언트 하이드레이션 완료 여부
booleantrue - 브라우저에서 JavaScript가 실행되어 테마 기능 사용 가능false - 서버 렌더링 중이거나 아직 하이드레이션 전 (테마 변경 비활성화)// 실제 사용 예시
function ThemeStatus() {
const { theme, setTheme, effectiveTheme, isHydrated } = useTheme();
if (!isHydrated) {
return <div>로딩 중...</div>; // 하이드레이션 전
}
return (
<div>
<p>설정된 테마: {theme}</p>
<p>실제 적용된 테마: {effectiveTheme}</p>
{/* 시스템 테마일 때는 실제 적용된 테마와 다를 수 있음 */}
{theme === 'system' && (
<p>시스템 설정을 따라 {effectiveTheme} 모드로 표시됩니다</p>
)}
</div>
);
}
createThemeScript()FOUC(Flash of Unstyled Content) 방지를 위한 인라인 스크립트 문자열을 생성합니다.
prefers-color-scheme 미디어 쿼리 지원neato(...inputs)Tailwind 충돌 자동 해결과 함께 클래스를 병합합니다.
neato(
'base-classes',
condition && 'conditional-classes',
{ 'class-name': boolean },
['array', 'of', 'classes'],
undefined, // 무시됨
null // 무시됨
);
neatoVariants(config)컴포넌트 스타일링을 위한 타입 안전한 variant 시스템을 생성합니다.
const styles = neatoVariants({
base: 'base-classes',
variants: {
variantName: {
option1: 'classes-for-option1',
option2: 'classes-for-option2'
}
},
compoundVariants: [
{
variantName: 'option1',
anotherVariant: 'value',
className: 'additional-classes'
}
],
defaultVariants: {
variantName: 'option1'
}
});
// 반환값: string
const className = styles({ variantName: 'option2' });
const cardStyles = neatoVariants({
container: {
base: 'rounded-lg border bg-white shadow-sm',
variants: {
size: { sm: 'p-4', md: 'p-6', lg: 'p-8' }
}
},
header: {
base: 'border-b pb-4 mb-4',
variants: {
align: { left: 'text-left', center: 'text-center', right: 'text-right' }
}
},
content: {
base: 'text-gray-700',
variants: {
spacing: { tight: 'space-y-2', normal: 'space-y-4', loose: 'space-y-6' }
}
}
});
// 각 슬롯별로 함수로 접근
cardStyles.container({ size: 'lg' }); // "rounded-lg border bg-white shadow-sm p-8"
cardStyles.header({ align: 'center', className: 'font-bold' }); // "border-b pb-4 mb-4 text-center font-bold"
cardStyles.content({ spacing: 'loose' }); // "text-gray-700 space-y-6"
이제 멀티 슬롯 컴포넌트에서 각 부분별 스타일을 독립적으로 사용할 수 있습니다.
const messageStyles = neatoVariants({
base: 'max-w-xs lg:max-w-md px-4 py-2 rounded-lg break-words',
variants: {
sender: {
user: 'bg-blue-500 text-white ml-auto',
other: 'bg-gray-200 text-gray-900 mr-auto'
},
status: {
sending: 'opacity-70',
sent: 'opacity-100',
failed: 'opacity-50 border border-red-300'
}
},
compoundVariants: [
{
sender: 'other',
status: 'sent',
className: 'shadow-sm'
}
]
});
function ChatMessage({ content, sender, status }) {
return (
<div className={messageStyles({ sender, status })}>
{content}
</div>
);
}
const cardStyles = neatoVariants({
container: {
base: 'rounded-lg border bg-white shadow-sm overflow-hidden',
variants: {
size: {
sm: 'p-4',
md: 'p-6',
lg: 'p-8'
}
}
},
header: {
base: 'border-b pb-4 mb-4',
variants: {
align: {
left: 'text-left',
center: 'text-center',
right: 'text-right'
}
}
},
content: {
base: 'text-gray-700',
variants: {
spacing: {
tight: 'space-y-2',
normal: 'space-y-4',
loose: 'space-y-6'
}
}
}
});
function Card({ size, headerAlign, contentSpacing, title, children }) {
return (
<div className={cardStyles.container({ size })}>
<header className={cardStyles.header({ align: headerAlign })}>
<h3>{title}</h3>
</header>
<div className={cardStyles.content({ spacing: contentSpacing })}>
{children}
</div>
</div>
);
}
// 장황하고 오류가 발생하기 쉬움
<div className={clsx(
'animate-slide-up-fade max-w-md rounded-md px-4 py-2 shadow',
isMine
? 'bg-blue-100 ml-auto justify-end'
: 'mr-auto justify-start',
!isMine && isConnected && 'ml-12',
hasError && 'border border-red-300',
className
)} />
// 깔끔하고 유지보수하기 쉬움
const messageStyles = neatoVariants({
base: 'animate-slide-up-fade max-w-md rounded-md px-4 py-2 shadow',
variants: {
owner: {
mine: 'bg-blue-100 ml-auto justify-end',
other: 'mr-auto justify-start'
},
connected: { true: '', false: '' },
error: { true: 'border border-red-300', false: '' }
},
compoundVariants: [
{
owner: 'other',
connected: true,
className: 'ml-12'
}
]
});
<div className={messageStyles({
owner: isMine ? 'mine' : 'other',
connected: isConnected,
error: hasError,
className
})} />
neato는 TypeScript로 구축되어 우수한 타입 안전성을 제공합니다:
// 완전한 타입 지원 variants
const styles = neatoVariants({
variants: {
size: {
sm: '...',
md: '...',
lg: '...'
}
}
});
// TypeScript가 유효한 옵션을 강제합니다
styles({ size: 'xl' }); // ❌ 오류: 'xl'은 할당할 수 없습니다
styles({ size: 'lg' }); // ✅ 유효함
neato는 모든 Tailwind CSS 설정과 잘 작동합니다. 최적의 성능을 위해 tailwind.config.js에 neato를 사용하는 모든 파일이 포함되어 있는지 확인하세요:
module.exports = {
content: [
'./src/**/*.{js,ts,jsx,tsx}',
// neato를 사용하는 다른 경로들도 추가
],
// ... 나머지 설정
};
MIT © Jeong Jinho
FAQs
Deprecated. Use tailwind-variants and next-themes: https://ilokesto.ayden94.com/ko/migrate/neato
We found that neato demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
GitHub Actions checkout now blocks risky pull_request_target checkouts by default to help prevent pwn request supply chain attacks.

Product
Socket now supports Custom Roles and Repository Access Permissions so organizations can control who can access specific repositories and actions.

Product
Socket MCP now lets AI assistants review org alerts, investigate threats using the Socket threat feed, and inspect package files in addition to dependency scoring.