@m1kapp/ui 0.1.3 → 0.1.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/README.md CHANGED
@@ -1,20 +1,21 @@
1
1
  # @m1kapp/ui
2
2
 
3
3
  > Mobile-first app shell for side projects.
4
- > Build apps that feel like native — in minutes.
4
+ > Build apps that feel native — in minutes.
5
5
 
6
6
  ```
7
7
  ┌─────────────────────┐
8
- │ Header (sticky) │
8
+ │ Header (sticky) │ ← AppShellHeader
9
9
  ├─────────────────────┤
10
10
  │ │
11
- │ Content (scroll) │
11
+ │ Content (scroll) │ ← AppShellContent
12
12
  │ │
13
13
  ├─────────────────────┤
14
- │ TabBar (sticky) │
14
+ │ TabBar (sticky) │ ← TabBar + Tab
15
15
  └─────────────────────┘
16
- rounded, shadow
17
- floating on color
16
+ rounded · shadow · floating on color
17
+
18
+ Watermark (full-screen colored bg)
18
19
  ```
19
20
 
20
21
  ## Install
@@ -23,130 +24,365 @@
23
24
  npm install @m1kapp/ui
24
25
  ```
25
26
 
27
+ **Requirements:** React 18+, Tailwind CSS 4+
28
+
29
+ Add the font (optional but recommended):
30
+
31
+ ```html
32
+ <!-- index.html -->
33
+ <link rel="stylesheet" href="https://static.toss.im/dist/tps.css" />
34
+ ```
35
+
36
+ ```ts
37
+ // main.tsx
38
+ import { fontFamily } from "@m1kapp/ui";
39
+ document.body.style.fontFamily = fontFamily.toss;
40
+ ```
41
+
42
+ ---
43
+
26
44
  ## Quick Start
27
45
 
28
46
  ```tsx
47
+ import { useState } from "react";
29
48
  import {
30
- Watermark,
31
- AppShell,
32
- AppShellHeader,
33
- AppShellContent,
34
- TabBar,
35
- Tab,
36
- Section,
37
- SectionHeader,
38
- Divider,
39
- StatChip,
40
- EmptyState,
49
+ Watermark, AppShell, AppShellHeader, AppShellContent,
50
+ TabBar, Tab, Section, StatChip, ThemeButton, ThemeDialog,
51
+ colors,
41
52
  } from "@m1kapp/ui";
42
53
 
43
54
  export default function App() {
44
55
  const [tab, setTab] = useState("home");
56
+ const [themeColor, setThemeColor] = useState(colors.blue);
57
+ const [themeOpen, setThemeOpen] = useState(false);
58
+ const [dark, setDark] = useState(false);
45
59
 
46
60
  return (
47
- <Watermark color="#3b82f6" text="myapp">
48
- <AppShell>
49
- <AppShellHeader>
50
- <span className="text-2xl font-black">myapp</span>
51
- </AppShellHeader>
52
-
53
- <AppShellContent>
54
- <Section>
55
- <h1 className="text-xl font-bold">Hello</h1>
56
- </Section>
57
-
58
- <Divider />
59
-
60
- <Section className="flex gap-3">
61
- <StatChip label="Today" value={42} />
62
- <StatChip label="Total" value={1234} />
63
- </Section>
64
- </AppShellContent>
65
-
66
- <TabBar>
67
- <Tab
68
- active={tab === "home"}
69
- onClick={() => setTab("home")}
70
- label="Home"
71
- icon={<span>🏠</span>}
72
- />
73
- <Tab
74
- active={tab === "profile"}
75
- onClick={() => setTab("profile")}
76
- label="Profile"
77
- icon={<span>👤</span>}
78
- />
79
- </TabBar>
80
- </AppShell>
81
- </Watermark>
61
+ <>
62
+ <Watermark color={themeColor} text="myapp">
63
+ <AppShell>
64
+ <AppShellHeader>
65
+ <span className="text-xl font-black">myapp</span>
66
+ <ThemeButton
67
+ color={themeColor}
68
+ dark={dark}
69
+ onClick={() => setThemeOpen(true)}
70
+ />
71
+ </AppShellHeader>
72
+
73
+ <AppShellContent>
74
+ <Section>
75
+ <StatChip label="Users" value={128} />
76
+ </Section>
77
+ </AppShellContent>
78
+
79
+ <TabBar>
80
+ <Tab
81
+ active={tab === "home"}
82
+ onClick={() => setTab("home")}
83
+ label="Home"
84
+ activeColor={themeColor}
85
+ icon={<HomeIcon />}
86
+ />
87
+ </TabBar>
88
+ </AppShell>
89
+ </Watermark>
90
+
91
+ <ThemeDialog
92
+ open={themeOpen}
93
+ onClose={() => setThemeOpen(false)}
94
+ current={themeColor}
95
+ onSelect={setThemeColor}
96
+ dark={dark}
97
+ onDarkToggle={() => {
98
+ setDark((v) => !v);
99
+ document.documentElement.classList.toggle("dark");
100
+ }}
101
+ />
102
+ </>
82
103
  );
83
104
  }
84
105
  ```
85
106
 
86
- ## Components
87
-
88
- ### Layout
107
+ ---
89
108
 
90
- | Component | Description |
91
- |-----------|-------------|
92
- | `Watermark` | Full-screen colored background with text pattern. The "floating app" look. |
93
- | `AppShell` | Mobile app container (rounded, shadow, ring) |
94
- | `AppShellHeader` | Sticky top header with blur backdrop |
95
- | `AppShellContent` | Scrollable main content area |
96
- | `TabBar` | Sticky bottom navigation |
97
- | `Tab` | Individual tab button |
98
-
99
- ### Content
109
+ ## Components
100
110
 
101
- | Component | Description |
102
- |-----------|-------------|
103
- | `Section` | Padded content section (px-4) |
104
- | `SectionHeader` | Small uppercase section title |
105
- | `Divider` | Horizontal separator line |
106
- | `StatChip` | Compact stat display (label + number) |
107
- | `EmptyState` | Placeholder with icon and message |
111
+ ### `Watermark`
108
112
 
109
- ## Props
113
+ Full-screen colored background with a repeating text pattern. The "floating app" aesthetic.
110
114
 
111
- ### `Watermark`
115
+ ```tsx
116
+ <Watermark
117
+ color="#3b82f6" // background color
118
+ text="myapp" // repeating watermark text
119
+ speed={20} // animation speed in seconds. 0 = static
120
+ sponsor={{ name: "@m1kapp/ui", url: "https://github.com/m1kapp/ui" }}
121
+ >
122
+ <AppShell>...</AppShell>
123
+ </Watermark>
124
+ ```
112
125
 
113
126
  | Prop | Type | Default | Description |
114
127
  |------|------|---------|-------------|
115
128
  | `color` | `string` | `#0f172a` | Background color |
116
- | `text` | `string` | `m1k` | Watermark pattern text |
129
+ | `text` | `string` | `"m1k"` | Watermark pattern text |
117
130
  | `maxWidth` | `number` | `430` | Max width of content area |
118
- | `padding` | `number` | `12` | Padding around the shell |
131
+ | `padding` | `number` | `12` | Padding around the shell (px) |
132
+ | `speed` | `number` | `20` | Drift animation speed (s). `0` = no animation |
133
+ | `sponsor` | `WatermarkSponsor` | — | 1k milestone sponsor — name shown interleaved with watermark text; entire bg becomes a link |
134
+
135
+ ```ts
136
+ interface WatermarkSponsor {
137
+ name: string; // shown in background
138
+ url: string; // entire background becomes a clickable link
139
+ }
140
+ ```
141
+
142
+ ---
119
143
 
120
144
  ### `AppShell`
121
145
 
122
- | Prop | Type | Default | Description |
123
- |------|------|---------|-------------|
124
- | `maxWidth` | `number` | `430` | Max width |
125
- | `className` | `string` | | Additional classes |
146
+ Mobile app container rounded corners, drop shadow, ring. Centers within `Watermark`.
126
147
 
127
- ### `Tab`
148
+ ```tsx
149
+ <AppShell maxWidth={430}>
150
+ <AppShellHeader>...</AppShellHeader>
151
+ <AppShellContent>...</AppShellContent>
152
+ <TabBar>...</TabBar>
153
+ </AppShell>
154
+ ```
155
+
156
+ | Prop | Type | Default |
157
+ |------|------|---------|
158
+ | `maxWidth` | `number` | `430` |
159
+ | `className` | `string` | — |
160
+ | `style` | `CSSProperties` | — |
161
+
162
+ ---
163
+
164
+ ### `AppShellHeader`
165
+
166
+ Sticky top bar (h-14) with blur backdrop.
167
+
168
+ ```tsx
169
+ <AppShellHeader>
170
+ <span className="font-black">myapp</span>
171
+ <ThemeButton color={themeColor} dark={dark} onClick={...} />
172
+ </AppShellHeader>
173
+ ```
174
+
175
+ ---
176
+
177
+ ### `AppShellContent`
178
+
179
+ Scrollable area between header and tab bar.
180
+
181
+ ```tsx
182
+ <AppShellContent>
183
+ <Section>...</Section>
184
+ <Divider />
185
+ <Section>...</Section>
186
+ </AppShellContent>
187
+ ```
188
+
189
+ ---
190
+
191
+ ### `TabBar` + `Tab`
192
+
193
+ Sticky bottom nav (h-16) with active color support.
194
+
195
+ ```tsx
196
+ <TabBar>
197
+ <Tab
198
+ active={tab === "home"}
199
+ onClick={() => setTab("home")}
200
+ label="Home"
201
+ icon={<HomeIcon />}
202
+ activeColor={themeColor} // optional, defaults to current text color
203
+ />
204
+ </TabBar>
205
+ ```
128
206
 
129
207
  | Prop | Type | Description |
130
208
  |------|------|-------------|
131
- | `active` | `boolean` | Whether tab is selected |
132
- | `onClick` | `() => void` | Click handler |
133
- | `icon` | `ReactNode` | Tab icon |
134
- | `label` | `string` | Tab label text |
209
+ | `active` | `boolean` | Selected state |
210
+ | `onClick` | `() => void` | |
211
+ | `icon` | `ReactNode` | Icon element |
212
+ | `label` | `string` | Label below icon |
135
213
  | `activeColor` | `string?` | Color when active |
136
214
 
