atomsystem 0.1.48 → 0.1.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +147 -55
  2. package/atom.design.md +155 -0
  3. package/atom.uxPattern.md +431 -0
  4. package/components/ui/Badge.tsx +20 -0
  5. package/components/ui/Button.tsx +33 -0
  6. package/components/ui/Card.tsx +20 -0
  7. package/components/ui/Input.tsx +35 -0
  8. package/components/ui/Modal.tsx +54 -0
  9. package/components/ui/index.ts +5 -0
  10. package/css/atom-ui.css +216 -0
  11. package/dist/cli.cjs +105 -0
  12. package/dist/cli.cjs.map +1 -0
  13. package/dist/cli.d.cts +1 -0
  14. package/dist/cli.d.ts +1 -0
  15. package/dist/cli.js +97 -0
  16. package/dist/cli.js.map +1 -0
  17. package/dist/index.cjs +7897 -0
  18. package/dist/index.cjs.map +1 -0
  19. package/dist/index.d.cts +218 -0
  20. package/dist/index.d.ts +218 -0
  21. package/dist/index.js +7845 -451
  22. package/dist/index.js.map +1 -0
  23. package/package.json +120 -81
  24. package/presets/default.design.md +155 -0
  25. package/presets/uxPattern.md +431 -0
  26. package/skills/atomsystem.skill.md +104 -0
  27. package/tokens/token.json +319 -0
  28. package/tokens/tokens.json +318 -976
  29. package/app/templates/Animations/Animation.tsx +0 -282
  30. package/app/templates/Badge/Badge.tsx +0 -28
  31. package/app/templates/Badge/badge.css +0 -28
  32. package/app/templates/Button/Button.tsx +0 -31
  33. package/app/templates/Button/button.css +0 -135
  34. package/app/templates/Card/Card.tsx +0 -50
  35. package/app/templates/Card/card.css +0 -17
  36. package/app/templates/Checkbox/Checkbox.tsx +0 -55
  37. package/app/templates/Checkbox/checkbox.css +0 -38
  38. package/app/templates/CodeBlock/CodeBlock.tsx +0 -68
  39. package/app/templates/Collapse/Collapse.tsx +0 -207
  40. package/app/templates/Collapse/collapse.css +0 -24
  41. package/app/templates/Dropdown/Dropdown.css +0 -112
  42. package/app/templates/Dropdown/Dropdown.tsx +0 -103
  43. package/app/templates/Input/Input.tsx +0 -29
  44. package/app/templates/Input/input.css +0 -24
  45. package/app/templates/Label/Label.tsx +0 -22
  46. package/app/templates/Modal/Modal.tsx +0 -71
  47. package/app/templates/Modal/modal.css +0 -98
  48. package/app/templates/Navigation/Navigation.tsx +0 -169
  49. package/app/templates/Navigation/navigation.css +0 -59
  50. package/app/templates/Pagination/Pagination.tsx +0 -104
  51. package/app/templates/Pagination/pagination.css +0 -66
  52. package/app/templates/Radio/Radio.tsx +0 -45
  53. package/app/templates/Radio/radio.css +0 -29
  54. package/app/templates/Select/Select.tsx +0 -143
  55. package/app/templates/Select/select.css +0 -47
  56. package/app/templates/Sidebar/Sidebar.tsx +0 -139
  57. package/app/templates/Sidebar/sidebar.css +0 -4
  58. package/app/templates/TOC/TOC.tsx +0 -165
  59. package/app/templates/Tab/Tab.tsx +0 -117
  60. package/app/templates/Tab/tab.css +0 -56
  61. package/app/templates/Table/Table.tsx +0 -54
  62. package/app/templates/Table/table.css +0 -58
  63. package/app/templates/Theme/Theme.tsx +0 -122
  64. package/app/templates/Toast/Toast.tsx +0 -106
  65. package/app/templates/Toast/toast.css +0 -69
  66. package/build/build-tokens.js +0 -223
  67. package/build/css/_variables.css +0 -251
  68. package/build/typescript/theme.ts +0 -6
  69. package/css/text.css +0 -18
