podo-ui 0.4.2 → 0.4.5
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.
- package/AI-GUIDE.md +775 -0
- package/README.md +66 -0
- package/package.json +3 -2
- package/scss/typo/font-family.scss +9 -27
- package/readme.md +0 -64
- package/scss/typo/font/Pretendard-Black.woff2 +0 -0
- package/scss/typo/font/Pretendard-Bold.woff2 +0 -0
- package/scss/typo/font/Pretendard-ExtraBold.woff2 +0 -0
- package/scss/typo/font/Pretendard-ExtraLight.woff2 +0 -0
- package/scss/typo/font/Pretendard-Light.woff2 +0 -0
- package/scss/typo/font/Pretendard-Medium.woff2 +0 -0
- package/scss/typo/font/Pretendard-Regular.woff2 +0 -0
- package/scss/typo/font/Pretendard-SemiBold.woff2 +0 -0
- package/scss/typo/font/Pretendard-Thin.woff2 +0 -0
package/AI-GUIDE.md
ADDED
|
@@ -0,0 +1,775 @@
|
|
|
1
|
+
# Podo UI - AI Assistant Guide
|
|
2
|
+
|
|
3
|
+
> **For AI Assistants Only**: This guide provides essential information for AI assistants working with the Podo UI library. This document is distributed with the NPM package.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Package Overview
|
|
8
|
+
|
|
9
|
+
**Podo UI** is a hybrid SCSS-first design system with minimal React components.
|
|
10
|
+
|
|
11
|
+
- **Philosophy**: 97% CSS classes, 3% React components
|
|
12
|
+
- **Distribution**: NPM package with SCSS files and compiled React components
|
|
13
|
+
- **Main exports**: `/dist` (React), `/scss` (SCSS source), `/global.scss`, `/mixin.scss`
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Package Structure (NPM Distribution)
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
podo-ui/
|
|
21
|
+
├── dist/ # Compiled React components (TypeScript → JavaScript)
|
|
22
|
+
│ ├── index.js # Main entry point
|
|
23
|
+
│ ├── index.d.ts # TypeScript definitions
|
|
24
|
+
│ └── react/
|
|
25
|
+
│ ├── atom/ # Atomic components
|
|
26
|
+
│ │ ├── input.js
|
|
27
|
+
│ │ ├── textarea.js
|
|
28
|
+
│ │ ├── editor.js
|
|
29
|
+
│ │ └── editor-view.js
|
|
30
|
+
│ └── molecule/ # Molecular components
|
|
31
|
+
│ ├── field.js
|
|
32
|
+
│ └── pagination.js
|
|
33
|
+
├── scss/ # SCSS source files (DO NOT MODIFY)
|
|
34
|
+
│ ├── button/
|
|
35
|
+
│ ├── color/
|
|
36
|
+
│ ├── form/
|
|
37
|
+
│ ├── icon/
|
|
38
|
+
│ ├── layout/
|
|
39
|
+
│ ├── molecule/
|
|
40
|
+
│ └── typo/
|
|
41
|
+
├── global.scss # Global styles entry point
|
|
42
|
+
├── mixin.scss # SCSS functions and mixins
|
|
43
|
+
├── vite-fonts.scss # Vite-specific font paths
|
|
44
|
+
└── README.md # User documentation
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Import Patterns
|
|
50
|
+
|
|
51
|
+
### ✅ Correct Import Methods
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
// Named imports (recommended)
|
|
55
|
+
import { Input, Textarea, Editor, EditorView, Field, Pagination } from 'podo-ui';
|
|
56
|
+
|
|
57
|
+
// Direct imports (legacy, still supported)
|
|
58
|
+
import Input from 'podo-ui/react/atom/input';
|
|
59
|
+
import Field from 'podo-ui/react/molecule/field';
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### ❌ Incorrect Import Methods
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// DON'T: Import from dist directly
|
|
66
|
+
import Input from 'podo-ui/dist/react/atom/input';
|
|
67
|
+
|
|
68
|
+
// DON'T: Import from source files (not in NPM package)
|
|
69
|
+
import Input from 'podo-ui/react/atom/input.tsx';
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## SCSS Usage
|
|
75
|
+
|
|
76
|
+
### Global SCSS Import
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// main.tsx or App.tsx
|
|
80
|
+
import 'podo-ui/global.scss';
|
|
81
|
+
|
|
82
|
+
// If using Vite bundler
|
|
83
|
+
import 'podo-ui/vite-fonts.scss';
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### SCSS Module Usage
|
|
87
|
+
|
|
88
|
+
```scss
|
|
89
|
+
// component.module.scss
|
|
90
|
+
@use 'podo-ui/mixin' as *;
|
|
91
|
+
|
|
92
|
+
.myComponent {
|
|
93
|
+
// Design tokens (ALWAYS use these, not hardcoded values)
|
|
94
|
+
padding: s(5); // Spacing: s(0-13)
|
|
95
|
+
background: color(primary-base); // Color: color(semantic-variant)
|
|
96
|
+
border-radius: r(4); // Radius: r(1-full)
|
|
97
|
+
|
|
98
|
+
@include p1; // Typography: @include display1~7, p1~5
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Available Design Tokens
|
|
103
|
+
|
|
104
|
+
#### Spacing Function: `s(0-13)`
|
|
105
|
+
```
|
|
106
|
+
0: 0px 1: 2px 2: 4px 3: 8px 4: 12px
|
|
107
|
+
5: 16px 6: 24px 7: 32px 8: 40px 9: 48px
|
|
108
|
+
10: 64px 11: 80px 12: 96px 13: 160px
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
#### Color Function: `color(semantic-variant)`
|
|
112
|
+
```
|
|
113
|
+
Semantics: primary, default, default-deep, info, link, success, warning, danger
|
|
114
|
+
Variants: base, hover, pressed, focus, fill, reverse, outline
|
|
115
|
+
|
|
116
|
+
Examples:
|
|
117
|
+
color(primary-base)
|
|
118
|
+
color(danger-hover)
|
|
119
|
+
color(success-fill)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### Radius Function: `r(value)`
|
|
123
|
+
```
|
|
124
|
+
Values: 1, 2, 3, 4, full
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### Typography Mixins
|
|
128
|
+
```
|
|
129
|
+
Display: @include display1; @include display2; ... @include display7;
|
|
130
|
+
Paragraph: @include p1; @include p2; @include p3; @include p4; @include p5;
|
|
131
|
+
Semibold variants: @include p1-semibold; @include p2-semibold; etc.
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## React Components API
|
|
137
|
+
|
|
138
|
+
### Input Component
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
import { Input } from 'podo-ui';
|
|
142
|
+
import { z } from 'zod';
|
|
143
|
+
|
|
144
|
+
const emailSchema = z.string().email();
|
|
145
|
+
|
|
146
|
+
<Input
|
|
147
|
+
value={value}
|
|
148
|
+
onChange={setValue}
|
|
149
|
+
placeholder="Enter email"
|
|
150
|
+
validator={emailSchema} // Optional: Zod validator
|
|
151
|
+
withIcon="mail" // Optional: icon name
|
|
152
|
+
unit="원" // Optional: unit display
|
|
153
|
+
/>
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Props:**
|
|
157
|
+
- `value`: string
|
|
158
|
+
- `onChange`: (value: string) => void
|
|
159
|
+
- `placeholder`: string (optional)
|
|
160
|
+
- `validator`: Zod schema (optional)
|
|
161
|
+
- `withIcon`: string (optional) - icon name from icon system
|
|
162
|
+
- `unit`: string (optional) - display unit (e.g., "원", "kg")
|
|
163
|
+
- `disabled`: boolean (optional)
|
|
164
|
+
|
|
165
|
+
### Textarea Component
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
import { Textarea } from 'podo-ui';
|
|
169
|
+
|
|
170
|
+
<Textarea
|
|
171
|
+
value={value}
|
|
172
|
+
onChange={setValue}
|
|
173
|
+
placeholder="Enter description"
|
|
174
|
+
validator={schema} // Optional: Zod validator
|
|
175
|
+
/>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Props:** Similar to Input, without `withIcon` and `unit`
|
|
179
|
+
|
|
180
|
+
### Editor Component (WYSIWYG)
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
import { Editor } from 'podo-ui';
|
|
184
|
+
|
|
185
|
+
<Editor
|
|
186
|
+
value={htmlContent}
|
|
187
|
+
onChange={setHtmlContent}
|
|
188
|
+
height="400px" // Or "contents" for auto-height
|
|
189
|
+
placeholder="Enter content"
|
|
190
|
+
validator={schema} // Optional: Zod validator
|
|
191
|
+
/>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Props:**
|
|
195
|
+
- `value`: string (HTML content)
|
|
196
|
+
- `onChange`: (html: string) => void
|
|
197
|
+
- `height`: string | "contents" (optional, default: "400px")
|
|
198
|
+
- `placeholder`: string (optional)
|
|
199
|
+
- `validator`: Zod schema (optional)
|
|
200
|
+
|
|
201
|
+
**Features:**
|
|
202
|
+
- Rich text formatting (bold, italic, underline, strikethrough)
|
|
203
|
+
- Headers (H1-H6), paragraphs, blockquotes
|
|
204
|
+
- Text alignment, font, size, color
|
|
205
|
+
- Image upload and editing
|
|
206
|
+
- YouTube video embedding
|
|
207
|
+
- Resizable
|
|
208
|
+
|
|
209
|
+
### EditorView Component (Read-only)
|
|
210
|
+
|
|
211
|
+
```tsx
|
|
212
|
+
import { EditorView } from 'podo-ui';
|
|
213
|
+
|
|
214
|
+
<EditorView value={htmlContent} />
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Props:**
|
|
218
|
+
- `value`: string (HTML content from Editor)
|
|
219
|
+
|
|
220
|
+
**Purpose:** Display HTML content generated by Editor component in read-only mode.
|
|
221
|
+
|
|
222
|
+
### Field Component (Form Field Wrapper)
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
import { Field, Input } from 'podo-ui';
|
|
226
|
+
|
|
227
|
+
<Field
|
|
228
|
+
label="Email"
|
|
229
|
+
required
|
|
230
|
+
helper="Enter a valid email address"
|
|
231
|
+
validator={emailSchema}
|
|
232
|
+
value={email}
|
|
233
|
+
>
|
|
234
|
+
<Input value={email} onChange={setEmail} />
|
|
235
|
+
</Field>
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**Props:**
|
|
239
|
+
- `label`: string
|
|
240
|
+
- `required`: boolean (optional) - shows asterisk
|
|
241
|
+
- `helper`: string (optional) - helper text
|
|
242
|
+
- `validator`: Zod schema (optional)
|
|
243
|
+
- `value`: string (optional) - for validation display
|
|
244
|
+
- `children`: ReactNode - input component
|
|
245
|
+
|
|
246
|
+
### Pagination Component
|
|
247
|
+
|
|
248
|
+
```tsx
|
|
249
|
+
import { Pagination } from 'podo-ui';
|
|
250
|
+
|
|
251
|
+
<Pagination
|
|
252
|
+
currentPage={currentPage}
|
|
253
|
+
totalPages={10}
|
|
254
|
+
onPageChange={setCurrentPage}
|
|
255
|
+
/>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**Props:**
|
|
259
|
+
- `currentPage`: number
|
|
260
|
+
- `totalPages`: number
|
|
261
|
+
- `onPageChange`: (page: number) => void
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## CSS Classes (Utility Classes)
|
|
266
|
+
|
|
267
|
+
### Button Classes
|
|
268
|
+
|
|
269
|
+
```html
|
|
270
|
+
<!-- Semantic variants -->
|
|
271
|
+
<button class="primary">Primary</button>
|
|
272
|
+
<button class="default">Default</button>
|
|
273
|
+
<button class="info">Info</button>
|
|
274
|
+
<button class="success">Success</button>
|
|
275
|
+
<button class="warning">Warning</button>
|
|
276
|
+
<button class="danger">Danger</button>
|
|
277
|
+
<button class="link">Link</button>
|
|
278
|
+
|
|
279
|
+
<!-- Sizes -->
|
|
280
|
+
<button class="primary small">Small</button>
|
|
281
|
+
<button class="primary large">Large</button>
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Form Elements
|
|
285
|
+
|
|
286
|
+
```html
|
|
287
|
+
<!-- Input -->
|
|
288
|
+
<input type="text" placeholder="Text input" />
|
|
289
|
+
|
|
290
|
+
<!-- Textarea -->
|
|
291
|
+
<textarea placeholder="Textarea"></textarea>
|
|
292
|
+
|
|
293
|
+
<!-- Select -->
|
|
294
|
+
<select>
|
|
295
|
+
<option>Option 1</option>
|
|
296
|
+
<option>Option 2</option>
|
|
297
|
+
</select>
|
|
298
|
+
|
|
299
|
+
<!-- Checkbox -->
|
|
300
|
+
<label>
|
|
301
|
+
<input type="checkbox" />
|
|
302
|
+
Checkbox label
|
|
303
|
+
</label>
|
|
304
|
+
|
|
305
|
+
<!-- Radio -->
|
|
306
|
+
<label>
|
|
307
|
+
<input type="radio" name="group" />
|
|
308
|
+
Radio label
|
|
309
|
+
</label>
|
|
310
|
+
|
|
311
|
+
<!-- Toggle -->
|
|
312
|
+
<label>
|
|
313
|
+
<input type="checkbox" role="switch" />
|
|
314
|
+
Toggle switch
|
|
315
|
+
</label>
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Grid System
|
|
319
|
+
|
|
320
|
+
```html
|
|
321
|
+
<!-- Auto-wrapping grid -->
|
|
322
|
+
<div class="grid">
|
|
323
|
+
<div class="w-4">Column 1 (4/12)</div>
|
|
324
|
+
<div class="w-8">Column 2 (8/12)</div>
|
|
325
|
+
</div>
|
|
326
|
+
|
|
327
|
+
<!-- Fixed column grid -->
|
|
328
|
+
<div class="grid-fix-3">
|
|
329
|
+
<div>Item 1</div>
|
|
330
|
+
<div>Item 2</div>
|
|
331
|
+
<div>Item 3</div>
|
|
332
|
+
</div>
|
|
333
|
+
|
|
334
|
+
<!-- Width utilities -->
|
|
335
|
+
<div class="w-6">50% width (6/12)</div>
|
|
336
|
+
<div class="w-200px">200px width</div>
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**Grid columns:**
|
|
340
|
+
- PC: 12 columns
|
|
341
|
+
- Tablet: 6 columns
|
|
342
|
+
- Mobile: 4 columns
|
|
343
|
+
|
|
344
|
+
**Width classes:**
|
|
345
|
+
- `.w-1` to `.w-12` (column-based)
|
|
346
|
+
- `.w-1_4`, `.w-2_6`, etc. (fraction-based)
|
|
347
|
+
- `.w-{n}px` (0-5000, pixel-based)
|
|
348
|
+
|
|
349
|
+
### Spacing Utilities
|
|
350
|
+
|
|
351
|
+
```html
|
|
352
|
+
<!-- Padding -->
|
|
353
|
+
<div class="p-5">Padding 16px all sides</div>
|
|
354
|
+
<div class="p-t-3">Padding-top 8px</div>
|
|
355
|
+
<div class="p-l-4 p-r-4">Padding left/right 12px</div>
|
|
356
|
+
|
|
357
|
+
<!-- Margin -->
|
|
358
|
+
<div class="m-6">Margin 24px all sides</div>
|
|
359
|
+
<div class="m-b-7">Margin-bottom 32px</div>
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**Pattern:** `{property}-{direction?}-{value}`
|
|
363
|
+
- Property: `p` (padding), `m` (margin)
|
|
364
|
+
- Direction: `t` (top), `b` (bottom), `l` (left), `r` (right), `x` (horizontal), `y` (vertical), or omit for all
|
|
365
|
+
- Value: 0-13 (see spacing scale above)
|
|
366
|
+
|
|
367
|
+
### Border Radius Utilities
|
|
368
|
+
|
|
369
|
+
```html
|
|
370
|
+
<div class="r-2">Small radius</div>
|
|
371
|
+
<div class="r-4">Medium radius</div>
|
|
372
|
+
<div class="r-full">Full rounded (pill shape)</div>
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Icon System
|
|
376
|
+
|
|
377
|
+
```html
|
|
378
|
+
<i class="icon-star"></i>
|
|
379
|
+
<i class="icon-heart-fill"></i>
|
|
380
|
+
<i class="icon-check"></i>
|
|
381
|
+
<i class="icon-x"></i>
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
**Complete Icon List (117 icons):**
|
|
385
|
+
|
|
386
|
+
```
|
|
387
|
+
// Basic Actions
|
|
388
|
+
icon-plus icon-minus icon-close
|
|
389
|
+
icon-check icon-check-small icon-cancel
|
|
390
|
+
icon-edit icon-save icon-delete
|
|
391
|
+
icon-trash icon-refresh
|
|
392
|
+
|
|
393
|
+
// Arrows
|
|
394
|
+
icon-arrow-up icon-arrow-down icon-arrow-left
|
|
395
|
+
icon-arrow-right icon-arrow-dropdown icon-arrow-dropdown-up
|
|
396
|
+
icon-arrow-dropdown-left icon-arrow-dropdown-right
|
|
397
|
+
|
|
398
|
+
// Expand/Collapse
|
|
399
|
+
icon-expand-up icon-expand-down icon-expand-left
|
|
400
|
+
icon-expand-right icon-expand-up-double icon-expand-down-double
|
|
401
|
+
icon-expand-left-double icon-expand-right-double
|
|
402
|
+
|
|
403
|
+
// Navigation
|
|
404
|
+
icon-home icon-menu icon-search
|
|
405
|
+
icon-more icon-more-horizontal icon-map
|
|
406
|
+
icon-compass icon-gps
|
|
407
|
+
|
|
408
|
+
// Communication
|
|
409
|
+
icon-mail icon-email icon-phone
|
|
410
|
+
icon-phone-stroke icon-dm icon-share
|
|
411
|
+
icon-notification icon-notification-stroke
|
|
412
|
+
|
|
413
|
+
// User & Social
|
|
414
|
+
icon-user icon-user-stroke icon-counselor
|
|
415
|
+
icon-facebook icon-naver icon-insta
|
|
416
|
+
icon-tiktok icon-apple icon-google
|
|
417
|
+
icon-youtube icon-kakao icon-x
|
|
418
|
+
|
|
419
|
+
// Files & Documents
|
|
420
|
+
icon-file icon-paper icon-clip
|
|
421
|
+
icon-upload icon-download icon-upload-cloud
|
|
422
|
+
icon-import icon-export icon-excel
|
|
423
|
+
icon-img icon-print
|
|
424
|
+
|
|
425
|
+
// UI Elements
|
|
426
|
+
icon-star icon-star-fill icon-favorite
|
|
427
|
+
icon-favorite-fill icon-ellipse icon-ellipse-stroke
|
|
428
|
+
icon-tag icon-flag icon-flag-finish
|
|
429
|
+
icon-pin icon-link icon-link-alt
|
|
430
|
+
icon-new-window icon-calendar icon-time
|
|
431
|
+
icon-show icon-hidden icon-lock
|
|
432
|
+
icon-unlock icon-drag icon-handle
|
|
433
|
+
|
|
434
|
+
// Status & Feedback
|
|
435
|
+
icon-check-circle-stroke icon-check-circle-fill icon-info
|
|
436
|
+
icon-warning icon-danger icon-danger-fill
|
|
437
|
+
icon-help icon-fordid
|
|
438
|
+
|
|
439
|
+
// Business & Commerce
|
|
440
|
+
icon-card icon-briefcase icon-receipt
|
|
441
|
+
icon-coin icon-currency icon-car
|
|
442
|
+
icon-chart icon-chart-bar icon-pyramid-chart
|
|
443
|
+
|
|
444
|
+
// Tools & Settings
|
|
445
|
+
icon-setting icon-setting-stroke icon-zoom-in
|
|
446
|
+
icon-zoom-out icon-hand icon-global
|
|
447
|
+
|
|
448
|
+
// Technical/Specialized
|
|
449
|
+
icon-layers icon-ruler icon-contour
|
|
450
|
+
icon-temperature icon-turbine icon-pressure
|
|
451
|
+
icon-exchange-horizontally icon-exchange-vertical
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
**Usage Pattern:**
|
|
455
|
+
- Class name format: `icon-{name}`
|
|
456
|
+
- All icons are from a custom icon font
|
|
457
|
+
- Icons inherit font-size and color from parent element
|
|
458
|
+
- Use filled variants (e.g., `icon-star-fill`) for solid icons
|
|
459
|
+
- Use stroke variants (e.g., `icon-user-stroke`) for outline icons
|
|
460
|
+
|
|
461
|
+
**Styling Icons:**
|
|
462
|
+
|
|
463
|
+
```html
|
|
464
|
+
<!-- Size control via font-size -->
|
|
465
|
+
<i class="icon-star" style="font-size: 24px;"></i>
|
|
466
|
+
|
|
467
|
+
<!-- Color control via color -->
|
|
468
|
+
<i class="icon-heart-fill" style="color: red;"></i>
|
|
469
|
+
|
|
470
|
+
<!-- Using with SCSS -->
|
|
471
|
+
<style>
|
|
472
|
+
.my-icon {
|
|
473
|
+
font-size: s(6); /* 24px */
|
|
474
|
+
color: color(primary-base);
|
|
475
|
+
}
|
|
476
|
+
</style>
|
|
477
|
+
<i class="icon-check my-icon"></i>
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
482
|
+
## Theme System
|
|
483
|
+
|
|
484
|
+
### Dark Mode Toggle
|
|
485
|
+
|
|
486
|
+
```html
|
|
487
|
+
<!-- Light mode -->
|
|
488
|
+
<html data-color-mode="light">
|
|
489
|
+
|
|
490
|
+
<!-- Dark mode -->
|
|
491
|
+
<html data-color-mode="dark">
|
|
492
|
+
|
|
493
|
+
<!-- Auto (follows system preference) -->
|
|
494
|
+
<html data-color-mode="">
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### Color Tone (Optional)
|
|
498
|
+
|
|
499
|
+
```html
|
|
500
|
+
<!-- Default tone -->
|
|
501
|
+
<html data-color-tone="">
|
|
502
|
+
|
|
503
|
+
<!-- Warm tone -->
|
|
504
|
+
<html data-color-tone="warm">
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
## Common Mistakes to Avoid
|
|
510
|
+
|
|
511
|
+
### ❌ Mistake 1: Hardcoded Values in SCSS
|
|
512
|
+
|
|
513
|
+
```scss
|
|
514
|
+
// BAD
|
|
515
|
+
.component {
|
|
516
|
+
padding: 16px;
|
|
517
|
+
background: #007bff;
|
|
518
|
+
border-radius: 8px;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// GOOD
|
|
522
|
+
@use 'podo-ui/mixin' as *;
|
|
523
|
+
|
|
524
|
+
.component {
|
|
525
|
+
padding: s(5);
|
|
526
|
+
background: color(primary-base);
|
|
527
|
+
border-radius: r(4);
|
|
528
|
+
}
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
### ❌ Mistake 2: Modifying Distributed Files
|
|
532
|
+
|
|
533
|
+
```bash
|
|
534
|
+
# BAD - Don't modify files in node_modules
|
|
535
|
+
Edit: node_modules/podo-ui/dist/react/atom/input.js
|
|
536
|
+
Edit: node_modules/podo-ui/scss/button/layout.scss
|
|
537
|
+
|
|
538
|
+
# GOOD - Override with your own styles
|
|
539
|
+
Create: src/styles/custom-button.module.scss
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
### ❌ Mistake 3: Incorrect Import Paths
|
|
543
|
+
|
|
544
|
+
```typescript
|
|
545
|
+
// BAD
|
|
546
|
+
import { Input } from 'podo-ui/dist/index';
|
|
547
|
+
import Input from 'podo-ui/react/atom/input.tsx';
|
|
548
|
+
|
|
549
|
+
// GOOD
|
|
550
|
+
import { Input } from 'podo-ui';
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### ❌ Mistake 4: Missing SCSS Import
|
|
554
|
+
|
|
555
|
+
```tsx
|
|
556
|
+
// BAD - Using components without importing global styles
|
|
557
|
+
import { Input } from 'podo-ui';
|
|
558
|
+
|
|
559
|
+
function App() {
|
|
560
|
+
return <Input value="" onChange={() => {}} />;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// GOOD - Import global styles first
|
|
564
|
+
import 'podo-ui/global.scss';
|
|
565
|
+
import { Input } from 'podo-ui';
|
|
566
|
+
|
|
567
|
+
function App() {
|
|
568
|
+
return <Input value="" onChange={() => {}} />;
|
|
569
|
+
}
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
---
|
|
573
|
+
|
|
574
|
+
## Vite-Specific Configuration
|
|
575
|
+
|
|
576
|
+
When using **Vite** bundler, import the font path fix:
|
|
577
|
+
|
|
578
|
+
```typescript
|
|
579
|
+
// main.tsx (Vite projects only)
|
|
580
|
+
import 'podo-ui/global.scss';
|
|
581
|
+
import 'podo-ui/vite-fonts.scss'; // Required for Vite
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
**Why?** Vite has different font path resolution. This file corrects the paths for icon font and Pretendard font.
|
|
585
|
+
|
|
586
|
+
**Not needed for:** Next.js, Create React App, or other bundlers.
|
|
587
|
+
|
|
588
|
+
---
|
|
589
|
+
|
|
590
|
+
## TypeScript Support
|
|
591
|
+
|
|
592
|
+
All React components include TypeScript definitions:
|
|
593
|
+
|
|
594
|
+
```typescript
|
|
595
|
+
import { Input, Field, Editor } from 'podo-ui';
|
|
596
|
+
import type { InputProps, FieldProps, EditorProps } from 'podo-ui';
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
Type definitions are located at:
|
|
600
|
+
- `podo-ui/dist/index.d.ts`
|
|
601
|
+
- `podo-ui/dist/react/atom/*.d.ts`
|
|
602
|
+
- `podo-ui/dist/react/molecule/*.d.ts`
|
|
603
|
+
|
|
604
|
+
---
|
|
605
|
+
|
|
606
|
+
## Validation with Zod
|
|
607
|
+
|
|
608
|
+
All input components support Zod schema validation:
|
|
609
|
+
|
|
610
|
+
```typescript
|
|
611
|
+
import { Input } from 'podo-ui';
|
|
612
|
+
import { z } from 'zod';
|
|
613
|
+
|
|
614
|
+
const schema = z.string()
|
|
615
|
+
.min(2, 'Minimum 2 characters')
|
|
616
|
+
.max(50, 'Maximum 50 characters')
|
|
617
|
+
.email('Invalid email format');
|
|
618
|
+
|
|
619
|
+
<Input
|
|
620
|
+
value={email}
|
|
621
|
+
onChange={setEmail}
|
|
622
|
+
validator={schema}
|
|
623
|
+
/>
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
**Visual feedback:**
|
|
627
|
+
- ✅ Valid input: green border
|
|
628
|
+
- ❌ Invalid input: red border
|
|
629
|
+
- Error message displayed below input
|
|
630
|
+
|
|
631
|
+
---
|
|
632
|
+
|
|
633
|
+
## Framework Compatibility
|
|
634
|
+
|
|
635
|
+
### React / Next.js
|
|
636
|
+
|
|
637
|
+
```typescript
|
|
638
|
+
import 'podo-ui/global.scss';
|
|
639
|
+
import { Input, Editor, Field } from 'podo-ui';
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
### Vite + React
|
|
643
|
+
|
|
644
|
+
```typescript
|
|
645
|
+
import 'podo-ui/global.scss';
|
|
646
|
+
import 'podo-ui/vite-fonts.scss'; // Important!
|
|
647
|
+
import { Input, Editor, Field } from 'podo-ui';
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
### Vue / Angular / Vanilla JS
|
|
651
|
+
|
|
652
|
+
Use CSS classes only. React components are React-specific and won't work in other frameworks.
|
|
653
|
+
|
|
654
|
+
```html
|
|
655
|
+
<!-- Works in any framework -->
|
|
656
|
+
<button class="primary">Click me</button>
|
|
657
|
+
<input type="text" placeholder="Email" />
|
|
658
|
+
<div class="grid">
|
|
659
|
+
<div class="w-6">Column 1</div>
|
|
660
|
+
<div class="w-6">Column 2</div>
|
|
661
|
+
</div>
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
---
|
|
665
|
+
|
|
666
|
+
## Performance Considerations
|
|
667
|
+
|
|
668
|
+
### Tree Shaking
|
|
669
|
+
|
|
670
|
+
Named imports support tree shaking:
|
|
671
|
+
|
|
672
|
+
```typescript
|
|
673
|
+
// Only Input code is included in bundle
|
|
674
|
+
import { Input } from 'podo-ui';
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
### CSS Size
|
|
678
|
+
|
|
679
|
+
Global CSS is ~50KB minified. Consider:
|
|
680
|
+
- Importing only needed SCSS modules if building custom bundle
|
|
681
|
+
- Using PurgeCSS to remove unused classes in production
|
|
682
|
+
|
|
683
|
+
---
|
|
684
|
+
|
|
685
|
+
## Debugging Checklist
|
|
686
|
+
|
|
687
|
+
### Styles not appearing?
|
|
688
|
+
|
|
689
|
+
```
|
|
690
|
+
□ Did you import 'podo-ui/global.scss'?
|
|
691
|
+
□ For Vite: Did you import 'podo-ui/vite-fonts.scss'?
|
|
692
|
+
□ Are you using correct class names?
|
|
693
|
+
□ Check browser console for CSS loading errors
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
### React components not working?
|
|
697
|
+
|
|
698
|
+
```
|
|
699
|
+
□ Is React version ≥18?
|
|
700
|
+
□ Did you import from 'podo-ui' correctly?
|
|
701
|
+
□ For Editor: Is it a client component (Next.js)?
|
|
702
|
+
□ Check browser console for JavaScript errors
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
### TypeScript errors?
|
|
706
|
+
|
|
707
|
+
```
|
|
708
|
+
□ Are type definitions installed (should be automatic)?
|
|
709
|
+
□ Try restarting TypeScript server
|
|
710
|
+
□ Check that you're importing from correct paths
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
---
|
|
714
|
+
|
|
715
|
+
## Quick Reference
|
|
716
|
+
|
|
717
|
+
### Essential Imports
|
|
718
|
+
|
|
719
|
+
```typescript
|
|
720
|
+
// Global styles (required)
|
|
721
|
+
import 'podo-ui/global.scss';
|
|
722
|
+
|
|
723
|
+
// Vite users only
|
|
724
|
+
import 'podo-ui/vite-fonts.scss';
|
|
725
|
+
|
|
726
|
+
// React components
|
|
727
|
+
import { Input, Textarea, Editor, EditorView, Field, Pagination } from 'podo-ui';
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
### Essential Design Tokens
|
|
731
|
+
|
|
732
|
+
```scss
|
|
733
|
+
@use 'podo-ui/mixin' as *;
|
|
734
|
+
|
|
735
|
+
.component {
|
|
736
|
+
padding: s(5); // Spacing
|
|
737
|
+
color: color(primary-base); // Color
|
|
738
|
+
border-radius: r(4); // Radius
|
|
739
|
+
@include p1; // Typography
|
|
740
|
+
}
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
### Essential CSS Classes
|
|
744
|
+
|
|
745
|
+
```html
|
|
746
|
+
<button class="primary">Button</button>
|
|
747
|
+
<div class="grid">
|
|
748
|
+
<div class="w-6">50%</div>
|
|
749
|
+
<div class="w-6">50%</div>
|
|
750
|
+
</div>
|
|
751
|
+
<div class="p-5 m-t-4">Padding 16px, margin-top 12px</div>
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
---
|
|
755
|
+
|
|
756
|
+
## Support
|
|
757
|
+
|
|
758
|
+
- **Documentation**: https://podoui.com
|
|
759
|
+
- **GitHub**: https://github.com/hada0127/podo-ui
|
|
760
|
+
- **Issues**: https://github.com/hada0127/podo-ui/issues
|
|
761
|
+
|
|
762
|
+
---
|
|
763
|
+
|
|
764
|
+
## Summary
|
|
765
|
+
|
|
766
|
+
**For AI Assistants:**
|
|
767
|
+
1. **Always** use design tokens (s, color, r) in SCSS, never hardcoded values
|
|
768
|
+
2. **Always** import 'podo-ui/global.scss' before using any components or classes
|
|
769
|
+
3. **Vite users** must also import 'podo-ui/vite-fonts.scss'
|
|
770
|
+
4. **Import components** using named imports from 'podo-ui'
|
|
771
|
+
5. **Never modify** files in node_modules/podo-ui
|
|
772
|
+
6. **Use CSS classes** for framework-agnostic styling
|
|
773
|
+
7. **Use React components** only when validation or complex interaction is needed
|
|
774
|
+
|
|
775
|
+
This library prioritizes CSS-first design with minimal JavaScript, ensuring maximum compatibility and performance.
|
package/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Podo UI
|
|
2
|
+
|
|
3
|
+
> Modern SCSS Module-based Design System
|
|
4
|
+
|
|
5
|
+
English | [한국어](./README.ko.md)
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install podo-ui
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
### Apply Global SCSS
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
// main.tsx
|
|
19
|
+
import 'podo-ui/global.scss';
|
|
20
|
+
import 'podo-ui/vite-fonts.scss'; // When using Vite
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Use in SCSS Modules
|
|
24
|
+
|
|
25
|
+
```scss
|
|
26
|
+
// component.module.scss
|
|
27
|
+
@use 'podo-ui/mixin' as *;
|
|
28
|
+
|
|
29
|
+
.myComponent {
|
|
30
|
+
color: color(primary);
|
|
31
|
+
margin: s(4);
|
|
32
|
+
border-radius: r(2);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### React Components
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
// Import individual components using named imports
|
|
40
|
+
import { Input, Textarea, Editor, EditorView, Field, Pagination } from 'podo-ui';
|
|
41
|
+
|
|
42
|
+
// Or import components directly (legacy method)
|
|
43
|
+
import Input from 'podo-ui/react/atom/input';
|
|
44
|
+
import Field from 'podo-ui/react/molecule/field';
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Key Features
|
|
48
|
+
|
|
49
|
+
- CSS class-based design system
|
|
50
|
+
- Responsive grid system (PC 12, Tablet 6, Mobile 4)
|
|
51
|
+
- Color system with dark mode support
|
|
52
|
+
- React components (Input, Textarea, Editor, Field)
|
|
53
|
+
|
|
54
|
+
## Documentation
|
|
55
|
+
|
|
56
|
+
For detailed usage, please refer to the [official documentation](https://podoui.com).
|
|
57
|
+
|
|
58
|
+
## Links
|
|
59
|
+
|
|
60
|
+
- [Official Documentation](https://podoui.com)
|
|
61
|
+
- [GitHub Repository](https://github.com/hada0127/podo-ui)
|
|
62
|
+
- [Report Issues](https://github.com/hada0127/podo-ui/issues)
|
|
63
|
+
|
|
64
|
+
## License
|
|
65
|
+
|
|
66
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "podo-ui",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "hada0127 <work@tarucy.net>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"global.d.ts",
|
|
22
22
|
"mixin.scss",
|
|
23
23
|
"vite-fonts.scss",
|
|
24
|
-
"README.md"
|
|
24
|
+
"README.md",
|
|
25
|
+
"AI-GUIDE.md"
|
|
25
26
|
],
|
|
26
27
|
"exports": {
|
|
27
28
|
".": {
|
|
@@ -1,80 +1,62 @@
|
|
|
1
1
|
@font-face {
|
|
2
2
|
font-family: 'Pretendard';
|
|
3
3
|
font-weight: 900;
|
|
4
|
-
src:
|
|
5
|
-
local('Pretendard Black'),
|
|
6
|
-
url(./font/Pretendard-Black.woff2) format('woff2');
|
|
4
|
+
src: url('https://cdn.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Black.woff') format('woff');
|
|
7
5
|
font-display: swap;
|
|
8
6
|
}
|
|
9
7
|
|
|
10
8
|
@font-face {
|
|
11
9
|
font-family: 'Pretendard';
|
|
12
10
|
font-weight: 800;
|
|
13
|
-
src:
|
|
14
|
-
local('Pretendard ExtraBold'),
|
|
15
|
-
url(./font/Pretendard-ExtraBold.woff2) format('woff2');
|
|
11
|
+
src: url('https://cdn.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-ExtraBold.woff') format('woff');
|
|
16
12
|
font-display: swap;
|
|
17
13
|
}
|
|
18
14
|
|
|
19
15
|
@font-face {
|
|
20
16
|
font-family: 'Pretendard';
|
|
21
17
|
font-weight: 700;
|
|
22
|
-
src:
|
|
23
|
-
local('Pretendard Bold'),
|
|
24
|
-
url(./font/Pretendard-Bold.woff2) format('woff2');
|
|
18
|
+
src: url('https://cdn.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Bold.woff') format('woff');
|
|
25
19
|
font-display: swap;
|
|
26
20
|
}
|
|
27
21
|
|
|
28
22
|
@font-face {
|
|
29
23
|
font-family: 'Pretendard';
|
|
30
24
|
font-weight: 600;
|
|
31
|
-
src:
|
|
32
|
-
local('Pretendard SemiBold'),
|
|
33
|
-
url(./font/Pretendard-SemiBold.woff2) format('woff2');
|
|
25
|
+
src: url('https://cdn.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-SemiBold.woff') format('woff');
|
|
34
26
|
font-display: swap;
|
|
35
27
|
}
|
|
36
28
|
|
|
37
29
|
@font-face {
|
|
38
30
|
font-family: 'Pretendard';
|
|
39
31
|
font-weight: 500;
|
|
40
|
-
src:
|
|
41
|
-
local('Pretendard Medium'),
|
|
42
|
-
url(./font/Pretendard-Medium.woff2) format('woff2');
|
|
32
|
+
src: url('https://cdn.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Medium.woff') format('woff');
|
|
43
33
|
font-display: swap;
|
|
44
34
|
}
|
|
45
35
|
|
|
46
36
|
@font-face {
|
|
47
37
|
font-family: 'Pretendard';
|
|
48
38
|
font-weight: 400;
|
|
49
|
-
src:
|
|
50
|
-
local('Pretendard Regular'),
|
|
51
|
-
url(./font/Pretendard-Regular.woff2) format('woff2');
|
|
39
|
+
src: url('https://cdn.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Regular.woff') format('woff');
|
|
52
40
|
font-display: swap;
|
|
53
41
|
}
|
|
54
42
|
|
|
55
43
|
@font-face {
|
|
56
44
|
font-family: 'Pretendard';
|
|
57
45
|
font-weight: 300;
|
|
58
|
-
src:
|
|
59
|
-
local('Pretendard Light'),
|
|
60
|
-
url(./font/Pretendard-Light.woff2) format('woff2');
|
|
46
|
+
src: url('https://cdn.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Light.woff') format('woff');
|
|
61
47
|
font-display: swap;
|
|
62
48
|
}
|
|
63
49
|
|
|
64
50
|
@font-face {
|
|
65
51
|
font-family: 'Pretendard';
|
|
66
52
|
font-weight: 200;
|
|
67
|
-
src:
|
|
68
|
-
local('Pretendard ExtraLight'),
|
|
69
|
-
url(./font/Pretendard-ExtraLight.woff2) format('woff2');
|
|
53
|
+
src: url('https://cdn.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-ExtraLight.woff') format('woff');
|
|
70
54
|
font-display: swap;
|
|
71
55
|
}
|
|
72
56
|
|
|
73
57
|
@font-face {
|
|
74
58
|
font-family: 'Pretendard';
|
|
75
59
|
font-weight: 100;
|
|
76
|
-
src:
|
|
77
|
-
local('Pretendard Thin'),
|
|
78
|
-
url(./font/Pretendard-Thin.woff2) format('woff2');
|
|
60
|
+
src: url('https://cdn.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Thin.woff') format('woff');
|
|
79
61
|
font-display: swap;
|
|
80
62
|
}
|
package/readme.md
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
# Podo UI
|
|
2
|
-
|
|
3
|
-
> SCSS Module 기반 디자인 시스템
|
|
4
|
-
|
|
5
|
-
## 설치
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install podo-ui
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## 빠른 시작
|
|
12
|
-
|
|
13
|
-
### Global SCSS 적용
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
// main.tsx
|
|
17
|
-
import 'podo-ui/global.scss';
|
|
18
|
-
import 'podo-ui/vite-fonts.scss'; // Vite 사용 시
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
### SCSS Module에서 사용
|
|
22
|
-
|
|
23
|
-
```scss
|
|
24
|
-
// component.module.scss
|
|
25
|
-
@use 'podo-ui/mixin' as *;
|
|
26
|
-
|
|
27
|
-
.myComponent {
|
|
28
|
-
color: color(primary);
|
|
29
|
-
margin: s(4);
|
|
30
|
-
border-radius: r(2);
|
|
31
|
-
}
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### React 컴포넌트
|
|
35
|
-
|
|
36
|
-
```tsx
|
|
37
|
-
// Named imports로 개별 컴포넌트 가져오기
|
|
38
|
-
import { Input, Textarea, Editor, EditorView, Field, Pagination } from 'podo-ui';
|
|
39
|
-
|
|
40
|
-
// 또는 개별 컴포넌트 직접 import (레거시 방식)
|
|
41
|
-
import Input from 'podo-ui/react/atom/input';
|
|
42
|
-
import Field from 'podo-ui/react/molecule/field';
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## 주요 기능
|
|
46
|
-
|
|
47
|
-
- CSS 클래스 기반 디자인 시스템
|
|
48
|
-
- 반응형 그리드 시스템 (PC 12, Tablet 6, Mobile 4)
|
|
49
|
-
- 색상 시스템 및 다크 모드 지원
|
|
50
|
-
- React 컴포넌트 제공 (Input, Textarea, Editor, Field)
|
|
51
|
-
|
|
52
|
-
## 문서
|
|
53
|
-
|
|
54
|
-
상세한 사용법은 [공식 설명서](https://podoui.com)를 참고하세요.
|
|
55
|
-
|
|
56
|
-
## 링크
|
|
57
|
-
|
|
58
|
-
- [공식 설명서](https://podoui.com)
|
|
59
|
-
- [GitHub 저장소](https://github.com/hada0127/podo-ui)
|
|
60
|
-
- [이슈 제보](https://github.com/hada0127/podo-ui/issues)
|
|
61
|
-
|
|
62
|
-
## 라이선스
|
|
63
|
-
|
|
64
|
-
MIT
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|