137
- ## Requirements
215
+ ---
216
+
217
+ ### `ThemeButton`
218
+
219
+ Single circular button split diagonally — half light/dark indicator, half theme color dot. Put it in the header.
220
+
221
+ ```tsx
222
+ <ThemeButton
223
+ color={themeColor} // theme color (bottom-right half)
224
+ dark={dark} // light mode = white half, dark mode = black half
225
+ onClick={() => setThemeOpen(true)}
226
+ />
227
+ ```
228
+
229
+ ---
230
+
231
+ ### `ThemeDialog`
232
+
233
+ Bottom-sheet color picker + dark/light mode toggle.
234
+
235
+ ```tsx
236
+ <ThemeDialog
237
+ open={themeOpen}
238
+ onClose={() => setThemeOpen(false)}
239
+ current={themeColor}
240
+ onSelect={(color) => setThemeColor(color)}
241
+ dark={dark}
242
+ onDarkToggle={() => {
243
+ setDark((v) => !v);
244
+ document.documentElement.classList.toggle("dark");
245
+ }}
246
+ />
247
+ ```
248
+
249
+ | Prop | Type | Description |
250
+ |------|------|-------------|
251
+ | `open` | `boolean` | Show/hide |
252
+ | `onClose` | `() => void` | Called on backdrop click or Escape |
253
+ | `current` | `string` | Currently selected color |
254
+ | `onSelect` | `(color: string) => void` | Called when a color is picked (closes dialog) |
255
+ | `dark` | `boolean?` | Current dark mode state |
256
+ | `onDarkToggle` | `() => void?` | Called when light/dark is toggled |
257
+ | `palette` | `Record<string, string>?` | Override color palette (default: built-in `colors`) |
258
+
259
+ ---
260
+
261
+ ### `Section` + `SectionHeader`
262
+
263
+ ```tsx
264
+ <Section className="pt-5">
265
+ <SectionHeader>Stats</SectionHeader>
266
+ <p>Content with px-4 padding applied.</p>
267
+ </Section>
268
+ ```
269
+
270
+ ---
271
+
272
+ ### `Divider`
273
+
274
+ ```tsx
275
+ <Divider />
276
+ ```
277
+
278
+ ---
279
+
280
+ ### `StatChip`
281
+
282
+ Compact label + number display.
283
+
284
+ ```tsx
285
+ <div className="flex gap-3">
286
+ <StatChip label="Users" value={1024} />
287
+ <StatChip label="Revenue" value={9800} />
288
+ </div>
289
+ ```
290
+
291
+ ---
292
+
293
+ ### `EmptyState`
294
+
295
+ ```tsx
296
+ <EmptyState message="Nothing here yet" />
297
+
298
+ // Custom icon:
299
+ <EmptyState message="No results" icon={<SearchIcon />} />
300
+ ```
301
+
302
+ ---
303
+
304
+ ### `Typewriter`
305
+
306
+ Human-like typing effect with a blinking cursor.
307
+
308
+ ```tsx
309
+ <Typewriter
310
+ words={["side project", "weekend build", "바이브코딩"]}
311
+ color={themeColor}
312
+ speed={80} // ms per character
313
+ pause={2000} // ms between words
314
+ />
315
+ ```
316
+
317
+ ---
318
+
319
+ ### `colors`
320
+
321
+ Curated palette. Use with `Watermark`, `Tab`, and `ThemeDialog`.
322
+
323
+ ```ts
324
+ import { colors } from "@m1kapp/ui";
325
+
326
+ colors.blue // #3b82f6
327
+ colors.purple // #8b5cf6
328
+ colors.green // #10b981
329
+ colors.orange // #f97316
330
+ colors.pink // #ec4899
331
+ colors.red // #ef4444
332
+ colors.yellow // #eab308
333
+ colors.cyan // #06b6d4
334
+ colors.slate // #0f172a
335
+ colors.zinc // #27272a
336
+ ```
337
+
338
+ ---
339
+
340
+ ### `fonts` + `fontFamily`
341
+
342
+ CDN font references — no files bundled.
343
+
344
+ ```ts
345
+ import { fonts, fontFamily } from "@m1kapp/ui";
346
+
347
+ // In HTML:
348
+ // <link rel="stylesheet" href={fonts.toss} />
349
+
350
+ // In JS:
351
+ document.body.style.fontFamily = fontFamily.toss;
352
+
353
+ // Available:
354
+ fonts.toss // Toss Product Sans
355
+ fonts.pretendard // Pretendard Variable
356
+ fonts.inter // Inter
357
+ ```
358
+
359
+ ---
360
+
361
+ ## Dark Mode
362
+
363
+ Uses Tailwind's class-based dark mode. Add this to your CSS:
364
+
365
+ ```css
366
+ /* index.css */
367
+ @custom-variant dark (&:where(.dark, .dark *));
368
+ ```
369
+
370
+ Then toggle with:
371
+
372
+ ```ts
373
+ document.documentElement.classList.toggle("dark", isDark);
374
+ ```
138
375
 
139
- - React 18+
140
- - Tailwind CSS 4+
376
+ ---
141
377
 
142
378
  ## Philosophy
143
379
 
144
- In the AI era, building a side project takes a day.
380
+ In the AI era, a side project takes a day to build.
145
381
  But making it *feel* like an app still takes effort.
146
382
 
147
- `@m1kapp/ui` gives you the mobile app shell — header, scrollable content, bottom tabs, floating on a colored background — so you can focus on what matters: your idea.
383
+ `@m1kapp/ui` gives you the shell — header, scrollable content, bottom tabs, floating on a colored background — so you can focus on the idea.
148
384
 