@@ -1,98 +0,0 @@
1
- .modal-overlay {
2
- position: fixed;
3
- inset: 0;
4
- background-color: rgba(0, 0, 0, 0.4);
5
- display: flex;
6
- justify-content: center;
7
- align-items: center;
8
- z-index: 50;
9
- }
10
-
11
- .modal {
12
- background-color: var(--color-bg-card);
13
- padding: 0;
14
- border-radius: var(--radius-common);
15
- box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
16
- width: 100%;
17
- display: flex;
18
- flex-direction: column;
19
- color: var(--color-text-standard);
20
- border: 1px solid var(--color-border-standard);
21
- max-height: 90vh;
22
- }
23
-
24
- .modal-content {
25
- padding: var(--spacing-common-x);
26
- width: 100%;
27
- overflow-y: auto;
28
- flex: 1;
29
- }
30
-
31
- .modal-header {
32
- display: flex;
33
- justify-content: space-between;
34
- align-items: center;
35
- padding: var(--spacing-common-y) var(--spacing-common-x);
36
- border-bottom: 1px solid var(--color-border-standard);
37
- }
38
-
39
- .modal-title {
40
- font-size: var(--text-h6);
41
- font-weight: var(--font-weight-header);
42
- margin: 0;
43
- color: var(--color-text-standard);
44
- }
45
-
46
- .modal-close {
47
- cursor: pointer;
48
- background: transparent;
49
- border: none;
50
- color: var(--color-text-standard);
51
- display: flex;
52
- align-items: center;
53
- justify-content: center;
54
- padding: 0;
55
- transition: color 0.2s ease-in-out;
56
- }
57
-
58
- .modal-close:hover {
59
- color: var(--color-danger);
60
- }
61
-
62
- .modal-footer {
63
- display: flex;
64
- justify-content: flex-end;
65
- padding: var(--spacing-common-y) var(--spacing-common-x);
66
- border-top: 1px solid var(--color-border-standard);
67
- gap: var(--spacing-gap-small);
68
- }
69
-
70
- /* Modal Sizes */
71
- .modal-normal {
72
- max-width: 28rem; /* Tailwind max-w-md */
73
- }
74
-
75
- .modal-middle {
76
- max-width: 36rem; /* Tailwind max-w-xl */
77
- }
78
-
79
- .modal-large {
80
- max-width: 64rem; /* Tailwind max-w-5xl */
81
- }
82
-
83
- .modal-xl {
84
- max-width: 72rem; /* Tailwind max-w-6xl */
85
- }
86
-
87
- .modal-full {
88
- max-width: calc(100vw - (var(--spacing-common-x) * 2));
89
- }
90
-
91
- .modal-full-screen {
92
- width: 100vw;
93
- height: 100vh;
94
- max-height: 100vh;
95
- max-width: 100vw;
96
- border-radius: 0;
97
- border: none;
98
- }
@@ -1,169 +0,0 @@
1
- "use client"
2
-
3
- import Link from "next/link";
4
- import { usePathname } from "next/navigation";
5
- import gsap from 'gsap';
6
- import { useGSAP } from '@gsap/react';
7
- import { useRef, createContext, useContext, useState } from "react";
8
-
9
- // Icons
10
- import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
11
-
12
-
13
- gsap.registerPlugin(useGSAP); // register the hook to avoid React version discrepancies
14
-
15
- // Navigation을 베이스 interface로 정의
16
- export interface Navigation {
17
- children: React.ReactNode;
18
- }
19
-
20
- export interface NavLink extends Navigation {
21
- href: string;
22
- }
23
-
24
- /**
25
- * NavContextProps: 네비게이션 상태를 하위 컴포넌트와 공유하기 위한 인터페이스
26
- * - isOpen: 메뉴가 열려 있는지 여부
27
- * - setOpen: 메뉴 상태를 변경하는 함수
28
- */
29
- interface NavContextProps {
30
- isOpen: boolean;
31
- setOpen: (open: boolean) => void;
32
- }
33
-
34
- // NavContext: 상위 NavItem의 상태를 하 하위 NavTrigger와 NavContainer에 전달하는 통로(우체국)
35
- const NavContext = createContext<NavContextProps | undefined>(undefined);
36
-
37
- /**
38
- * useNavContext: Context 정보를 쉽고 안전하게 꺼내 쓰기 위한 전용 커스텀 훅
39
- * - 부모인 NavItem이 없을 경우(undefined)에도 에러가 나지 않도록 기본값을 반환하는 안전 장치 포함
40
- */
41
- const useNavContext = () => {
42
- const context = useContext(NavContext);
43
- if (!context) {
44
- // 부모를 찾지 못했을 때 앱이 멈추지 않도록 기본 상태 반환
45
- return { isOpen: false, setOpen: () => {} };
46
- }
47
- return context;
48
- };
49
-
50
- // 최상위 Navigation 레이아웃 컴포넌트
51
- const Navigation = ({ children }: Navigation) => {
52
- return (
53
- <nav className="nav-menu flex items-center justify-between">
54
- {children}
55
- </nav>
56
- )
57
- }
58
-
59
- // 로고나 브랜드명을 위한 컴포넌트
60
- const NavBrand = ({children, href}: NavLink) => {
61
- return (
62
- <Link href={href} className="flex items-center h-full font-bold text-xl">{children}</Link>
63
- )
64
- }
65
-
66
- /**
67
- * NavItem: 개별 메뉴 항목 및 서브 메뉴의 상태를 관리하는 부모 컨테이너
68
- * - 각각의 NavItem은 자신만의 isOpen 상태를 독립적으로 가짐
69
- */
70
- const NavItem = ({children}: Navigation) => {
71
- const [isOpen, setIsOpen] = useState(false);
72
- const setOpen = (open: boolean) => setIsOpen(open);
73
-
74
- // 마우스가 메뉴 전체 영역을 완전히 벗어날 때 호출 (메뉴 닫기)
75
- const handleMouseLeave = () => setIsOpen(false);
76
-
77
- return (
78
- <NavContext.Provider value={{ isOpen, setOpen }}>
79
- <li
80
- className={`nav-item`}
81
- onMouseLeave={handleMouseLeave}
82
- >
83
- {children}
84
- </li>
85
- </NavContext.Provider>
86
- )
87
- }
88
-
89
- // 메뉴 항목들을 가로로 정렬해주는 리스트 컨테이너
90
- const NavList = ({children}: Navigation) => {
91
- return (
92
- <ul className="flex items-center gap-0">{children}</ul>
93
- )
94
- }
95
-
96
- // 일반적인 링크 메뉴 컴포넌트
97
- const NavLink = ({children, href}: NavLink) => {
98
- const pathname = usePathname();
99
- const active = pathname === href;
100
-
101
- return (
102
- <Link href={href} className={`nav-link ${active ? "active" : ""}`}>{children}</Link>
103
- )
104
- }
105
-
106
- /**
107
- * NavTrigger: 서브 메뉴를 여는 트리거 버튼
108
- * - 마우스를 올렸을 때(onMouseEnter) 부모 NavItem의 상태를 열림(true)으로 변경
109
- */
110
- const NavTrigger = ({children}: Navigation) => {
111
- const { isOpen, setOpen } = useNavContext();
112
-
113
- // 트리거 영역에 진입했을 때만 메뉴 열기 실행
114
- const handleMouseEnter = () => setOpen(true);
115
-
116
- return (
117
- <div
118
- className="nav-link flex items-center gap-1"
119
- onMouseEnter={handleMouseEnter}
120
- >
121
- {children}
122
- {/* 상태에 따라 화살표 아이콘 회전 애니메이션 클래스 적용 */}
123
- <KeyboardArrowDownIcon className={`nav-arrow ${isOpen ? "open" : ""}`} />
124
- </div>
125
- )
126
- }
127
-
128
- /**
129
- * NavContainer: 서브 메뉴의 실제 내용물이 담기는 컨테이너
130
- * - GSAP을 사용하여 나타날 때 부드러운 애니메이션 효과 적용
131
- */
132
- const NavContainer = ({children}: Navigation) => {
133
- const { isOpen } = useNavContext();
134
- const containerContentRef = useRef<HTMLUListElement>(null);
135
-
136
- // 메뉴가 열릴 때 실행되는 GSAP 애니메이션
137
- useGSAP(() => {
138
- if (isOpen && containerContentRef.current) {
139
- gsap.fromTo(containerContentRef.current,
140
- { opacity: 0, y: -10 }, // 시작 상태: 투명하고 살짝 위쪽
141
- { opacity: 1, y: 0, duration: 0.2, ease: "power2.out" } // 도착 상태: 불투명하고 제자리
142
- );
143
- }
144
- }, [isOpen]);
145
-
146
-
147
- // 닫혀 있을 때는 아예 렌더링하지 않음
148
- if (!isOpen) return null;
149
-
150
- return (
151
- <div className="nav-container">
152
- {/* 실제 박스 형태를 가진 내부 리스트 */}
153
- <ul ref={containerContentRef} className="nav-content">
154
- {children}
155
- </ul>
156
- </div>
157
- )
158
- }
159
-
160
-
161
- export {
162
- Navigation,
163
- NavBrand,
164
- NavList,
165
- NavItem,
166
- NavLink,
167
- NavTrigger,
168
- NavContainer
169
- }
@@ -1,59 +0,0 @@
1
- .nav-menu{
2
- background-color: var(--bg-card);
3
- padding: 0 var(--spacing-common-x);
4
- border-bottom: 1px solid var(--border-standard);
5
- position: relative;
6
- }
7
-
8
- .nav-item{
9
- display: block;
10
- border-radius: var(--radius-common);
11
- padding: var(--spacing-common-y) 0;
12
- color: var(--text-standard);
13
- }
14
-
15
-
16
- .nav-link{
17
- display: block;
18
- padding: var(--spacing-common-y) var(--spacing-common-x);
19
- border-radius: var(--radius-common);
20
- cursor: pointer;
21
- }
22
-
23
- .nav-link:hover{
24
- background-color: var(--bg-hover);
25
- }
26
-
27
- .nav-link.active{
28
- color: var(--color-primary);
29
- }
30
-
31
- .nav-container {
32
- position: absolute;
33
- padding: var(--spacing-common-y) 0;
34
- top: 100%;
35
- left: 0;
36
- right: 0;
37
- width: 100%;
38
- z-index: 100;
39
- }
40
-
41
- .nav-content {
42
- display: flex;
43
- width: 100%;
44
- flex-wrap: wrap;
45
- gap: var(--spacing-common-x);
46
- background-color: var(--bg-card);
47
- border: 1px solid var(--border-standard);
48
- border-radius: var(--radius-common);
49
- padding: var(--spacing-common-y) var(--spacing-common-x);
50
- box-shadow: var(--shadow-standard);
51
- }
52
-
53
- .nav-arrow {
54
- transition: transform 0.2s ease;
55
- }
56
-
57
- .nav-arrow.open {
58
- transform: rotate(180deg);
59
- }
@@ -1,104 +0,0 @@
1
- "use client";
2
-
3
- import { useState } from "react";
4
-
5
- const Pagination = ({
6
- pageRange,
7
- pageViewRange,
8
- totalCount,
9
- pageTotal,
10
- currentPage,
11
- onPageChange,
12
- }: {
13
- currentPage: number;
14
- onPageChange: (page: number) => void;
15
- /** 페이지당 데이터 개수 정보를 받습니다. */
16
- pageViewRange: number;
17
- /** 페이지네이션을 보여줄 최대 개수정보를 받습니다. */
18
- pageRange: number;
19
- /** 데이터의 총 개수를 받아 페이지당 데이터 개수로 나누어 총 페이지네이션 정보를 계산합니다. */
20
- totalCount?: number;
21
- /** 전체 페이지네이션의 토탈 정보를 받습니다. */
22
- pageTotal?: number;
23
- }) => {
24
- const totalPages = pageTotal
25
- ? pageTotal
26
- : totalCount
27
- ? Math.ceil(totalCount / pageViewRange)
28
- : 0;
29
- const [pageStart, setPageStart] = useState(1);
30
- const scrollTop = () => {
31
- setTimeout(() => {
32
- window.scrollTo({ top: 0, behavior: "smooth" });
33
- }, 0);
34
- };
35
-
36
- return (
37
- <div className="pagination">
38
- <button
39
- disabled={pageStart === 1}
40
- onClick={() => {
41
- scrollTop();
42
- const newStart = Math.max(1, pageStart - pageRange);
43
- setPageStart(newStart);
44
- onPageChange(newStart);
45
- }}
46
- className="pagination-btn"
47
- >
48
- <span className="material-symbols-outlined">keyboard_arrow_left</span>
49
- </button>
50
- <ul className="pagination-list">
51
- {[...Array(pageRange)].map((_, i) => {
52
- const page = pageStart + i;
53
-
54
- const isFirstIndex = i === 0;
55
- const isLastIndex = i === pageRange - 1;
56
- const isLastPageInRange = page === totalPages;
57
-
58
- if (page > totalPages) return null;
59
-
60
- return (
61
- <li
62
- key={page}
63
- onClick={() => {
64
- onPageChange(page);
65
-
66
- // 첫 번째 인덱스 클릭 시 이전 범위로
67
- if (isFirstIndex && pageStart > 1) {
68
- setPageStart(Math.max(1, pageStart - pageRange + 1));
69
- }
70
-
71
- // 마지막 인덱스 클릭 시 다음 범위로
72
- if (isLastIndex && !isLastPageInRange) {
73
- setPageStart(pageStart + pageRange - 1);
74
- }
75
- scrollTop();
76
- }}
77
- className={`pagination-item ${
78
- currentPage === page ? "pagination-item-active" : ""
79
- }`}
80
- >
81
- {page}
82
- </li>
83
- );
84
- })}
85
- </ul>
86
- <button
87
- disabled={pageStart + pageRange > totalPages}
88
- onClick={() => {
89
- scrollTop();
90
- const newStart = pageStart + pageRange;
91
- if (newStart <= totalPages) {
92
- setPageStart(newStart);
93
- onPageChange(newStart);
94
- }
95
- }}
96
- className="pagination-btn"
97
- >
98
- <span className="material-symbols-outlined">keyboard_arrow_right</span>
99
- </button>
100
- </div>
101
- );
102
- };
103
-
104
- export default Pagination;
@@ -1,66 +0,0 @@
1
- .pagination {
2
- display: flex;
3
- align-items: center;
4
- color: var(--color-text-standard);
5
- }
6
-
7
- .pagination-btn {
8
- padding: var(--spacing-common-y) var(--spacing-common-x);
9
- cursor: pointer;
10
- background: transparent;
11
- border: none;
12
- border-radius: var(--radius-common);
13
- color: inherit;
14
- transition: all 0.2s ease;
15
- display: flex;
16
- align-items: center;
17
- justify-content: center;
18
- }
19
-
20
- .pagination-btn:hover:not(:disabled) {
21
- background-color: var(--color-pagination-bg-hover);
22
- color: var(--color-primary);
23
- }
24
-
25
- .pagination-btn:disabled {
26
- opacity: 0.4;
27
- cursor: not-allowed;
28
- color: var(--color-text-disabled);
29
- }
30
-
31
- .pagination-list {
32
- display: flex;
33
- width: 100%;
34
- list-style: none;
35
- padding: 0;
36
- margin: 0;
37
- }
38
-
39
- .pagination-item {
40
- flex: 1; /* w-full behavior mapped */
41
- text-align: center;
42
- padding: var(--spacing-common-y) var(--spacing-common-x);
43
- cursor: pointer;
44
- color: inherit;
45
- border-radius: var(--radius-common);
46
- transition: all 0.2s ease;
47
- user-select: none;
48
- display: flex;
49
- align-items: center;
50
- justify-content: center;
51
- }
52
-
53
- .pagination-item:hover {
54
- background-color: var(--color-pagination-bg-hover);
55
- color: var(--color-primary);
56
- }
57
-
58
- .pagination-item-active {
59
- color: var(--color-primary);
60
- font-weight: var(--font-weight-header);
61
- }
62
-
63
- .pagination-item-active:hover {
64
- background-color: transparent; /* Reset hover if it's the active one */
65
- cursor: default;
66
- }
@@ -1,45 +0,0 @@
1
- "use client";
2
- import clsx from "clsx";
3
- import "./radio.css";
4
-
5
- export const Radio = ({
6
- name,
7
- value,
8
- label,
9
- className,
10
- onChange,
11
- defaultChecked,
12
- checked,
13
- }: {
14
- name: string;
15
- value: string;
16
- label?: string;
17
- className?: string;
18
- onChange?: () => void;
19
- defaultChecked?: boolean;
20
- checked?: boolean;
21
- }) => {
22
- return (
23
- <>
24
- {label ? <p>{label}</p> : null}
25
- <label className="flex items-center gap-1 cursor-pointer">
26
- <input
27
- type="radio"
28
- className={clsx(
29
- "relative appearance-none radio rounded-full ",
30
- {
31
- "checked:bg-primary after:w-2.5 after:h-2.5 after:bg-[var(--color-bg-input-standard)] after:content-[''] after:absolute after:rounded-full after:left-1 after:top-1":
32
- true,
33
- },
34
- className
35
- )}
36
- name={name}
37
- onChange={onChange}
38
- defaultChecked={defaultChecked}
39
- checked={checked}
40
- />
41
- <span>{value}</span>
42
- </label>
43
- </>
44
- );
45
- };
@@ -1,29 +0,0 @@
1
- .radio{
2
- position: relative;
3
- width: var(--spacing-small);
4
- height: var(--spacing-small);
5
- border: 1px solid var(--color-border-standard);
6
- background: var(--color-bg-input-standard);
7
- color: var(--color-bg-input-standard);
8
- cursor: pointer;
9
- }
10
-
11
- .radio::after{
12
- content:'';
13
- position:absolute;
14
- left: 50%;
15
- top: 50%;
16
- transform: translate(-50%, -50%);
17
- width: var(--spacing-common-y);
18
- height: var(--spacing-common-y);
19
- border-radius: var(--radius-circle);
20
- }
21
-
22
- .radio:checked::after{
23
- background: var(--color-primary);
24
- }
25
-
26
- .radio:disabled {
27
- background: var(--color-bg-input-disabled);
28
- cursor: not-allowed;
29
- }