149
- Built and battle-tested in [m1k](https://m1k.app).
385
+ Built and battle-tested at [m1k.app](https://m1k.app).
150
386
 
151
387
  ## License
152
388
 
package/dist/index.d.mts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as react from 'react';
2
3
  import { ReactNode, CSSProperties } from 'react';
3
4
 
4
5
  interface AppShellProps {
@@ -93,22 +94,57 @@ interface EmptyStateProps {
93
94
  */
94
95
  declare function EmptyState({ message, icon }: EmptyStateProps): react_jsx_runtime.JSX.Element;
95
96
 
97
+ interface WatermarkSponsor {
98
+ /** Service name displayed in the background as clickable text */
99
+ name: string;
100
+ /** URL to navigate to when the sponsor text is clicked */
101
+ url: string;
102
+ }
96
103
  interface WatermarkProps {
97
104
  children: ReactNode;
98
- /** Background color */
105
+ /** Background fill color. Accepts any CSS color value. Default: "#0f172a" */
99
106
  color?: string;
100
- /** Watermark text. Default: "m1k" */
107
+ /**
108
+ * Repeating watermark text shown across the background.
109
+ * Default: "m1k"
110
+ */
101
111
  text?: string;
102
- /** Max width of content area. Default: 430 */
112
+ /** Max width of the center content area in px. Default: 430 */
103
113
  maxWidth?: number;
104
- /** Padding around the app shell. Default: 12px */
114
+ /** Padding around the app shell in px. Default: 12 */
105
115
  padding?: number;
116
+ /**
117
+ * 1k milestone sponsor slot.
118
+ * The sponsor's name is interleaved with the watermark text across the
119
+ * background. Only the sponsor text is clickable (not the whole background).
120
+ *
121
+ * Font size auto-scales based on text length (14–28px).
122
+ *
123
+ * @example
124
+ * <Watermark
125
+ * color={colors.blue}
126
+ * sponsor={{ name: "@m1kapp/ui", url: "https://github.com/m1kapp/ui" }}
127
+ * >
128
+ * <AppShell>...</AppShell>
129
+ * </Watermark>
130
+ */
131
+ sponsor?: WatermarkSponsor;
132
+ /**
133
+ * Background drift animation speed in seconds per cycle.
134
+ * Set to `0` to disable animation (static background).
135
+ * Default: 20
136
+ *
137
+ * @example
138
+ * <Watermark speed={0} /> // static
139
+ * <Watermark speed={10} /> // faster
140
+ * <Watermark speed={40} /> // very slow
141
+ */
142
+ speed?: number;
106
143
  }
107
144
  /**
108
- * Full-screen colored background with repeating text watermark pattern.
109
- * Wraps the AppShell and provides the "floating app" look.
145
+ * Full-screen colored background with repeating animated text watermark pattern.
110
146
  */
111
- declare function Watermark({ children, color, text, maxWidth, padding, }: WatermarkProps): react_jsx_runtime.JSX.Element;
147
+ declare function Watermark({ children, color, text, maxWidth, padding, sponsor, speed, }: WatermarkProps): react_jsx_runtime.JSX.Element;
112
148
 
113
149
  declare const colors: {
114
150
  readonly blue: "#3b82f6";
@@ -126,19 +162,21 @@ type ColorName = keyof typeof colors;
126
162
 
127
163
  interface ThemeButtonProps {
128
164
  color: string;
165
+ dark?: boolean;
129
166
  onClick: () => void;
130
167
  className?: string;
131
168
  }
132
169
  /**
133
- * Small circular button showing the current theme color.
134
- * Designed for the AppShellHeader top-right slot.
170
+ * Single circular button split diagonally half dark/light, half theme color.
135
171
  */
136
- declare function ThemeButton({ color, onClick, className }: ThemeButtonProps): react_jsx_runtime.JSX.Element;
172
+ declare function ThemeButton({ color, dark, onClick, className }: ThemeButtonProps): react_jsx_runtime.JSX.Element;
137
173
  interface ThemeDialogProps {
138
174
  open: boolean;
139
175
  onClose: () => void;
140
176
  current: string;
141
177
  onSelect: (color: string) => void;
178
+ dark?: boolean;
179
+ onDarkToggle?: () => void;
142
180
  /** Override the color palette. Defaults to built-in colors. */
143
181
  palette?: Record<string, string>;
144
182
  }
@@ -146,40 +184,128 @@ interface ThemeDialogProps {
146
184
  * Bottom-sheet style color picker dialog.
147
185
  * Shows a 5-column grid of color circles with check on the active one.
148
186
  */
149
- declare function ThemeDialog({ open, onClose, current, onSelect, palette, }: ThemeDialogProps): react_jsx_runtime.JSX.Element | null;
187
+ declare function ThemeDialog({ open, onClose, current, onSelect, dark, onDarkToggle, palette, }: ThemeDialogProps): react_jsx_runtime.JSX.Element | null;
150
188
 
151
189
  /**
152
190
  * Font presets for @m1kapp/ui.
153
- * These return CSS @import strings to load fonts from official CDNs.
154
- * No font files are bundled — only references to the original sources.
191
+ * CDN links only no font files bundled.
192
+ *
193
+ * ## Quick setup (recommended)
194
+ *
195
+ * Add to your `index.html` <head>:
196
+ * ```html
197
+ * <link rel="preconnect" href="https://cdn.jsdelivr.net" />
198
+ * <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
199
+ * <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/toss/tossface/dist/tossface.css" />
200
+ * <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css" />
201
+ * ```
202
+ *
203
+ * Add to your global CSS:
204
+ * ```css
205
+ * html {
206
+ * font-family: "Tossface", "Pretendard Variable", "Pretendard", system-ui, sans-serif;
207
+ * }
208
+ * ```
209
+ *
210
+ * That's it — Tossface handles emojis, Pretendard handles text.
155
211
  */
156
212
  declare const fonts: {
157
- /** Toss Product Sans — from toss.im (free for commercial use) */
158
- readonly toss: "https://static.toss.im/dist/tps.css";
159
- /** Pretendard popular Korean web font */
213
+ /**
214
+ * Tossface — Toss emoji font (open source, jsDelivr CDN).
215
+ * Renders all emoji with the Toss design style.
216
+ * Add this to get consistent emoji across platforms.
217
+ */
218
+ readonly tossface: "https://cdn.jsdelivr.net/gh/toss/tossface/dist/tossface.css";
219
+ /**
220
+ * Pretendard — best Korean variable web font (jsDelivr CDN).
221
+ * Recommended for all Korean UI text.
222
+ */
160
223
  readonly pretendard: "https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css";
161
- /** Inter — clean Latin sans-serif */
224
+ /** Inter — clean Latin sans-serif (Google Fonts) */
162
225
  readonly inter: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;900&display=swap";
163
226
  };
164
227
  type FontName = keyof typeof fonts;
165
228
  /**
166
- * Returns a <link> href for the given font preset.
167
- * Usage in your HTML head or via a <link> tag:
229
+ * Recommended font-family stacks.
168
230
  *
169
- * ```tsx
170
- * <link rel="stylesheet" href={fonts.toss} />
171
- * ```
231
+ * @example
232
+ * // In your global CSS:
233
+ * html { font-family: ${fontFamily.default}; }
172
234
  *
173
- * Or in CSS:
174
- * ```css
175
- * @import url("https://static.toss.im/dist/tps.css");
176
- * body { font-family: "Toss Product Sans", sans-serif; }
177
- * ```
235
+ * // Or in JS (e.g. main.tsx):
236
+ * document.documentElement.style.fontFamily = fontFamily.default;
178
237
  */
179
238
  declare const fontFamily: {
180
- readonly toss: "\"Toss Product Sans\", \"Pretendard\", system-ui, sans-serif";
239
+ /**
240
+ * Default recommended stack.
241
+ * Tossface for emoji + Pretendard for Korean/Latin text.
242
+ */
243
+ readonly default: "\"Pretendard Variable\", \"Pretendard\", system-ui, -apple-system, sans-serif, \"Tossface\"";
244
+ /** Pretendard only */
181
245
  readonly pretendard: "\"Pretendard Variable\", \"Pretendard\", system-ui, sans-serif";
246
+ /** Inter only */
182
247
  readonly inter: "\"Inter\", system-ui, sans-serif";
183
248
  };
184
249
 
185
- export { AppShell, AppShellContent, type AppShellContentProps, AppShellHeader, type AppShellHeaderProps, type AppShellProps, type ColorName, Divider, EmptyState, type EmptyStateProps, type FontName, Section, SectionHeader, type SectionHeaderProps, type SectionProps, StatChip, type StatChipProps, Tab, TabBar, type TabBarProps, type TabProps, ThemeButton, type ThemeButtonProps, ThemeDialog, type ThemeDialogProps, Watermark, type WatermarkProps, colors, fontFamily, fonts };
250
+ interface TypewriterProps {
251
+ /** Words to cycle through */
252
+ words: string[];
253
+ /** Text color */
254
+ color?: string;
255
+ /** Typing speed in ms (base, actual varies ±50%). Default: 80 */
256
+ speed?: number;
257
+ /** Delete speed in ms. Default: 30 */
258
+ deleteSpeed?: number;
259
+ /** Pause after typing completes in ms. Default: 2200 */
260
+ pauseMs?: number;
261
+ /** Pause between words in ms. Default: 400 */
262
+ gapMs?: number;
263
+ /** Cursor color. Defaults to `color` prop */
264
+ cursorColor?: string;
265
+ className?: string;
266
+ }
267
+ /**
268
+ * Typewriter effect that cycles through words with human-like timing.
269
+ * Features irregular delays, space pauses, char pop animation, and blinking cursor.
270
+ */
271
+ declare function Typewriter({ words, color, speed, deleteSpeed, pauseMs, gapMs, cursorColor, className, }: TypewriterProps): react_jsx_runtime.JSX.Element;
272
+
273
+ interface EmojiButtonProps {
274
+ emoji: string;
275
+ onClick: () => void;
276
+ className?: string;
277
+ }
278
+ /**
279
+ * Small button displaying the selected emoji.
280
+ * Use it anywhere — tab icons, headers, list items, etc.
281
+ */
282
+ declare function EmojiButton({ emoji, onClick, className }: EmojiButtonProps): react_jsx_runtime.JSX.Element;
283
+ interface EmojiPickerProps {
284
+ open: boolean;
285
+ onClose: () => void;
286
+ current: string;
287
+ onSelect: (emoji: string) => void;
288
+ }
289
+ /**
290
+ * Bottom-sheet emoji picker with categories.
291
+ */
292
+ declare function EmojiPicker({ open, onClose, current, onSelect }: EmojiPickerProps): react.ReactPortal | null;
293
+
294
+ interface TooltipProps {
295
+ label: string;
296
+ children: ReactNode;
297
+ /** Placement relative to the trigger. Default: "top" */
298
+ placement?: "top" | "bottom";
299
+ }
300
+ /**
301
+ * Simple tooltip that appears above (or below) the trigger on hover/focus.
302
+ * Renders via portal so it's never clipped by overflow-hidden containers.
303
+ *
304
+ * @example
305
+ * <Tooltip label="복사하기">
306
+ * <button>복사</button>
307
+ * </Tooltip>
308
+ */
309
+ declare function Tooltip({ label, children, placement }: TooltipProps): react_jsx_runtime.JSX.Element;
310
+
311
+ export { AppShell, AppShellContent, type AppShellContentProps, AppShellHeader, type AppShellHeaderProps, type AppShellProps, type ColorName, Divider, EmojiButton, type EmojiButtonProps, EmojiPicker, type EmojiPickerProps, EmptyState, type EmptyStateProps, type FontName, Section, SectionHeader, type SectionHeaderProps, type SectionProps, StatChip, type StatChipProps, Tab, TabBar, type TabBarProps, type TabProps, ThemeButton, type ThemeButtonProps, ThemeDialog, type ThemeDialogProps, Tooltip, type TooltipProps, Typewriter, type TypewriterProps, Watermark, type WatermarkProps, type WatermarkSponsor, colors, fontFamily, fonts };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as react from 'react';
2
3
  import { ReactNode, CSSProperties } from 'react';
3
4
 
4
5
  interface AppShellProps {
@@ -93,22 +94,57 @@ interface EmptyStateProps {
93
94
  */
94
95
  declare function EmptyState({ message, icon }: EmptyStateProps): react_jsx_runtime.JSX.Element;
95
96
 
97
+ interface WatermarkSponsor {
98
+ /** Service name displayed in the background as clickable text */
99
+ name: string;
100
+ /** URL to navigate to when the sponsor text is clicked */
101
+ url: string;
102
+ }
96
103
  interface WatermarkProps {
97
104
  children: ReactNode;
98
- /** Background color */
105
+ /** Background fill color. Accepts any CSS color value. Default: "#0f172a" */
99
106
  color?: string;
100
- /** Watermark text. Default: "m1k" */
107
+ /**
108
+ * Repeating watermark text shown across the background.
109
+ * Default: "m1k"
110
+ */
101
111
  text?: string;
102
- /** Max width of content area. Default: 430 */
112
+ /** Max width of the center content area in px. Default: 430 */
103
113
  maxWidth?: number;
104
- /** Padding around the app shell. Default: 12px */
114
+ /** Padding around the app shell in px. Default: 12 */
105
115
  padding?: number;
116
+ /**
117
+ * 1k milestone sponsor slot.
118
+ * The sponsor's name is interleaved with the watermark text across the
119
+ * background. Only the sponsor text is clickable (not the whole background).
120
+ *
121
+ * Font size auto-scales based on text length (14–28px).
122
+ *
123
+ * @example
124
+ * <Watermark
125
+ * color={colors.blue}
126
+ * sponsor={{ name: "@m1kapp/ui", url: "https://github.com/m1kapp/ui" }}
127
+ * >
128
+ * <AppShell>...</AppShell>
129
+ * </Watermark>
130
+ */
131
+ sponsor?: WatermarkSponsor;
132
+ /**
133
+ * Background drift animation speed in seconds per cycle.
134
+ * Set to `0` to disable animation (static background).
135
+ * Default: 20
136
+ *
137
+ * @example
138
+ * <Watermark speed={0} /> // static
139
+ * <Watermark speed={10} /> // faster
140
+ * <Watermark speed={40} /> // very slow
141
+ */
142
+ speed?: number;
106
143
  }
107
144
  /**
108
- * Full-screen colored background with repeating text watermark pattern.
109
- * Wraps the AppShell and provides the "floating app" look.
145
+ * Full-screen colored background with repeating animated text watermark pattern.
110
146
  */
111
- declare function Watermark({ children, color, text, maxWidth, padding, }: WatermarkProps): react_jsx_runtime.JSX.Element;
147
+ declare function Watermark({ children, color, text, maxWidth, padding, sponsor, speed, }: WatermarkProps): react_jsx_runtime.JSX.Element;
112
148
 
113
149
  declare const colors: {
114
150
  readonly blue: "#3b82f6";
@@ -126,19 +162,21 @@ type ColorName = keyof typeof colors;
126
162
 
127
163
  interface ThemeButtonProps {
128
164
  color: string;
165
+ dark?: boolean;
129
166
  onClick: () => void;
130
167
  className?: string;
131
168
  }
132
169
  /**
133
- * Small circular button showing the current theme color.
134
- * Designed for the AppShellHeader top-right slot.
170
+ * Single circular button split diagonally half dark/light, half theme color.
135
171
  */
136
- declare function ThemeButton({ color, onClick, className }: ThemeButtonProps): react_jsx_runtime.JSX.Element;
172
+ declare function ThemeButton({ color, dark, onClick, className }: ThemeButtonProps): react_jsx_runtime.JSX.Element;
137
173
  interface ThemeDialogProps {
138
174
  open: boolean;
139
175
  onClose: () => void;
140
176
  current: string;
141
177
  onSelect: (color: string) => void;
178
+ dark?: boolean;
179
+ onDarkToggle?: () => void;
142
180
  /** Override the color palette. Defaults to built-in colors. */
143
181
  palette?: Record<string, string>;
144
182
  }
@@ -146,40 +184,128 @@ interface ThemeDialogProps {
146
184
  * Bottom-sheet style color picker dialog.
147
185
  * Shows a 5-column grid of color circles with check on the active one.
148
186
  */
149
- declare function ThemeDialog({ open, onClose, current, onSelect, palette, }: ThemeDialogProps): react_jsx_runtime.JSX.Element | null;
187
+ declare function ThemeDialog({ open, onClose, current, onSelect, dark, onDarkToggle, palette, }: ThemeDialogProps): react_jsx_runtime.JSX.Element | null;
150
188
 
151
189
  /**
152
190
  * Font presets for @m1kapp/ui.
153
- * These return CSS @import strings to load fonts from official CDNs.
154
- * No font files are bundled — only references to the original sources.
191
+ * CDN links only no font files bundled.
192
+ *
193
+ * ## Quick setup (recommended)
194
+ *
195
+ * Add to your `index.html` <head>:
196
+ * ```html
197
+ * <link rel="preconnect" href="https://cdn.jsdelivr.net" />
198
+ * <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
199
+ * <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/toss/tossface/dist/tossface.css" />
200
+ * <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css" />
201
+ * ```
202
+ *
203
+ * Add to your global CSS:
204
+ * ```css
205
+ * html {
206
+ * font-family: "Tossface", "Pretendard Variable", "Pretendard", system-ui, sans-serif;
207
+ * }
208
+ * ```
209
+ *
210
+ * That's it — Tossface handles emojis, Pretendard handles text.
155
211
  */
156
212
  declare const fonts: {
157
- /** Toss Product Sans — from toss.im (free for commercial use) */
158
- readonly toss: "https://static.toss.im/dist/tps.css";
159
- /** Pretendard popular Korean web font */
213
+ /**
214
+ * Tossface — Toss emoji font (open source, jsDelivr CDN).
215
+ * Renders all emoji with the Toss design style.
216
+ * Add this to get consistent emoji across platforms.
217
+ */
218
+ readonly tossface: "https://cdn.jsdelivr.net/gh/toss/tossface/dist/tossface.css";
219
+ /**
220
+ * Pretendard — best Korean variable web font (jsDelivr CDN).
221
+ * Recommended for all Korean UI text.
222
+ */
160
223
  readonly pretendard: "https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css";
161
- /** Inter — clean Latin sans-serif */
224
+ /** Inter — clean Latin sans-serif (Google Fonts) */
162
225
  readonly inter: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;900&display=swap";
163
226
  };
164
227
  type FontName = keyof typeof fonts;
165
228
  /**
166
- * Returns a <link> href for the given font preset.
167
- * Usage in your HTML head or via a <link> tag:
229
+ * Recommended font-family stacks.
168
230
  *
169
- * ```tsx
170
- * <link rel="stylesheet" href={fonts.toss} />
171
- * ```
231
+ * @example
232
+ * // In your global CSS:
233
+ * html { font-family: ${fontFamily.default}; }
172
234
  *
173
- * Or in CSS:
174
- * ```css
175
- * @import url("https://static.toss.im/dist/tps.css");
176
- * body { font-family: "Toss Product Sans", sans-serif; }
177
- * ```
235
+ * // Or in JS (e.g. main.tsx):
236
+ * document.documentElement.style.fontFamily = fontFamily.default;
178
237
  */
179
238
  declare const fontFamily: {
180
- readonly toss: "\"Toss Product Sans\", \"Pretendard\", system-ui, sans-serif";
239
+ /**
240
+ * Default recommended stack.
241
+ * Tossface for emoji + Pretendard for Korean/Latin text.
242
+ */
243
+ readonly default: "\"Pretendard Variable\", \"Pretendard\", system-ui, -apple-system, sans-serif, \"Tossface\"";
244
+ /** Pretendard only */
181
245
  readonly pretendard: "\"Pretendard Variable\", \"Pretendard\", system-ui, sans-serif";
246
+ /** Inter only */
182
247
  readonly inter: "\"Inter\", system-ui, sans-serif";
183
248
  };
184
249
 
185
- export { AppShell, AppShellContent, type AppShellContentProps, AppShellHeader, type AppShellHeaderProps, type AppShellProps, type ColorName, Divider, EmptyState, type EmptyStateProps, type FontName, Section, SectionHeader, type SectionHeaderProps, type SectionProps, StatChip, type StatChipProps, Tab, TabBar, type TabBarProps, type TabProps, ThemeButton, type ThemeButtonProps, ThemeDialog, type ThemeDialogProps, Watermark, type WatermarkProps, colors, fontFamily, fonts };
250
+ interface TypewriterProps {
251
+ /** Words to cycle through */
252
+ words: string[];
253
+ /** Text color */
254
+ color?: string;
255
+ /** Typing speed in ms (base, actual varies ±50%). Default: 80 */
256
+ speed?: number;
257
+ /** Delete speed in ms. Default: 30 */
258
+ deleteSpeed?: number;
259
+ /** Pause after typing completes in ms. Default: 2200 */
260
+ pauseMs?: number;
261
+ /** Pause between words in ms. Default: 400 */
262
+ gapMs?: number;
263
+ /** Cursor color. Defaults to `color` prop */
264
+ cursorColor?: string;
265
+ className?: string;
266
+ }
267
+ /**
268
+ * Typewriter effect that cycles through words with human-like timing.
269
+ * Features irregular delays, space pauses, char pop animation, and blinking cursor.
270
+ */
271
+ declare function Typewriter({ words, color, speed, deleteSpeed, pauseMs, gapMs, cursorColor, className, }: TypewriterProps): react_jsx_runtime.JSX.Element;
272
+
273
+ interface EmojiButtonProps {
274
+ emoji: string;
275
+ onClick: () => void;
276
+ className?: string;
277
+ }
278
+ /**
279
+ * Small button displaying the selected emoji.
280
+ * Use it anywhere — tab icons, headers, list items, etc.
281
+ */
282
+ declare function EmojiButton({ emoji, onClick, className }: EmojiButtonProps): react_jsx_runtime.JSX.Element;
283
+ interface EmojiPickerProps {
284
+ open: boolean;
285
+ onClose: () => void;
286
+ current: string;
287
+ onSelect: (emoji: string) => void;
288
+ }
289
+ /**
290
+ * Bottom-sheet emoji picker with categories.
291
+ */
292
+ declare function EmojiPicker({ open, onClose, current, onSelect }: EmojiPickerProps): react.ReactPortal | null;
293
+
294
+ interface TooltipProps {
295
+ label: string;
296
+ children: ReactNode;
297
+ /** Placement relative to the trigger. Default: "top" */
298
+ placement?: "top" | "bottom";
299
+ }
300
+ /**
301
+ * Simple tooltip that appears above (or below) the trigger on hover/focus.
302
+ * Renders via portal so it's never clipped by overflow-hidden containers.
303
+ *
304
+ * @example
305
+ * <Tooltip label="복사하기">
306
+ * <button>복사</button>
307
+ * </Tooltip>
308
+ */
309
+ declare function Tooltip({ label, children, placement }: TooltipProps): react_jsx_runtime.JSX.Element;
310
+
311
+ export { AppShell, AppShellContent, type AppShellContentProps, AppShellHeader, type AppShellHeaderProps, type AppShellProps, type ColorName, Divider, EmojiButton, type EmojiButtonProps, EmojiPicker, type EmojiPickerProps, EmptyState, type EmptyStateProps, type FontName, Section, SectionHeader, type SectionHeaderProps, type SectionProps, StatChip, type StatChipProps, Tab, TabBar, type TabBarProps, type TabProps, ThemeButton, type ThemeButtonProps, ThemeDialog, type ThemeDialogProps, Tooltip, type TooltipProps, Typewriter, type TypewriterProps, Watermark, type WatermarkProps, type WatermarkSponsor, colors, fontFamily, fonts };
package/dist/index.js CHANGED
@@ -1,5 +1,12 @@
1
1
  "use client";
2
- "use strict";var x=Object.defineProperty;var H=Object.getOwnPropertyDescriptor;var W=Object.getOwnPropertyNames;var D=Object.prototype.hasOwnProperty;var L=(e,t)=>{for(var r in t)x(e,r,{get:t[r],enumerable:!0})},F=(e,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of W(t))!D.call(e,n)&&n!==r&&x(e,n,{get:()=>t[n],enumerable:!(s=H(t,n))||s.enumerable});return e};var I=e=>F(x({},"__esModule",{value:!0}),e);var O={};L(O,{AppShell:()=>b,AppShellContent:()=>g,AppShellHeader:()=>u,Divider:()=>w,EmptyState:()=>S,Section:()=>v,SectionHeader:()=>N,StatChip:()=>P,Tab:()=>k,TabBar:()=>y,ThemeButton:()=>R,ThemeDialog:()=>$,Watermark:()=>C,colors:()=>f,fontFamily:()=>B,fonts:()=>A});module.exports=I(O);var m=require("react/jsx-runtime");function b({children:e,className:t="",maxWidth:r=430,style:s}){return(0,m.jsx)("div",{className:`w-full h-full flex flex-col bg-white dark:bg-zinc-950 shadow-2xl ring-1 ring-black/5 dark:ring-white/10 rounded-2xl overflow-hidden ${t}`,style:{maxWidth:r,...s},children:e})}function u({children:e,className:t=""}){return(0,m.jsx)("header",{className:`sticky top-0 z-20 px-4 py-3 flex items-center justify-between border-b border-zinc-100 dark:border-zinc-800 bg-white/90 dark:bg-zinc-950/90 backdrop-blur-md rounded-t-2xl ${t}`,children:e})}function g({children:e,className:t=""}){return(0,m.jsx)("div",{className:`flex-1 overflow-y-auto scrollbar-hide ${t}`,children:e})}var p=require("react/jsx-runtime");function y({children:e,className:t=""}){return(0,p.jsx)("nav",{className:`sticky bottom-0 z-20 border-t border-zinc-200 dark:border-zinc-800 flex bg-white/90 dark:bg-zinc-950/90 backdrop-blur-md rounded-b-2xl ${t}`,children:e})}function k({active:e,onClick:t,icon:r,label:s,activeColor:n}){return(0,p.jsxs)("button",{onClick:t,className:`flex-1 flex flex-col items-center gap-0.5 py-2.5 transition-colors ${e?"":"text-zinc-300 dark:text-zinc-600"}`,style:e?{color:n}:void 0,children:[r,(0,p.jsx)("span",{className:"text-[10px] font-medium",children:s})]})}var h=require("react/jsx-runtime");function v({children:e,className:t=""}){return(0,h.jsx)("section",{className:`px-4 ${t}`,children:e})}function N({children:e}){return(0,h.jsx)("h2",{className:"text-[11px] font-semibold text-zinc-400 dark:text-zinc-500 uppercase tracking-wider mb-3",children:e})}var z=require("react/jsx-runtime");function w({className:e=""}){return(0,z.jsx)("div",{className:`mx-4 my-6 h-px bg-zinc-200 dark:bg-zinc-800 ${e}`})}var l=require("react/jsx-runtime");function P({label:e,value:t,className:r=""}){return(0,l.jsxs)("div",{className:`flex-1 rounded-xl bg-zinc-100 dark:bg-zinc-900 px-3 py-3 text-center ${r}`,children:[(0,l.jsx)("p",{className:"text-[10px] text-zinc-500 dark:text-zinc-400 font-medium mb-0.5",children:e}),(0,l.jsx)("p",{className:"text-lg font-bold tabular-nums text-zinc-900 dark:text-white",children:t.toLocaleString()})]})}var a=require("react/jsx-runtime");function S({message:e,icon:t}){return(0,a.jsxs)("div",{className:"flex flex-col items-center justify-center py-12 gap-2",children:[t||(0,a.jsxs)("svg",{width:"32",height:"32",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",className:"text-zinc-200 dark:text-zinc-700",children:[(0,a.jsx)("circle",{cx:"12",cy:"12",r:"10"}),(0,a.jsx)("path",{d:"M8 15h8"}),(0,a.jsx)("circle",{cx:"9",cy:"9",r:"1",fill:"currentColor",stroke:"none"}),(0,a.jsx)("circle",{cx:"15",cy:"9",r:"1",fill:"currentColor",stroke:"none"})]}),(0,a.jsx)("p",{className:"text-sm text-zinc-400 dark:text-zinc-500",children:e})]})}var d=require("react/jsx-runtime");function j(e,t=.08){let n=`<svg xmlns="http://www.w3.org/2000/svg" width="220" height="120">
3
- <text x="10" y="45" font-family="system-ui,sans-serif" font-size="44" font-weight="900" fill="white" opacity="${t}">${e}</text>
4
- <text x="120" y="100" font-family="system-ui,sans-serif" font-size="44" font-weight="900" fill="white" opacity="${t}">${e}</text>
5
- </svg>`;return`url("data:image/svg+xml,${encodeURIComponent(n)}")`}function C({children:e,color:t="#0f172a",text:r="m1k",maxWidth:s=430,padding:n=12}){return(0,d.jsxs)("div",{className:"h-dvh w-full relative overflow-hidden",style:{backgroundColor:t,transition:"background-color 0.5s ease"},children:[(0,d.jsx)("div",{className:"absolute inset-0 pointer-events-none select-none",style:{backgroundImage:j(r),backgroundRepeat:"repeat",transform:"rotate(-12deg) scale(1.5)",transformOrigin:"center center"}}),(0,d.jsx)("div",{className:"relative z-10 h-full flex items-center justify-center mx-auto",style:{maxWidth:s,padding:n},children:e})]})}var f={blue:"#3b82f6",purple:"#8b5cf6",green:"#10b981",orange:"#f97316",pink:"#ec4899",red:"#ef4444",yellow:"#eab308",cyan:"#06b6d4",slate:"#0f172a",zinc:"#27272a"};var T=require("react");var o=require("react/jsx-runtime");function R({color:e,onClick:t,className:r=""}){return(0,o.jsx)("button",{onClick:t,className:`w-7 h-7 rounded-full border-2 border-white dark:border-zinc-700 shadow-sm transition-transform hover:scale-110 ${r}`,style:{backgroundColor:e},title:"Change theme"})}function $({open:e,onClose:t,current:r,onSelect:s,palette:n=f}){if((0,T.useEffect)(()=>{if(!e)return;let c=i=>{i.key==="Escape"&&t()};return window.addEventListener("keydown",c),()=>window.removeEventListener("keydown",c)},[e,t]),!e)return null;let E=Object.entries(n);return(0,o.jsxs)("div",{className:"fixed inset-0 z-50 flex items-end justify-center",onClick:t,children:[(0,o.jsx)("div",{className:"absolute inset-0 bg-black/40 backdrop-blur-sm"}),(0,o.jsxs)("div",{className:"relative z-10 w-full max-w-[406px] mb-3 mx-3 rounded-2xl bg-white dark:bg-zinc-900 shadow-2xl overflow-hidden",onClick:c=>c.stopPropagation(),children:[(0,o.jsxs)("div",{className:"px-4 pt-4 pb-2",children:[(0,o.jsx)("p",{className:"text-sm font-bold text-zinc-900 dark:text-white",children:"Theme Color"}),(0,o.jsx)("p",{className:"text-xs text-zinc-400 dark:text-zinc-500 mt-0.5",children:"Change the Watermark background"})]}),(0,o.jsx)("div",{className:"px-4 pb-3 grid grid-cols-5 gap-3 justify-items-center",children:E.map(([c,i])=>(0,o.jsx)("button",{onClick:()=>{s(i),t()},className:`relative w-11 h-11 rounded-full transition-all hover:scale-110 ${r===i?"ring-2 ring-offset-2 ring-offset-white dark:ring-offset-zinc-900":""}`,style:{backgroundColor:i,...r===i?{"--tw-ring-color":i}:{}},children:r===i&&(0,o.jsx)("div",{className:"absolute inset-0 flex items-center justify-center",children:(0,o.jsx)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"3",strokeLinecap:"round",strokeLinejoin:"round",children:(0,o.jsx)("polyline",{points:"20 6 9 17 4 12"})})})},i))}),(0,o.jsx)("div",{className:"px-4 py-3 border-t border-zinc-100 dark:border-zinc-800",children:(0,o.jsx)("button",{onClick:t,className:"w-full py-2.5 rounded-xl bg-zinc-100 dark:bg-zinc-800 text-sm font-medium text-zinc-600 dark:text-zinc-400 hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors",children:"Close"})})]})]})}var A={toss:"https://static.toss.im/dist/tps.css",pretendard:"https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css",inter:"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;900&display=swap"},B={toss:'"Toss Product Sans", "Pretendard", system-ui, sans-serif',pretendard:'"Pretendard Variable", "Pretendard", system-ui, sans-serif',inter:'"Inter", system-ui, sans-serif'};0&&(module.exports={AppShell,AppShellContent,AppShellHeader,Divider,EmptyState,Section,SectionHeader,StatChip,Tab,TabBar,ThemeButton,ThemeDialog,Watermark,colors,fontFamily,fonts});
2
+ "use strict";var A=Object.defineProperty;var me=Object.getOwnPropertyDescriptor;var fe=Object.getOwnPropertyNames;var ue=Object.prototype.hasOwnProperty;var xe=(e,t)=>{for(var o in t)A(e,o,{get:t[o],enumerable:!0})},be=(e,t,o,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of fe(t))!ue.call(e,a)&&a!==o&&A(e,a,{get:()=>t[a],enumerable:!(n=me(t,a))||n.enumerable});return e};var he=e=>be(A({},"__esModule",{value:!0}),e);var ye={};xe(ye,{AppShell:()=>D,AppShellContent:()=>I,AppShellHeader:()=>H,Divider:()=>K,EmojiButton:()=>ie,EmojiPicker:()=>ae,EmptyState:()=>Z,Section:()=>O,SectionHeader:()=>_,StatChip:()=>V,Tab:()=>Y,TabBar:()=>F,ThemeButton:()=>Q,ThemeDialog:()=>U,Tooltip:()=>ce,Typewriter:()=>oe,Watermark:()=>J,colors:()=>E,fontFamily:()=>te,fonts:()=>ee});module.exports=he(ye);var C=require("react/jsx-runtime");function D({children:e,className:t="",maxWidth:o=430,style:n}){return(0,C.jsx)("div",{className:`w-full h-full flex flex-col bg-white dark:bg-zinc-950 shadow-2xl ring-1 ring-black/10 dark:ring-zinc-700 rounded-2xl overflow-hidden ${t}`,style:{maxWidth:o,...n},children:e})}function H({children:e,className:t=""}){return(0,C.jsx)("header",{className:`sticky top-0 z-20 h-14 px-4 flex items-center justify-between border-b border-zinc-100 dark:border-zinc-800 bg-white/90 dark:bg-zinc-950/90 backdrop-blur-md rounded-t-2xl ${t}`,children:e})}function I({children:e,className:t=""}){return(0,C.jsx)("div",{className:`flex-1 overflow-y-auto scrollbar-hide ${t}`,children:e})}var P=require("react/jsx-runtime");function F({children:e,className:t=""}){return(0,P.jsx)("nav",{className:`sticky bottom-0 z-20 h-16 border-t border-zinc-200 dark:border-zinc-800 flex bg-white/90 dark:bg-zinc-950/90 backdrop-blur-md rounded-b-2xl ${t}`,children:e})}function Y({active:e,onClick:t,icon:o,label:n,activeColor:a}){return(0,P.jsxs)("button",{onClick:t,className:`flex-1 flex flex-col items-center gap-0.5 py-2.5 transition-colors ${e?"":"text-zinc-300 dark:text-zinc-600"}`,style:e?{color:a}:void 0,children:[o,(0,P.jsx)("span",{className:"text-[10px] font-medium",children:n})]})}var W=require("react/jsx-runtime");function O({children:e,className:t=""}){return(0,W.jsx)("section",{className:`px-4 ${t}`,children:e})}function _({children:e}){return(0,W.jsx)("h2",{className:"text-[11px] font-semibold text-zinc-400 dark:text-zinc-500 uppercase tracking-wider mb-3",children:e})}var X=require("react/jsx-runtime");function K({className:e=""}){return(0,X.jsx)("div",{className:`mx-4 my-6 h-px bg-zinc-200 dark:bg-zinc-800 ${e}`})}var S=require("react/jsx-runtime");function V({label:e,value:t,className:o=""}){return(0,S.jsxs)("div",{className:`flex-1 rounded-xl bg-zinc-100 dark:bg-zinc-900 px-3 py-3 text-center ${o}`,children:[(0,S.jsx)("p",{className:"text-[10px] text-zinc-500 dark:text-zinc-400 font-medium mb-0.5",children:e}),(0,S.jsx)("p",{className:"text-lg font-bold tabular-nums text-zinc-900 dark:text-white",children:t.toLocaleString()})]})}var b=require("react/jsx-runtime");function Z({message:e,icon:t}){return(0,b.jsxs)("div",{className:"flex flex-col items-center justify-center py-12 gap-2",children:[t||(0,b.jsxs)("svg",{width:"32",height:"32",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",className:"text-zinc-200 dark:text-zinc-700",children:[(0,b.jsx)("circle",{cx:"12",cy:"12",r:"10"}),(0,b.jsx)("path",{d:"M8 15h8"}),(0,b.jsx)("circle",{cx:"9",cy:"9",r:"1",fill:"currentColor",stroke:"none"}),(0,b.jsx)("circle",{cx:"15",cy:"9",r:"1",fill:"currentColor",stroke:"none"})]}),(0,b.jsx)("p",{className:"text-sm text-zinc-400 dark:text-zinc-500",children:e})]})}var w=require("react/jsx-runtime"),ge=`
3
+ @keyframes watermark-drift {
4
+ 0% { transform: rotate(-12deg) scale(2) translate(0, 0); }
5
+ 100% { transform: rotate(-12deg) scale(2) translate(180px, 100px); }
6
+ }
7
+ `,G=!1;function ke(){if(G||typeof document>"u")return;let e=document.createElement("style");e.textContent=ge,document.head.appendChild(e),G=!0}function J({children:e,color:t="#0f172a",text:o="m1k",maxWidth:n=430,padding:a=12,sponsor:c,speed:f=20}){ke();let l=Math.max(14,Math.min(28,Math.floor(160/o.length))),s=c?Math.max(14,Math.min(28,Math.floor(160/c.name.length))):l,i=180,p=100,z=16,x=16,T=z*i/2,M=x*p/2;return(0,w.jsxs)("div",{className:"h-dvh w-full relative overflow-hidden",style:{backgroundColor:t,transition:"background-color 0.5s ease"},children:[(0,w.jsx)("div",{className:"absolute inset-0 pointer-events-none select-none",style:{transformOrigin:"center center",animation:f>0?`watermark-drift ${f}s linear infinite`:void 0,transform:"rotate(-12deg) scale(2)"},children:Array.from({length:x}).flatMap((R,u)=>Array.from({length:z}).map((L,y)=>{let N=y*i-T+i/2,B=u*p-M+p/2,$=(u+y)%2===1&&c,m={position:"absolute",left:N,top:B,transform:"translate(-50%, -50%)",fontWeight:900,color:"rgba(255,255,255,0.12)",whiteSpace:"nowrap",lineHeight:1};return $?(0,w.jsx)("a",{href:c.url,target:"_blank",rel:"noopener noreferrer",className:"hover:opacity-30 transition-opacity",style:{...m,fontSize:s,textDecoration:"none",pointerEvents:"auto"},children:c.name},`${u}-${y}`):(0,w.jsx)("a",{href:"https://m1k.app",target:"_blank",rel:"noopener noreferrer",className:"hover:opacity-30 transition-opacity",style:{...m,fontSize:l,textDecoration:"none",pointerEvents:"auto"},children:o},`${u}-${y}`)}))}),(0,w.jsx)("div",{className:"relative z-10 h-full flex items-center justify-center mx-auto",style:{maxWidth:n,padding:a},children:e})]})}var E={blue:"#3b82f6",purple:"#8b5cf6",green:"#10b981",orange:"#f97316",pink:"#ec4899",red:"#ef4444",yellow:"#eab308",cyan:"#06b6d4",slate:"#0f172a",zinc:"#27272a"};var q=require("react");var r=require("react/jsx-runtime");function Q({color:e,dark:t=!1,onClick:o,className:n=""}){let a=t?"#000":"#fff",c=t?"rgba(255,255,255,0.15)":"rgba(0,0,0,0.12)";return(0,r.jsx)("button",{onClick:o,className:`w-7 h-7 rounded-full transition-all active:scale-90 hover:scale-110 overflow-hidden ${n}`,style:{boxShadow:`0 2px 10px ${e}55`},title:"Theme",children:(0,r.jsxs)("svg",{width:"100%",height:"100%",viewBox:"0 0 100 100",children:[(0,r.jsx)("path",{d:"M0 0 L100 0 L0 100 Z",fill:a}),(0,r.jsx)("path",{d:"M100 0 L100 100 L0 100 Z",fill:e}),(0,r.jsx)("circle",{cx:"50",cy:"50",r:"49",fill:"none",stroke:c,strokeWidth:"2"})]})})}function U({open:e,onClose:t,current:o,onSelect:n,dark:a=!1,onDarkToggle:c,palette:f=E}){if((0,q.useEffect)(()=>{if(!e)return;let s=i=>{i.key==="Escape"&&t()};return window.addEventListener("keydown",s),()=>window.removeEventListener("keydown",s)},[e,t]),!e)return null;let l=Object.entries(f);return(0,r.jsxs)("div",{className:"fixed inset-0 z-50 flex items-end justify-center",onClick:t,children:[(0,r.jsx)("div",{className:"absolute inset-0 bg-black/40 backdrop-blur-sm"}),(0,r.jsxs)("div",{className:"relative z-10 w-full max-w-101.5 mb-3 mx-3 rounded-2xl bg-white dark:bg-zinc-900 shadow-2xl overflow-hidden",onClick:s=>s.stopPropagation(),children:[(0,r.jsxs)("div",{className:"px-4 pt-4 pb-3",children:[(0,r.jsx)("p",{className:"text-sm font-bold text-zinc-900 dark:text-white mb-3",children:"\uD14C\uB9C8"}),c&&(0,r.jsx)("div",{className:"flex gap-2 mb-4",children:[{label:"\uB77C\uC774\uD2B8",isDark:!1},{label:"\uB2E4\uD06C",isDark:!0}].map(s=>{let i=a===s.isDark;return(0,r.jsxs)("button",{onClick:()=>{i||c()},className:`flex-1 flex items-center justify-center gap-2 py-2.5 rounded-2xl transition-all ${i?"bg-zinc-900 dark:bg-white ring-2 ring-zinc-900 dark:ring-white ring-offset-2 ring-offset-white dark:ring-offset-zinc-900":"bg-zinc-100 dark:bg-zinc-800 hover:bg-zinc-200 dark:hover:bg-zinc-700"}`,children:[s.isDark?(0,r.jsx)("svg",{width:"15",height:"15",viewBox:"-1 -1 26 26",fill:i?"#18181b":"#71717a",children:(0,r.jsx)("path",{d:"M21 12.79A9 9 0 1 1 11.21 3a7 7 0 0 0 9.79 9.79z"})}):(0,r.jsxs)("svg",{width:"15",height:"15",viewBox:"-1 -1 26 26",fill:i?"white":"#71717a",children:[(0,r.jsx)("circle",{cx:"12",cy:"12",r:"5"}),(0,r.jsx)("path",{d:"M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42",stroke:i?"white":"#71717a",strokeWidth:"2",strokeLinecap:"round"})]}),(0,r.jsx)("span",{className:`text-sm font-semibold ${i?"text-white dark:text-zinc-900":"text-zinc-400 dark:text-zinc-500"}`,children:s.label})]},s.label)})})]}),(0,r.jsx)("div",{className:"px-4 pb-3 grid grid-cols-5 gap-3 justify-items-center",children:l.map(([s,i])=>(0,r.jsx)("button",{onClick:()=>{n(i),t()},className:"relative w-11 h-11 rounded-full transition-all hover:scale-110",style:{backgroundColor:i,boxShadow:o===i?`0 0 0 2px #fff, 0 0 0 4px ${i}`:"0 0 0 1.5px rgba(255,255,255,0.5), 0 2px 8px rgba(255,255,255,0.2)"},children:o===i&&(0,r.jsx)("div",{className:"absolute inset-0 flex items-center justify-center",children:(0,r.jsx)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"3",strokeLinecap:"round",strokeLinejoin:"round",children:(0,r.jsx)("polyline",{points:"20 6 9 17 4 12"})})})},i))}),(0,r.jsx)("div",{className:"px-4 py-3 border-t border-zinc-100 dark:border-zinc-800",children:(0,r.jsx)("button",{onClick:t,className:"w-full py-2.5 rounded-xl bg-zinc-100 dark:bg-zinc-800 text-sm font-medium text-zinc-600 dark:text-zinc-400 hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors",children:"Close"})})]})]})}var ee={tossface:"https://cdn.jsdelivr.net/gh/toss/tossface/dist/tossface.css",pretendard:"https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css",inter:"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;900&display=swap"},te={default:'"Pretendard Variable", "Pretendard", system-ui, -apple-system, sans-serif, "Tossface"',pretendard:'"Pretendard Variable", "Pretendard", system-ui, sans-serif',inter:'"Inter", system-ui, sans-serif'};var g=require("react"),h=require("react/jsx-runtime");function oe({words:e,color:t="currentColor",speed:o=80,deleteSpeed:n=30,pauseMs:a=2200,gapMs:c=400,cursorColor:f,className:l=""}){let[s,i]=(0,g.useState)(0),[p,z]=(0,g.useState)(0),[x,T]=(0,g.useState)(!1),[M,R]=(0,g.useState)(!0),u=e[s]||"",L=f||t,y=x?p>0:p<u.length;(0,g.useEffect)(()=>{if(y){R(!0);return}let m=setInterval(()=>R(v=>!v),530);return()=>clearInterval(m)},[y]),(0,g.useEffect)(()=>{if(!x&&p<u.length){let m=Math.random()*o,v=u[p-1]===" "?o*.4:0,pe=setTimeout(()=>z(de=>de+1),o*.75+m+v);return()=>clearTimeout(pe)}if(!x&&p===u.length){let m=setTimeout(()=>T(!0),a);return()=>clearTimeout(m)}if(x&&p>0){let m=setTimeout(()=>z(v=>v-1),n+Math.random()*n*.6);return()=>clearTimeout(m)}if(x&&p===0){let m=setTimeout(()=>{T(!1),i(v=>(v+1)%e.length)},c);return()=>clearTimeout(m)}},[p,x,u,o,n,a,c,e.length]);let N=u.slice(0,p),B=N[N.length-1],$=N.slice(0,-1);return(0,h.jsxs)("span",{className:l,style:{color:t},children:[p>0&&(0,h.jsxs)(h.Fragment,{children:[$,(0,h.jsx)("span",{className:"inline-block",style:{animation:x?void 0:"m1k-char-pop 0.1s ease-out"},children:B},`${s}-${p}`)]}),(0,h.jsx)("span",{className:"inline-block w-0.5 h-[1em] ml-px align-middle rounded-full",style:{backgroundColor:L,opacity:M?1:0,transition:"opacity 0.1s"}}),(0,h.jsx)("style",{children:`
8
+ @keyframes m1k-char-pop {
9
+ 0% { opacity: 0; transform: translateY(4px); }
10
+ 100% { opacity: 1; transform: translateY(0); }
11
+ }
12
+ `})]})}var j=require("react"),ne=require("react-dom"),d=require("react/jsx-runtime"),re=[{label:"\uC790\uC8FC \uC4F0\uB294",emojis:["\u{1F3E0}","\u{1F50D}","\u{1F464}","\u2B50","\u2764\uFE0F","\u{1F525}","\u2705","\u{1F4CC}","\u{1F3AF}","\u{1F4A1}","\u{1F680}","\u{1F4AC}","\u{1F44D}","\u{1F64C}","\u{1F4AA}","\u{1F389}","\u{1F4E2}","\u{1F511}","\u26A1","\u{1F31F}","\u{1F380}","\u{1F9E1}","\u{1FAF6}","\u{1F947}"]},{label:"\uAC10\uC815",emojis:["\u{1F600}","\u{1F604}","\u{1F606}","\u{1F60E}","\u{1F979}","\u{1F60D}","\u{1F929}","\u{1F605}","\u{1F602}","\u{1F972}","\u{1F62D}","\u{1F624}","\u{1F914}","\u{1F607}","\u{1FAF6}","\u{1F917}","\u{1F634}","\u{1F92F}","\u{1F973}","\u{1F62C}","\u{1FAE0}","\u{1F92B}","\u{1F636}","\u{1FAE1}"]},{label:"\uB3D9\uBB3C",emojis:["\u{1F436}","\u{1F431}","\u{1F42D}","\u{1F439}","\u{1F430}","\u{1F98A}","\u{1F43B}","\u{1F43C}","\u{1F428}","\u{1F42F}","\u{1F981}","\u{1F42E}","\u{1F437}","\u{1F438}","\u{1F435}","\u{1F414}","\u{1F427}","\u{1F426}","\u{1F986}","\u{1F989}","\u{1F98B}","\u{1F422}","\u{1F42C}","\u{1F433}"]},{label:"\uC0AC\uBB3C",emojis:["\u{1F4F1}","\u{1F4BB}","\u2328\uFE0F","\u{1F5A5}\uFE0F","\u{1F4F7}","\u{1F3B5}","\u{1F3AE}","\u{1F4DA}","\u{1F4B0}","\u{1F381}","\u{1F514}","\u{1F4CA}","\u{1F5D3}\uFE0F","\u26A1","\u{1F527}","\u{1F48A}","\u{1F9EA}","\u{1F52D}","\u{1F399}\uFE0F","\u{1F58B}\uFE0F","\u{1F4E6}","\u{1F6CD}\uFE0F","\u{1F4B3}","\u{1F510}"]},{label:"\uC790\uC5F0",emojis:["\u{1F308}","\u{1F338}","\u{1F33F}","\u{1F340}","\u{1F319}","\u2600\uFE0F","\u2B50","\u{1F30A}","\u{1F34E}","\u{1F33A}","\u2744\uFE0F","\u{1F334}","\u{1F335}","\u{1F344}","\u{1F33B}","\u{1F30D}","\u26C5","\u{1F32A}\uFE0F","\u{1F305}","\u{1F341}","\u{1F33E}","\u{1FAB8}","\u{1FAE7}","\u2604\uFE0F"]},{label:"\uD65C\uB3D9",emojis:["\u{1F3C3}","\u{1F9D8}","\u{1F3A8}","\u{1F373}","\u2708\uFE0F","\u{1F3D5}\uFE0F","\u{1F3A4}","\u{1F3CB}\uFE0F","\u{1F938}","\u{1F9E9}","\u{1F3AD}","\u{1F6D2}","\u{1F6B4}","\u{1F3CA}","\u26F7\uFE0F","\u{1F3B8}","\u{1F3B9}","\u{1F4F8}","\u{1F9D7}","\u{1F93F}","\u{1F3B2}","\u{1F3C6}","\u{1F3AF}","\u{1FA84}"]}];function ie({emoji:e,onClick:t,className:o=""}){return(0,d.jsx)("button",{onClick:t,className:`w-9 h-9 rounded-full flex items-center justify-center text-lg bg-zinc-100 dark:bg-zinc-800 hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-all hover:scale-110 active:scale-90 ${o}`,title:"Pick emoji",children:e})}function ae({open:e,onClose:t,current:o,onSelect:n}){let[a,c]=(0,j.useState)(0);if((0,j.useEffect)(()=>{if(!e)return;let l=s=>{s.key==="Escape"&&t()};return window.addEventListener("keydown",l),()=>window.removeEventListener("keydown",l)},[e,t]),!e)return null;let{emojis:f}=re[a];return(0,ne.createPortal)((0,d.jsxs)("div",{className:"fixed inset-0 z-50 flex items-end justify-center",onClick:t,children:[(0,d.jsx)("div",{className:"absolute inset-0 bg-black/40 backdrop-blur-sm"}),(0,d.jsxs)("div",{className:"relative z-10 w-full max-w-101.5 mb-3 mx-3 rounded-2xl bg-white dark:bg-zinc-900 shadow-2xl overflow-hidden",onClick:l=>l.stopPropagation(),children:[(0,d.jsx)("div",{className:"px-4 pt-4 pb-3",children:(0,d.jsx)("p",{className:"text-sm font-bold text-zinc-900 dark:text-white",children:"\uC774\uBAA8\uC9C0"})}),(0,d.jsx)("div",{className:"flex gap-1 px-4 pb-3 overflow-x-auto scrollbar-hide",children:re.map((l,s)=>(0,d.jsx)("button",{onClick:()=>c(s),className:`shrink-0 px-3 py-1.5 rounded-full text-xs font-semibold transition-colors ${a===s?"bg-zinc-900 dark:bg-white text-white dark:text-zinc-900":"bg-zinc-100 dark:bg-zinc-800 text-zinc-500 dark:text-zinc-400 hover:bg-zinc-200 dark:hover:bg-zinc-700"}`,children:l.label},l.label))}),(0,d.jsx)("div",{className:"px-4 pb-3 grid grid-cols-6 gap-2",children:f.map(l=>(0,d.jsx)("button",{onClick:()=>{n(l),t()},className:`h-11 rounded-xl flex items-center justify-center text-2xl transition-all hover:scale-110 active:scale-90 ${o===l?"bg-zinc-900 dark:bg-white":"bg-zinc-100 dark:bg-zinc-800 hover:bg-zinc-200 dark:hover:bg-zinc-700"}`,children:l},l))}),(0,d.jsx)("div",{className:"px-4 py-3 border-t border-zinc-100 dark:border-zinc-800",children:(0,d.jsx)("button",{onClick:t,className:"w-full py-2.5 rounded-xl bg-zinc-100 dark:bg-zinc-800 text-sm font-medium text-zinc-600 dark:text-zinc-400 hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors",children:"\uB2EB\uAE30"})})]})]}),document.body)}var se=require("react"),le=require("react-dom"),k=require("react/jsx-runtime");function ce({label:e,children:t,placement:o="top"}){let[n,a]=(0,se.useState)(null),c=i=>{a(i.currentTarget.getBoundingClientRect())},f=()=>a(null),l=n?o==="top"?n.top+window.scrollY-36:n.bottom+window.scrollY+8:0,s=n?n.left+window.scrollX+n.width/2:0;return(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)("span",{className:"inline-flex",onMouseEnter:c,onMouseLeave:f,onFocus:c,onBlur:f,children:t}),n&&(0,le.createPortal)((0,k.jsx)("div",{className:"fixed z-[9999] pointer-events-none",style:{top:l,left:s,transform:"translateX(-50%)"},children:(0,k.jsx)("div",{className:"px-3 py-1.5 rounded-xl bg-zinc-900 dark:bg-zinc-100 text-white dark:text-zinc-900 text-xs font-semibold whitespace-nowrap shadow-lg animate-in fade-in zoom-in-95 duration-100",children:e})}),document.body)]})}0&&(module.exports={AppShell,AppShellContent,AppShellHeader,Divider,EmojiButton,EmojiPicker,EmptyState,Section,SectionHeader,StatChip,Tab,TabBar,ThemeButton,ThemeDialog,Tooltip,Typewriter,Watermark,colors,fontFamily,fonts});
package/dist/index.mjs CHANGED
@@ -1,5 +1,12 @@
1
1
  "use client";
2
- import{jsx as p}from"react/jsx-runtime";function g({children:e,className:t="",maxWidth:r=430,style:s}){return p("div",{className:`w-full h-full flex flex-col bg-white dark:bg-zinc-950 shadow-2xl ring-1 ring-black/5 dark:ring-white/10 rounded-2xl overflow-hidden ${t}`,style:{maxWidth:r,...s},children:e})}function y({children:e,className:t=""}){return p("header",{className:`sticky top-0 z-20 px-4 py-3 flex items-center justify-between border-b border-zinc-100 dark:border-zinc-800 bg-white/90 dark:bg-zinc-950/90 backdrop-blur-md rounded-t-2xl ${t}`,children:e})}function k({children:e,className:t=""}){return p("div",{className:`flex-1 overflow-y-auto scrollbar-hide ${t}`,children:e})}import{jsx as m,jsxs as w}from"react/jsx-runtime";function v({children:e,className:t=""}){return m("nav",{className:`sticky bottom-0 z-20 border-t border-zinc-200 dark:border-zinc-800 flex bg-white/90 dark:bg-zinc-950/90 backdrop-blur-md rounded-b-2xl ${t}`,children:e})}function N({active:e,onClick:t,icon:r,label:s,activeColor:i}){return w("button",{onClick:t,className:`flex-1 flex flex-col items-center gap-0.5 py-2.5 transition-colors ${e?"":"text-zinc-300 dark:text-zinc-600"}`,style:e?{color:i}:void 0,children:[r,m("span",{className:"text-[10px] font-medium",children:s})]})}import{jsx as f}from"react/jsx-runtime";function z({children:e,className:t=""}){return f("section",{className:`px-4 ${t}`,children:e})}function P({children:e}){return f("h2",{className:"text-[11px] font-semibold text-zinc-400 dark:text-zinc-500 uppercase tracking-wider mb-3",children:e})}import{jsx as C}from"react/jsx-runtime";function S({className:e=""}){return C("div",{className:`mx-4 my-6 h-px bg-zinc-200 dark:bg-zinc-800 ${e}`})}import{jsx as x,jsxs as R}from"react/jsx-runtime";function T({label:e,value:t,className:r=""}){return R("div",{className:`flex-1 rounded-xl bg-zinc-100 dark:bg-zinc-900 px-3 py-3 text-center ${r}`,children:[x("p",{className:"text-[10px] text-zinc-500 dark:text-zinc-400 font-medium mb-0.5",children:e}),x("p",{className:"text-lg font-bold tabular-nums text-zinc-900 dark:text-white",children:t.toLocaleString()})]})}import{jsx as c,jsxs as h}from"react/jsx-runtime";function $({message:e,icon:t}){return h("div",{className:"flex flex-col items-center justify-center py-12 gap-2",children:[t||h("svg",{width:"32",height:"32",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",className:"text-zinc-200 dark:text-zinc-700",children:[c("circle",{cx:"12",cy:"12",r:"10"}),c("path",{d:"M8 15h8"}),c("circle",{cx:"9",cy:"9",r:"1",fill:"currentColor",stroke:"none"}),c("circle",{cx:"15",cy:"9",r:"1",fill:"currentColor",stroke:"none"})]}),c("p",{className:"text-sm text-zinc-400 dark:text-zinc-500",children:e})]})}import{jsx as b,jsxs as E}from"react/jsx-runtime";function A(e,t=.08){let i=`<svg xmlns="http://www.w3.org/2000/svg" width="220" height="120">
3
- <text x="10" y="45" font-family="system-ui,sans-serif" font-size="44" font-weight="900" fill="white" opacity="${t}">${e}</text>
4
- <text x="120" y="100" font-family="system-ui,sans-serif" font-size="44" font-weight="900" fill="white" opacity="${t}">${e}</text>
5
- </svg>`;return`url("data:image/svg+xml,${encodeURIComponent(i)}")`}function B({children:e,color:t="#0f172a",text:r="m1k",maxWidth:s=430,padding:i=12}){return E("div",{className:"h-dvh w-full relative overflow-hidden",style:{backgroundColor:t,transition:"background-color 0.5s ease"},children:[b("div",{className:"absolute inset-0 pointer-events-none select-none",style:{backgroundImage:A(r),backgroundRepeat:"repeat",transform:"rotate(-12deg) scale(1.5)",transformOrigin:"center center"}}),b("div",{className:"relative z-10 h-full flex items-center justify-center mx-auto",style:{maxWidth:s,padding:i},children:e})]})}var l={blue:"#3b82f6",purple:"#8b5cf6",green:"#10b981",orange:"#f97316",pink:"#ec4899",red:"#ef4444",yellow:"#eab308",cyan:"#06b6d4",slate:"#0f172a",zinc:"#27272a"};import{useEffect as H}from"react";import{jsx as o,jsxs as d}from"react/jsx-runtime";function W({color:e,onClick:t,className:r=""}){return o("button",{onClick:t,className:`w-7 h-7 rounded-full border-2 border-white dark:border-zinc-700 shadow-sm transition-transform hover:scale-110 ${r}`,style:{backgroundColor:e},title:"Change theme"})}function D({open:e,onClose:t,current:r,onSelect:s,palette:i=l}){if(H(()=>{if(!e)return;let a=n=>{n.key==="Escape"&&t()};return window.addEventListener("keydown",a),()=>window.removeEventListener("keydown",a)},[e,t]),!e)return null;let u=Object.entries(i);return d("div",{className:"fixed inset-0 z-50 flex items-end justify-center",onClick:t,children:[o("div",{className:"absolute inset-0 bg-black/40 backdrop-blur-sm"}),d("div",{className:"relative z-10 w-full max-w-[406px] mb-3 mx-3 rounded-2xl bg-white dark:bg-zinc-900 shadow-2xl overflow-hidden",onClick:a=>a.stopPropagation(),children:[d("div",{className:"px-4 pt-4 pb-2",children:[o("p",{className:"text-sm font-bold text-zinc-900 dark:text-white",children:"Theme Color"}),o("p",{className:"text-xs text-zinc-400 dark:text-zinc-500 mt-0.5",children:"Change the Watermark background"})]}),o("div",{className:"px-4 pb-3 grid grid-cols-5 gap-3 justify-items-center",children:u.map(([a,n])=>o("button",{onClick:()=>{s(n),t()},className:`relative w-11 h-11 rounded-full transition-all hover:scale-110 ${r===n?"ring-2 ring-offset-2 ring-offset-white dark:ring-offset-zinc-900":""}`,style:{backgroundColor:n,...r===n?{"--tw-ring-color":n}:{}},children:r===n&&o("div",{className:"absolute inset-0 flex items-center justify-center",children:o("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"3",strokeLinecap:"round",strokeLinejoin:"round",children:o("polyline",{points:"20 6 9 17 4 12"})})})},n))}),o("div",{className:"px-4 py-3 border-t border-zinc-100 dark:border-zinc-800",children:o("button",{onClick:t,className:"w-full py-2.5 rounded-xl bg-zinc-100 dark:bg-zinc-800 text-sm font-medium text-zinc-600 dark:text-zinc-400 hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors",children:"Close"})})]})]})}var L={toss:"https://static.toss.im/dist/tps.css",pretendard:"https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css",inter:"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;900&display=swap"},F={toss:'"Toss Product Sans", "Pretendard", system-ui, sans-serif',pretendard:'"Pretendard Variable", "Pretendard", system-ui, sans-serif',inter:'"Inter", system-ui, sans-serif'};export{g as AppShell,k as AppShellContent,y as AppShellHeader,S as Divider,$ as EmptyState,z as Section,P as SectionHeader,T as StatChip,N as Tab,v as TabBar,W as ThemeButton,D as ThemeDialog,B as Watermark,l as colors,F as fontFamily,L as fonts};
2
+ import{jsx as E}from"react/jsx-runtime";function K({children:e,className:t="",maxWidth:o=430,style:r}){return E("div",{className:`w-full h-full flex flex-col bg-white dark:bg-zinc-950 shadow-2xl ring-1 ring-black/10 dark:ring-zinc-700 rounded-2xl overflow-hidden ${t}`,style:{maxWidth:o,...r},children:e})}function X({children:e,className:t=""}){return E("header",{className:`sticky top-0 z-20 h-14 px-4 flex items-center justify-between border-b border-zinc-100 dark:border-zinc-800 bg-white/90 dark:bg-zinc-950/90 backdrop-blur-md rounded-t-2xl ${t}`,children:e})}function V({children:e,className:t=""}){return E("div",{className:`flex-1 overflow-y-auto scrollbar-hide ${t}`,children:e})}import{jsx as $,jsxs as J}from"react/jsx-runtime";function Z({children:e,className:t=""}){return $("nav",{className:`sticky bottom-0 z-20 h-16 border-t border-zinc-200 dark:border-zinc-800 flex bg-white/90 dark:bg-zinc-950/90 backdrop-blur-md rounded-b-2xl ${t}`,children:e})}function G({active:e,onClick:t,icon:o,label:r,activeColor:c}){return J("button",{onClick:t,className:`flex-1 flex flex-col items-center gap-0.5 py-2.5 transition-colors ${e?"":"text-zinc-300 dark:text-zinc-600"}`,style:e?{color:c}:void 0,children:[o,$("span",{className:"text-[10px] font-medium",children:r})]})}import{jsx as A}from"react/jsx-runtime";function q({children:e,className:t=""}){return A("section",{className:`px-4 ${t}`,children:e})}function Q({children:e}){return A("h2",{className:"text-[11px] font-semibold text-zinc-400 dark:text-zinc-500 uppercase tracking-wider mb-3",children:e})}import{jsx as ee}from"react/jsx-runtime";function U({className:e=""}){return ee("div",{className:`mx-4 my-6 h-px bg-zinc-200 dark:bg-zinc-800 ${e}`})}import{jsx as W,jsxs as oe}from"react/jsx-runtime";function te({label:e,value:t,className:o=""}){return oe("div",{className:`flex-1 rounded-xl bg-zinc-100 dark:bg-zinc-900 px-3 py-3 text-center ${o}`,children:[W("p",{className:"text-[10px] text-zinc-500 dark:text-zinc-400 font-medium mb-0.5",children:e}),W("p",{className:"text-lg font-bold tabular-nums text-zinc-900 dark:text-white",children:t.toLocaleString()})]})}import{jsx as v,jsxs as L}from"react/jsx-runtime";function re({message:e,icon:t}){return L("div",{className:"flex flex-col items-center justify-center py-12 gap-2",children:[t||L("svg",{width:"32",height:"32",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",className:"text-zinc-200 dark:text-zinc-700",children:[v("circle",{cx:"12",cy:"12",r:"10"}),v("path",{d:"M8 15h8"}),v("circle",{cx:"9",cy:"9",r:"1",fill:"currentColor",stroke:"none"}),v("circle",{cx:"15",cy:"9",r:"1",fill:"currentColor",stroke:"none"})]}),v("p",{className:"text-sm text-zinc-400 dark:text-zinc-500",children:e})]})}import{jsx as z,jsxs as se}from"react/jsx-runtime";var ne=`
3
+ @keyframes watermark-drift {
4
+ 0% { transform: rotate(-12deg) scale(2) translate(0, 0); }
5
+ 100% { transform: rotate(-12deg) scale(2) translate(180px, 100px); }
6
+ }
7
+ `,D=!1;function ie(){if(D||typeof document>"u")return;let e=document.createElement("style");e.textContent=ne,document.head.appendChild(e),D=!0}function ae({children:e,color:t="#0f172a",text:o="m1k",maxWidth:r=430,padding:c=12,sponsor:l,speed:m=20}){ie();let a=Math.max(14,Math.min(28,Math.floor(160/o.length))),i=l?Math.max(14,Math.min(28,Math.floor(160/l.name.length))):a,n=180,p=100,k=16,u=16,w=k*n/2,P=u*p/2;return se("div",{className:"h-dvh w-full relative overflow-hidden",style:{backgroundColor:t,transition:"background-color 0.5s ease"},children:[z("div",{className:"absolute inset-0 pointer-events-none select-none",style:{transformOrigin:"center center",animation:m>0?`watermark-drift ${m}s linear infinite`:void 0,transform:"rotate(-12deg) scale(2)"},children:Array.from({length:u}).flatMap((S,f)=>Array.from({length:k}).map((B,b)=>{let y=b*n-w+n/2,T=f*p-P+p/2,C=(f+b)%2===1&&l,d={position:"absolute",left:y,top:T,transform:"translate(-50%, -50%)",fontWeight:900,color:"rgba(255,255,255,0.12)",whiteSpace:"nowrap",lineHeight:1};return C?z("a",{href:l.url,target:"_blank",rel:"noopener noreferrer",className:"hover:opacity-30 transition-opacity",style:{...d,fontSize:i,textDecoration:"none",pointerEvents:"auto"},children:l.name},`${f}-${b}`):z("a",{href:"https://m1k.app",target:"_blank",rel:"noopener noreferrer",className:"hover:opacity-30 transition-opacity",style:{...d,fontSize:a,textDecoration:"none",pointerEvents:"auto"},children:o},`${f}-${b}`)}))}),z("div",{className:"relative z-10 h-full flex items-center justify-center mx-auto",style:{maxWidth:r,padding:c},children:e})]})}var j={blue:"#3b82f6",purple:"#8b5cf6",green:"#10b981",orange:"#f97316",pink:"#ec4899",red:"#ef4444",yellow:"#eab308",cyan:"#06b6d4",slate:"#0f172a",zinc:"#27272a"};import{useEffect as le}from"react";import{jsx as s,jsxs as g}from"react/jsx-runtime";function ce({color:e,dark:t=!1,onClick:o,className:r=""}){let c=t?"#000":"#fff",l=t?"rgba(255,255,255,0.15)":"rgba(0,0,0,0.12)";return s("button",{onClick:o,className:`w-7 h-7 rounded-full transition-all active:scale-90 hover:scale-110 overflow-hidden ${r}`,style:{boxShadow:`0 2px 10px ${e}55`},title:"Theme",children:g("svg",{width:"100%",height:"100%",viewBox:"0 0 100 100",children:[s("path",{d:"M0 0 L100 0 L0 100 Z",fill:c}),s("path",{d:"M100 0 L100 100 L0 100 Z",fill:e}),s("circle",{cx:"50",cy:"50",r:"49",fill:"none",stroke:l,strokeWidth:"2"})]})})}function pe({open:e,onClose:t,current:o,onSelect:r,dark:c=!1,onDarkToggle:l,palette:m=j}){if(le(()=>{if(!e)return;let i=n=>{n.key==="Escape"&&t()};return window.addEventListener("keydown",i),()=>window.removeEventListener("keydown",i)},[e,t]),!e)return null;let a=Object.entries(m);return g("div",{className:"fixed inset-0 z-50 flex items-end justify-center",onClick:t,children:[s("div",{className:"absolute inset-0 bg-black/40 backdrop-blur-sm"}),g("div",{className:"relative z-10 w-full max-w-101.5 mb-3 mx-3 rounded-2xl bg-white dark:bg-zinc-900 shadow-2xl overflow-hidden",onClick:i=>i.stopPropagation(),children:[g("div",{className:"px-4 pt-4 pb-3",children:[s("p",{className:"text-sm font-bold text-zinc-900 dark:text-white mb-3",children:"\uD14C\uB9C8"}),l&&s("div",{className:"flex gap-2 mb-4",children:[{label:"\uB77C\uC774\uD2B8",isDark:!1},{label:"\uB2E4\uD06C",isDark:!0}].map(i=>{let n=c===i.isDark;return g("button",{onClick:()=>{n||l()},className:`flex-1 flex items-center justify-center gap-2 py-2.5 rounded-2xl transition-all ${n?"bg-zinc-900 dark:bg-white ring-2 ring-zinc-900 dark:ring-white ring-offset-2 ring-offset-white dark:ring-offset-zinc-900":"bg-zinc-100 dark:bg-zinc-800 hover:bg-zinc-200 dark:hover:bg-zinc-700"}`,children:[i.isDark?s("svg",{width:"15",height:"15",viewBox:"-1 -1 26 26",fill:n?"#18181b":"#71717a",children:s("path",{d:"M21 12.79A9 9 0 1 1 11.21 3a7 7 0 0 0 9.79 9.79z"})}):g("svg",{width:"15",height:"15",viewBox:"-1 -1 26 26",fill:n?"white":"#71717a",children:[s("circle",{cx:"12",cy:"12",r:"5"}),s("path",{d:"M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42",stroke:n?"white":"#71717a",strokeWidth:"2",strokeLinecap:"round"})]}),s("span",{className:`text-sm font-semibold ${n?"text-white dark:text-zinc-900":"text-zinc-400 dark:text-zinc-500"}`,children:i.label})]},i.label)})})]}),s("div",{className:"px-4 pb-3 grid grid-cols-5 gap-3 justify-items-center",children:a.map(([i,n])=>s("button",{onClick:()=>{r(n),t()},className:"relative w-11 h-11 rounded-full transition-all hover:scale-110",style:{backgroundColor:n,boxShadow:o===n?`0 0 0 2px #fff, 0 0 0 4px ${n}`:"0 0 0 1.5px rgba(255,255,255,0.5), 0 2px 8px rgba(255,255,255,0.2)"},children:o===n&&s("div",{className:"absolute inset-0 flex items-center justify-center",children:s("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"3",strokeLinecap:"round",strokeLinejoin:"round",children:s("polyline",{points:"20 6 9 17 4 12"})})})},n))}),s("div",{className:"px-4 py-3 border-t border-zinc-100 dark:border-zinc-800",children:s("button",{onClick:t,className:"w-full py-2.5 rounded-xl bg-zinc-100 dark:bg-zinc-800 text-sm font-medium text-zinc-600 dark:text-zinc-400 hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors",children:"Close"})})]})]})}var de={tossface:"https://cdn.jsdelivr.net/gh/toss/tossface/dist/tossface.css",pretendard:"https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css",inter:"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;900&display=swap"},me={default:'"Pretendard Variable", "Pretendard", system-ui, -apple-system, sans-serif, "Tossface"',pretendard:'"Pretendard Variable", "Pretendard", system-ui, sans-serif',inter:'"Inter", system-ui, sans-serif'};import{useState as N,useEffect as H}from"react";import{Fragment as ue,jsx as M,jsxs as I}from"react/jsx-runtime";function fe({words:e,color:t="currentColor",speed:o=80,deleteSpeed:r=30,pauseMs:c=2200,gapMs:l=400,cursorColor:m,className:a=""}){let[i,n]=N(0),[p,k]=N(0),[u,w]=N(!1),[P,S]=N(!0),f=e[i]||"",B=m||t,b=u?p>0:p<f.length;H(()=>{if(b){S(!0);return}let d=setInterval(()=>S(h=>!h),530);return()=>clearInterval(d)},[b]),H(()=>{if(!u&&p<f.length){let d=Math.random()*o,h=f[p-1]===" "?o*.4:0,O=setTimeout(()=>k(_=>_+1),o*.75+d+h);return()=>clearTimeout(O)}if(!u&&p===f.length){let d=setTimeout(()=>w(!0),c);return()=>clearTimeout(d)}if(u&&p>0){let d=setTimeout(()=>k(h=>h-1),r+Math.random()*r*.6);return()=>clearTimeout(d)}if(u&&p===0){let d=setTimeout(()=>{w(!1),n(h=>(h+1)%e.length)},l);return()=>clearTimeout(d)}},[p,u,f,o,r,c,l,e.length]);let y=f.slice(0,p),T=y[y.length-1],C=y.slice(0,-1);return I("span",{className:a,style:{color:t},children:[p>0&&I(ue,{children:[C,M("span",{className:"inline-block",style:{animation:u?void 0:"m1k-char-pop 0.1s ease-out"},children:T},`${i}-${p}`)]}),M("span",{className:"inline-block w-0.5 h-[1em] ml-px align-middle rounded-full",style:{backgroundColor:B,opacity:P?1:0,transition:"opacity 0.1s"}}),M("style",{children:`
8
+ @keyframes m1k-char-pop {
9
+ 0% { opacity: 0; transform: translateY(4px); }
10
+ 100% { opacity: 1; transform: translateY(0); }
11
+ }
12
+ `})]})}import{useEffect as xe,useState as be}from"react";import{createPortal as he}from"react-dom";import{jsx as x,jsxs as Y}from"react/jsx-runtime";var F=[{label:"\uC790\uC8FC \uC4F0\uB294",emojis:["\u{1F3E0}","\u{1F50D}","\u{1F464}","\u2B50","\u2764\uFE0F","\u{1F525}","\u2705","\u{1F4CC}","\u{1F3AF}","\u{1F4A1}","\u{1F680}","\u{1F4AC}","\u{1F44D}","\u{1F64C}","\u{1F4AA}","\u{1F389}","\u{1F4E2}","\u{1F511}","\u26A1","\u{1F31F}","\u{1F380}","\u{1F9E1}","\u{1FAF6}","\u{1F947}"]},{label:"\uAC10\uC815",emojis:["\u{1F600}","\u{1F604}","\u{1F606}","\u{1F60E}","\u{1F979}","\u{1F60D}","\u{1F929}","\u{1F605}","\u{1F602}","\u{1F972}","\u{1F62D}","\u{1F624}","\u{1F914}","\u{1F607}","\u{1FAF6}","\u{1F917}","\u{1F634}","\u{1F92F}","\u{1F973}","\u{1F62C}","\u{1FAE0}","\u{1F92B}","\u{1F636}","\u{1FAE1}"]},{label:"\uB3D9\uBB3C",emojis:["\u{1F436}","\u{1F431}","\u{1F42D}","\u{1F439}","\u{1F430}","\u{1F98A}","\u{1F43B}","\u{1F43C}","\u{1F428}","\u{1F42F}","\u{1F981}","\u{1F42E}","\u{1F437}","\u{1F438}","\u{1F435}","\u{1F414}","\u{1F427}","\u{1F426}","\u{1F986}","\u{1F989}","\u{1F98B}","\u{1F422}","\u{1F42C}","\u{1F433}"]},{label:"\uC0AC\uBB3C",emojis:["\u{1F4F1}","\u{1F4BB}","\u2328\uFE0F","\u{1F5A5}\uFE0F","\u{1F4F7}","\u{1F3B5}","\u{1F3AE}","\u{1F4DA}","\u{1F4B0}","\u{1F381}","\u{1F514}","\u{1F4CA}","\u{1F5D3}\uFE0F","\u26A1","\u{1F527}","\u{1F48A}","\u{1F9EA}","\u{1F52D}","\u{1F399}\uFE0F","\u{1F58B}\uFE0F","\u{1F4E6}","\u{1F6CD}\uFE0F","\u{1F4B3}","\u{1F510}"]},{label:"\uC790\uC5F0",emojis:["\u{1F308}","\u{1F338}","\u{1F33F}","\u{1F340}","\u{1F319}","\u2600\uFE0F","\u2B50","\u{1F30A}","\u{1F34E}","\u{1F33A}","\u2744\uFE0F","\u{1F334}","\u{1F335}","\u{1F344}","\u{1F33B}","\u{1F30D}","\u26C5","\u{1F32A}\uFE0F","\u{1F305}","\u{1F341}","\u{1F33E}","\u{1FAB8}","\u{1FAE7}","\u2604\uFE0F"]},{label:"\uD65C\uB3D9",emojis:["\u{1F3C3}","\u{1F9D8}","\u{1F3A8}","\u{1F373}","\u2708\uFE0F","\u{1F3D5}\uFE0F","\u{1F3A4}","\u{1F3CB}\uFE0F","\u{1F938}","\u{1F9E9}","\u{1F3AD}","\u{1F6D2}","\u{1F6B4}","\u{1F3CA}","\u26F7\uFE0F","\u{1F3B8}","\u{1F3B9}","\u{1F4F8}","\u{1F9D7}","\u{1F93F}","\u{1F3B2}","\u{1F3C6}","\u{1F3AF}","\u{1FA84}"]}];function ge({emoji:e,onClick:t,className:o=""}){return x("button",{onClick:t,className:`w-9 h-9 rounded-full flex items-center justify-center text-lg bg-zinc-100 dark:bg-zinc-800 hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-all hover:scale-110 active:scale-90 ${o}`,title:"Pick emoji",children:e})}function ke({open:e,onClose:t,current:o,onSelect:r}){let[c,l]=be(0);if(xe(()=>{if(!e)return;let a=i=>{i.key==="Escape"&&t()};return window.addEventListener("keydown",a),()=>window.removeEventListener("keydown",a)},[e,t]),!e)return null;let{emojis:m}=F[c];return he(Y("div",{className:"fixed inset-0 z-50 flex items-end justify-center",onClick:t,children:[x("div",{className:"absolute inset-0 bg-black/40 backdrop-blur-sm"}),Y("div",{className:"relative z-10 w-full max-w-101.5 mb-3 mx-3 rounded-2xl bg-white dark:bg-zinc-900 shadow-2xl overflow-hidden",onClick:a=>a.stopPropagation(),children:[x("div",{className:"px-4 pt-4 pb-3",children:x("p",{className:"text-sm font-bold text-zinc-900 dark:text-white",children:"\uC774\uBAA8\uC9C0"})}),x("div",{className:"flex gap-1 px-4 pb-3 overflow-x-auto scrollbar-hide",children:F.map((a,i)=>x("button",{onClick:()=>l(i),className:`shrink-0 px-3 py-1.5 rounded-full text-xs font-semibold transition-colors ${c===i?"bg-zinc-900 dark:bg-white text-white dark:text-zinc-900":"bg-zinc-100 dark:bg-zinc-800 text-zinc-500 dark:text-zinc-400 hover:bg-zinc-200 dark:hover:bg-zinc-700"}`,children:a.label},a.label))}),x("div",{className:"px-4 pb-3 grid grid-cols-6 gap-2",children:m.map(a=>x("button",{onClick:()=>{r(a),t()},className:`h-11 rounded-xl flex items-center justify-center text-2xl transition-all hover:scale-110 active:scale-90 ${o===a?"bg-zinc-900 dark:bg-white":"bg-zinc-100 dark:bg-zinc-800 hover:bg-zinc-200 dark:hover:bg-zinc-700"}`,children:a},a))}),x("div",{className:"px-4 py-3 border-t border-zinc-100 dark:border-zinc-800",children:x("button",{onClick:t,className:"w-full py-2.5 rounded-xl bg-zinc-100 dark:bg-zinc-800 text-sm font-medium text-zinc-600 dark:text-zinc-400 hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors",children:"\uB2EB\uAE30"})})]})]}),document.body)}import{useState as ye}from"react";import{createPortal as ve}from"react-dom";import{Fragment as ze,jsx as R,jsxs as Ne}from"react/jsx-runtime";function we({label:e,children:t,placement:o="top"}){let[r,c]=ye(null),l=n=>{c(n.currentTarget.getBoundingClientRect())},m=()=>c(null),a=r?o==="top"?r.top+window.scrollY-36:r.bottom+window.scrollY+8:0,i=r?r.left+window.scrollX+r.width/2:0;return Ne(ze,{children:[R("span",{className:"inline-flex",onMouseEnter:l,onMouseLeave:m,onFocus:l,onBlur:m,children:t}),r&&ve(R("div",{className:"fixed z-[9999] pointer-events-none",style:{top:a,left:i,transform:"translateX(-50%)"},children:R("div",{className:"px-3 py-1.5 rounded-xl bg-zinc-900 dark:bg-zinc-100 text-white dark:text-zinc-900 text-xs font-semibold whitespace-nowrap shadow-lg animate-in fade-in zoom-in-95 duration-100",children:e})}),document.body)]})}export{K as AppShell,V as AppShellContent,X as AppShellHeader,U as Divider,ge as EmojiButton,ke as EmojiPicker,re as EmptyState,q as Section,Q as SectionHeader,te as StatChip,G as Tab,Z as TabBar,ce as ThemeButton,pe as ThemeDialog,we as Tooltip,fe as Typewriter,ae as Watermark,j as colors,me as fontFamily,de as fonts};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m1kapp/ui",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Mobile-first app shell UI components for side projects",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -47,7 +47,7 @@
47
47
  "license": "MIT",
48
48
  "repository": {
49
49
  "type": "git",
50
- "url": "https://github.com/yoo-minho/m1kapp-ui"
50
+ "url": "https://github.com/m1kapp/ui"
51
51
  },
52
52
  "homepage": "https://m1k.app"
53
53
  }