@m1kapp/ui 0.1.0
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/LICENSE +21 -0
- package/README.md +153 -0
- package/dist/index.d.mts +113 -0
- package/dist/index.d.ts +113 -0
- package/dist/index.js +194 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +158 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 m1k
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# @m1k/ui
|
|
2
|
+
|
|
3
|
+
> Mobile-first app shell for side projects.
|
|
4
|
+
> Build apps that feel like native — in minutes.
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
┌─────────────────────┐
|
|
8
|
+
│ Header (sticky) │
|
|
9
|
+
├─────────────────────┤
|
|
10
|
+
│ │
|
|
11
|
+
│ Content (scroll) │
|
|
12
|
+
│ │
|
|
13
|
+
├─────────────────────┤
|
|
14
|
+
│ TabBar (sticky) │
|
|
15
|
+
└─────────────────────┘
|
|
16
|
+
rounded, shadow
|
|
17
|
+
floating on color
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install @m1k/ui
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import {
|
|
30
|
+
Watermark,
|
|
31
|
+
AppShell,
|
|
32
|
+
AppShellHeader,
|
|
33
|
+
AppShellContent,
|
|
34
|
+
TabBar,
|
|
35
|
+
Tab,
|
|
36
|
+
Section,
|
|
37
|
+
SectionHeader,
|
|
38
|
+
Divider,
|
|
39
|
+
StatChip,
|
|
40
|
+
EmptyState,
|
|
41
|
+
} from "@m1k/ui";
|
|
42
|
+
|
|
43
|
+
export default function App() {
|
|
44
|
+
const [tab, setTab] = useState("home");
|
|
45
|
+
|
|
46
|
+
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>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Components
|
|
87
|
+
|
|
88
|
+
### Layout
|
|
89
|
+
|
|
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
|
|
100
|
+
|
|
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 |
|
|
108
|
+
|
|
109
|
+
## Props
|
|
110
|
+
|
|
111
|
+
### `Watermark`
|
|
112
|
+
|
|
113
|
+
| Prop | Type | Default | Description |
|
|
114
|
+
|------|------|---------|-------------|
|
|
115
|
+
| `color` | `string` | `#0f172a` | Background color |
|
|
116
|
+
| `text` | `string` | `m1k` | Watermark pattern text |
|
|
117
|
+
| `maxWidth` | `number` | `430` | Max width of content area |
|
|
118
|
+
| `padding` | `number` | `12` | Padding around the shell |
|
|
119
|
+
|
|
120
|
+
### `AppShell`
|
|
121
|
+
|
|
122
|
+
| Prop | Type | Default | Description |
|
|
123
|
+
|------|------|---------|-------------|
|
|
124
|
+
| `maxWidth` | `number` | `430` | Max width |
|
|
125
|
+
| `className` | `string` | | Additional classes |
|
|
126
|
+
|
|
127
|
+
### `Tab`
|
|
128
|
+
|
|
129
|
+
| Prop | Type | Description |
|
|
130
|
+
|------|------|-------------|
|
|
131
|
+
| `active` | `boolean` | Whether tab is selected |
|
|
132
|
+
| `onClick` | `() => void` | Click handler |
|
|
133
|
+
| `icon` | `ReactNode` | Tab icon |
|
|
134
|
+
| `label` | `string` | Tab label text |
|
|
135
|
+
| `activeColor` | `string?` | Color when active |
|
|
136
|
+
|
|
137
|
+
## Requirements
|
|
138
|
+
|
|
139
|
+
- React 18+
|
|
140
|
+
- Tailwind CSS 4+
|
|
141
|
+
|
|
142
|
+
## Philosophy
|
|
143
|
+
|
|
144
|
+
In the AI era, building a side project takes a day.
|
|
145
|
+
But making it *feel* like an app still takes effort.
|
|
146
|
+
|
|
147
|
+
`@m1k/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.
|
|
148
|
+
|
|
149
|
+
Built and battle-tested in [m1k](https://m1k.app).
|
|
150
|
+
|
|
151
|
+
## License
|
|
152
|
+
|
|
153
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode, CSSProperties } from 'react';
|
|
3
|
+
|
|
4
|
+
interface AppShellProps {
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
className?: string;
|
|
7
|
+
/** Max width of the shell. Default: 430px */
|
|
8
|
+
maxWidth?: number;
|
|
9
|
+
style?: CSSProperties;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Mobile app-like container with rounded corners, shadow, and ring.
|
|
13
|
+
* Centers content and constrains width for a phone-like viewport.
|
|
14
|
+
*/
|
|
15
|
+
declare function AppShell({ children, className, maxWidth, style, }: AppShellProps): react_jsx_runtime.JSX.Element;
|
|
16
|
+
interface AppShellHeaderProps {
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Sticky top header with blur backdrop.
|
|
22
|
+
*/
|
|
23
|
+
declare function AppShellHeader({ children, className }: AppShellHeaderProps): react_jsx_runtime.JSX.Element;
|
|
24
|
+
interface AppShellContentProps {
|
|
25
|
+
children: ReactNode;
|
|
26
|
+
className?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Scrollable main content area.
|
|
30
|
+
*/
|
|
31
|
+
declare function AppShellContent({ children, className }: AppShellContentProps): react_jsx_runtime.JSX.Element;
|
|
32
|
+
|
|
33
|
+
interface TabBarProps {
|
|
34
|
+
children: ReactNode;
|
|
35
|
+
className?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Sticky bottom navigation tab bar.
|
|
39
|
+
*/
|
|
40
|
+
declare function TabBar({ children, className }: TabBarProps): react_jsx_runtime.JSX.Element;
|
|
41
|
+
interface TabProps {
|
|
42
|
+
active: boolean;
|
|
43
|
+
onClick: () => void;
|
|
44
|
+
icon: ReactNode;
|
|
45
|
+
label: string;
|
|
46
|
+
/** Active tab color. Default: current text color */
|
|
47
|
+
activeColor?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Individual tab button for the TabBar.
|
|
51
|
+
*/
|
|
52
|
+
declare function Tab({ active, onClick, icon, label, activeColor }: TabProps): react_jsx_runtime.JSX.Element;
|
|
53
|
+
|
|
54
|
+
interface SectionProps {
|
|
55
|
+
children: ReactNode;
|
|
56
|
+
className?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Padded section wrapper (px-4).
|
|
60
|
+
*/
|
|
61
|
+
declare function Section({ children, className }: SectionProps): react_jsx_runtime.JSX.Element;
|
|
62
|
+
interface SectionHeaderProps {
|
|
63
|
+
children: ReactNode;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Small uppercase section title.
|
|
67
|
+
*/
|
|
68
|
+
declare function SectionHeader({ children }: SectionHeaderProps): react_jsx_runtime.JSX.Element;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Horizontal divider line with margin.
|
|
72
|
+
*/
|
|
73
|
+
declare function Divider({ className }: {
|
|
74
|
+
className?: string;
|
|
75
|
+
}): react_jsx_runtime.JSX.Element;
|
|
76
|
+
|
|
77
|
+
interface StatChipProps {
|
|
78
|
+
label: string;
|
|
79
|
+
value: number;
|
|
80
|
+
className?: string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Compact stat display chip with label and number.
|
|
84
|
+
*/
|
|
85
|
+
declare function StatChip({ label, value, className }: StatChipProps): react_jsx_runtime.JSX.Element;
|
|
86
|
+
|
|
87
|
+
interface EmptyStateProps {
|
|
88
|
+
message: string;
|
|
89
|
+
icon?: ReactNode;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Empty state placeholder with icon and message.
|
|
93
|
+
*/
|
|
94
|
+
declare function EmptyState({ message, icon }: EmptyStateProps): react_jsx_runtime.JSX.Element;
|
|
95
|
+
|
|
96
|
+
interface WatermarkProps {
|
|
97
|
+
children: ReactNode;
|
|
98
|
+
/** Background color */
|
|
99
|
+
color?: string;
|
|
100
|
+
/** Watermark text. Default: "m1k" */
|
|
101
|
+
text?: string;
|
|
102
|
+
/** Max width of content area. Default: 430 */
|
|
103
|
+
maxWidth?: number;
|
|
104
|
+
/** Padding around the app shell. Default: 12px */
|
|
105
|
+
padding?: number;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Full-screen colored background with repeating text watermark pattern.
|
|
109
|
+
* Wraps the AppShell and provides the "floating app" look.
|
|
110
|
+
*/
|
|
111
|
+
declare function Watermark({ children, color, text, maxWidth, padding, }: WatermarkProps): react_jsx_runtime.JSX.Element;
|
|
112
|
+
|
|
113
|
+
export { AppShell, AppShellContent, type AppShellContentProps, AppShellHeader, type AppShellHeaderProps, type AppShellProps, Divider, EmptyState, type EmptyStateProps, Section, SectionHeader, type SectionHeaderProps, type SectionProps, StatChip, type StatChipProps, Tab, TabBar, type TabBarProps, type TabProps, Watermark, type WatermarkProps };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode, CSSProperties } from 'react';
|
|
3
|
+
|
|
4
|
+
interface AppShellProps {
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
className?: string;
|
|
7
|
+
/** Max width of the shell. Default: 430px */
|
|
8
|
+
maxWidth?: number;
|
|
9
|
+
style?: CSSProperties;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Mobile app-like container with rounded corners, shadow, and ring.
|
|
13
|
+
* Centers content and constrains width for a phone-like viewport.
|
|
14
|
+
*/
|
|
15
|
+
declare function AppShell({ children, className, maxWidth, style, }: AppShellProps): react_jsx_runtime.JSX.Element;
|
|
16
|
+
interface AppShellHeaderProps {
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Sticky top header with blur backdrop.
|
|
22
|
+
*/
|
|
23
|
+
declare function AppShellHeader({ children, className }: AppShellHeaderProps): react_jsx_runtime.JSX.Element;
|
|
24
|
+
interface AppShellContentProps {
|
|
25
|
+
children: ReactNode;
|
|
26
|
+
className?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Scrollable main content area.
|
|
30
|
+
*/
|
|
31
|
+
declare function AppShellContent({ children, className }: AppShellContentProps): react_jsx_runtime.JSX.Element;
|
|
32
|
+
|
|
33
|
+
interface TabBarProps {
|
|
34
|
+
children: ReactNode;
|
|
35
|
+
className?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Sticky bottom navigation tab bar.
|
|
39
|
+
*/
|
|
40
|
+
declare function TabBar({ children, className }: TabBarProps): react_jsx_runtime.JSX.Element;
|
|
41
|
+
interface TabProps {
|
|
42
|
+
active: boolean;
|
|
43
|
+
onClick: () => void;
|
|
44
|
+
icon: ReactNode;
|
|
45
|
+
label: string;
|
|
46
|
+
/** Active tab color. Default: current text color */
|
|
47
|
+
activeColor?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Individual tab button for the TabBar.
|
|
51
|
+
*/
|
|
52
|
+
declare function Tab({ active, onClick, icon, label, activeColor }: TabProps): react_jsx_runtime.JSX.Element;
|
|
53
|
+
|
|
54
|
+
interface SectionProps {
|
|
55
|
+
children: ReactNode;
|
|
56
|
+
className?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Padded section wrapper (px-4).
|
|
60
|
+
*/
|
|
61
|
+
declare function Section({ children, className }: SectionProps): react_jsx_runtime.JSX.Element;
|
|
62
|
+
interface SectionHeaderProps {
|
|
63
|
+
children: ReactNode;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Small uppercase section title.
|
|
67
|
+
*/
|
|
68
|
+
declare function SectionHeader({ children }: SectionHeaderProps): react_jsx_runtime.JSX.Element;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Horizontal divider line with margin.
|
|
72
|
+
*/
|
|
73
|
+
declare function Divider({ className }: {
|
|
74
|
+
className?: string;
|
|
75
|
+
}): react_jsx_runtime.JSX.Element;
|
|
76
|
+
|
|
77
|
+
interface StatChipProps {
|
|
78
|
+
label: string;
|
|
79
|
+
value: number;
|
|
80
|
+
className?: string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Compact stat display chip with label and number.
|
|
84
|
+
*/
|
|
85
|
+
declare function StatChip({ label, value, className }: StatChipProps): react_jsx_runtime.JSX.Element;
|
|
86
|
+
|
|
87
|
+
interface EmptyStateProps {
|
|
88
|
+
message: string;
|
|
89
|
+
icon?: ReactNode;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Empty state placeholder with icon and message.
|
|
93
|
+
*/
|
|
94
|
+
declare function EmptyState({ message, icon }: EmptyStateProps): react_jsx_runtime.JSX.Element;
|
|
95
|
+
|
|
96
|
+
interface WatermarkProps {
|
|
97
|
+
children: ReactNode;
|
|
98
|
+
/** Background color */
|
|
99
|
+
color?: string;
|
|
100
|
+
/** Watermark text. Default: "m1k" */
|
|
101
|
+
text?: string;
|
|
102
|
+
/** Max width of content area. Default: 430 */
|
|
103
|
+
maxWidth?: number;
|
|
104
|
+
/** Padding around the app shell. Default: 12px */
|
|
105
|
+
padding?: number;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Full-screen colored background with repeating text watermark pattern.
|
|
109
|
+
* Wraps the AppShell and provides the "floating app" look.
|
|
110
|
+
*/
|
|
111
|
+
declare function Watermark({ children, color, text, maxWidth, padding, }: WatermarkProps): react_jsx_runtime.JSX.Element;
|
|
112
|
+
|
|
113
|
+
export { AppShell, AppShellContent, type AppShellContentProps, AppShellHeader, type AppShellHeaderProps, type AppShellProps, Divider, EmptyState, type EmptyStateProps, Section, SectionHeader, type SectionHeaderProps, type SectionProps, StatChip, type StatChipProps, Tab, TabBar, type TabBarProps, type TabProps, Watermark, type WatermarkProps };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/index.ts
|
|
22
|
+
var index_exports = {};
|
|
23
|
+
__export(index_exports, {
|
|
24
|
+
AppShell: () => AppShell,
|
|
25
|
+
AppShellContent: () => AppShellContent,
|
|
26
|
+
AppShellHeader: () => AppShellHeader,
|
|
27
|
+
Divider: () => Divider,
|
|
28
|
+
EmptyState: () => EmptyState,
|
|
29
|
+
Section: () => Section,
|
|
30
|
+
SectionHeader: () => SectionHeader,
|
|
31
|
+
StatChip: () => StatChip,
|
|
32
|
+
Tab: () => Tab,
|
|
33
|
+
TabBar: () => TabBar,
|
|
34
|
+
Watermark: () => Watermark
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(index_exports);
|
|
37
|
+
|
|
38
|
+
// src/components/app-shell.tsx
|
|
39
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
40
|
+
function AppShell({
|
|
41
|
+
children,
|
|
42
|
+
className = "",
|
|
43
|
+
maxWidth = 430,
|
|
44
|
+
style
|
|
45
|
+
}) {
|
|
46
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
47
|
+
"div",
|
|
48
|
+
{
|
|
49
|
+
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 ${className}`,
|
|
50
|
+
style: { maxWidth, ...style },
|
|
51
|
+
children
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
function AppShellHeader({ children, className = "" }) {
|
|
56
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
57
|
+
"header",
|
|
58
|
+
{
|
|
59
|
+
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 ${className}`,
|
|
60
|
+
children
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
function AppShellContent({ children, className = "" }) {
|
|
65
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: `flex-1 overflow-y-auto ${className}`, children });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/components/tab-bar.tsx
|
|
69
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
70
|
+
function TabBar({ children, className = "" }) {
|
|
71
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
72
|
+
"nav",
|
|
73
|
+
{
|
|
74
|
+
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 ${className}`,
|
|
75
|
+
children
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
function Tab({ active, onClick, icon, label, activeColor }) {
|
|
80
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
81
|
+
"button",
|
|
82
|
+
{
|
|
83
|
+
onClick,
|
|
84
|
+
className: `flex-1 flex flex-col items-center gap-0.5 py-2.5 transition-colors ${!active ? "text-zinc-300 dark:text-zinc-600" : ""}`,
|
|
85
|
+
style: active ? { color: activeColor } : void 0,
|
|
86
|
+
children: [
|
|
87
|
+
icon,
|
|
88
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-[10px] font-medium", children: label })
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// src/components/section.tsx
|
|
95
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
96
|
+
function Section({ children, className = "" }) {
|
|
97
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("section", { className: `px-4 ${className}`, children });
|
|
98
|
+
}
|
|
99
|
+
function SectionHeader({ children }) {
|
|
100
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { className: "text-[11px] font-semibold text-zinc-400 dark:text-zinc-500 uppercase tracking-wider mb-3", children });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// src/components/divider.tsx
|
|
104
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
105
|
+
function Divider({ className = "" }) {
|
|
106
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: `mx-4 my-6 h-px bg-zinc-200 dark:bg-zinc-800 ${className}` });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// src/components/stat-chip.tsx
|
|
110
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
111
|
+
function StatChip({ label, value, className = "" }) {
|
|
112
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `flex-1 rounded-xl bg-zinc-100 dark:bg-zinc-900 px-3 py-3 text-center ${className}`, children: [
|
|
113
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-[10px] text-zinc-500 dark:text-zinc-400 font-medium mb-0.5", children: label }),
|
|
114
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-lg font-bold tabular-nums text-zinc-900 dark:text-white", children: value.toLocaleString() })
|
|
115
|
+
] });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/components/empty-state.tsx
|
|
119
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
120
|
+
function EmptyState({ message, icon }) {
|
|
121
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-col items-center justify-center py-12 gap-2", children: [
|
|
122
|
+
icon || /* @__PURE__ */ (0, import_jsx_runtime6.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: [
|
|
123
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
|
|
124
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M8 15h8" }),
|
|
125
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "9", cy: "9", r: "1", fill: "currentColor", stroke: "none" }),
|
|
126
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "15", cy: "9", r: "1", fill: "currentColor", stroke: "none" })
|
|
127
|
+
] }),
|
|
128
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-sm text-zinc-400 dark:text-zinc-500", children: message })
|
|
129
|
+
] });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// src/components/watermark.tsx
|
|
133
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
134
|
+
function buildSvgPattern(text, opacity = 0.08) {
|
|
135
|
+
const w = 220;
|
|
136
|
+
const h = 120;
|
|
137
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}">
|
|
138
|
+
<text x="10" y="45" font-family="system-ui,sans-serif" font-size="44" font-weight="900" fill="white" opacity="${opacity}">${text}</text>
|
|
139
|
+
<text x="120" y="100" font-family="system-ui,sans-serif" font-size="44" font-weight="900" fill="white" opacity="${opacity}">${text}</text>
|
|
140
|
+
</svg>`;
|
|
141
|
+
return `url("data:image/svg+xml,${encodeURIComponent(svg)}")`;
|
|
142
|
+
}
|
|
143
|
+
function Watermark({
|
|
144
|
+
children,
|
|
145
|
+
color = "#0f172a",
|
|
146
|
+
text = "m1k",
|
|
147
|
+
maxWidth = 430,
|
|
148
|
+
padding = 12
|
|
149
|
+
}) {
|
|
150
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
151
|
+
"div",
|
|
152
|
+
{
|
|
153
|
+
className: "h-dvh w-full relative overflow-hidden",
|
|
154
|
+
style: { backgroundColor: color, transition: "background-color 0.5s ease" },
|
|
155
|
+
children: [
|
|
156
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
157
|
+
"div",
|
|
158
|
+
{
|
|
159
|
+
className: "absolute inset-0 pointer-events-none select-none",
|
|
160
|
+
style: {
|
|
161
|
+
backgroundImage: buildSvgPattern(text),
|
|
162
|
+
backgroundRepeat: "repeat",
|
|
163
|
+
transform: "rotate(-12deg) scale(1.5)",
|
|
164
|
+
transformOrigin: "center center"
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
),
|
|
168
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
169
|
+
"div",
|
|
170
|
+
{
|
|
171
|
+
className: "relative z-10 h-full flex items-center justify-center mx-auto",
|
|
172
|
+
style: { maxWidth, padding },
|
|
173
|
+
children
|
|
174
|
+
}
|
|
175
|
+
)
|
|
176
|
+
]
|
|
177
|
+
}
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
181
|
+
0 && (module.exports = {
|
|
182
|
+
AppShell,
|
|
183
|
+
AppShellContent,
|
|
184
|
+
AppShellHeader,
|
|
185
|
+
Divider,
|
|
186
|
+
EmptyState,
|
|
187
|
+
Section,
|
|
188
|
+
SectionHeader,
|
|
189
|
+
StatChip,
|
|
190
|
+
Tab,
|
|
191
|
+
TabBar,
|
|
192
|
+
Watermark
|
|
193
|
+
});
|
|
194
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/components/app-shell.tsx","../src/components/tab-bar.tsx","../src/components/section.tsx","../src/components/divider.tsx","../src/components/stat-chip.tsx","../src/components/empty-state.tsx","../src/components/watermark.tsx"],"sourcesContent":["export { AppShell, AppShellHeader, AppShellContent } from \"./components/app-shell\";\nexport type { AppShellProps, AppShellHeaderProps, AppShellContentProps } from \"./components/app-shell\";\n\nexport { TabBar, Tab } from \"./components/tab-bar\";\nexport type { TabBarProps, TabProps } from \"./components/tab-bar\";\n\nexport { Section, SectionHeader } from \"./components/section\";\nexport type { SectionProps, SectionHeaderProps } from \"./components/section\";\n\nexport { Divider } from \"./components/divider\";\n\nexport { StatChip } from \"./components/stat-chip\";\nexport type { StatChipProps } from \"./components/stat-chip\";\n\nexport { EmptyState } from \"./components/empty-state\";\nexport type { EmptyStateProps } from \"./components/empty-state\";\n\nexport { Watermark } from \"./components/watermark\";\nexport type { WatermarkProps } from \"./components/watermark\";\n","import { type ReactNode, type CSSProperties } from \"react\";\n\nexport interface AppShellProps {\n children: ReactNode;\n className?: string;\n /** Max width of the shell. Default: 430px */\n maxWidth?: number;\n style?: CSSProperties;\n}\n\n/**\n * Mobile app-like container with rounded corners, shadow, and ring.\n * Centers content and constrains width for a phone-like viewport.\n */\nexport function AppShell({\n children,\n className = \"\",\n maxWidth = 430,\n style,\n}: AppShellProps) {\n return (\n <div\n 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 ${className}`}\n style={{ maxWidth, ...style }}\n >\n {children}\n </div>\n );\n}\n\nexport interface AppShellHeaderProps {\n children: ReactNode;\n className?: string;\n}\n\n/**\n * Sticky top header with blur backdrop.\n */\nexport function AppShellHeader({ children, className = \"\" }: AppShellHeaderProps) {\n return (\n <header\n 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 ${className}`}\n >\n {children}\n </header>\n );\n}\n\nexport interface AppShellContentProps {\n children: ReactNode;\n className?: string;\n}\n\n/**\n * Scrollable main content area.\n */\nexport function AppShellContent({ children, className = \"\" }: AppShellContentProps) {\n return (\n <div className={`flex-1 overflow-y-auto ${className}`}>\n {children}\n </div>\n );\n}\n","import { type ReactNode } from \"react\";\n\nexport interface TabBarProps {\n children: ReactNode;\n className?: string;\n}\n\n/**\n * Sticky bottom navigation tab bar.\n */\nexport function TabBar({ children, className = \"\" }: TabBarProps) {\n return (\n <nav\n 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 ${className}`}\n >\n {children}\n </nav>\n );\n}\n\nexport interface TabProps {\n active: boolean;\n onClick: () => void;\n icon: ReactNode;\n label: string;\n /** Active tab color. Default: current text color */\n activeColor?: string;\n}\n\n/**\n * Individual tab button for the TabBar.\n */\nexport function Tab({ active, onClick, icon, label, activeColor }: TabProps) {\n return (\n <button\n onClick={onClick}\n className={`flex-1 flex flex-col items-center gap-0.5 py-2.5 transition-colors ${\n !active ? \"text-zinc-300 dark:text-zinc-600\" : \"\"\n }`}\n style={active ? { color: activeColor } : undefined}\n >\n {icon}\n <span className=\"text-[10px] font-medium\">{label}</span>\n </button>\n );\n}\n","import { type ReactNode } from \"react\";\n\nexport interface SectionProps {\n children: ReactNode;\n className?: string;\n}\n\n/**\n * Padded section wrapper (px-4).\n */\nexport function Section({ children, className = \"\" }: SectionProps) {\n return <section className={`px-4 ${className}`}>{children}</section>;\n}\n\nexport interface SectionHeaderProps {\n children: ReactNode;\n}\n\n/**\n * Small uppercase section title.\n */\nexport function SectionHeader({ children }: SectionHeaderProps) {\n return (\n <h2 className=\"text-[11px] font-semibold text-zinc-400 dark:text-zinc-500 uppercase tracking-wider mb-3\">\n {children}\n </h2>\n );\n}\n","/**\n * Horizontal divider line with margin.\n */\nexport function Divider({ className = \"\" }: { className?: string }) {\n return <div className={`mx-4 my-6 h-px bg-zinc-200 dark:bg-zinc-800 ${className}`} />;\n}\n","export interface StatChipProps {\n label: string;\n value: number;\n className?: string;\n}\n\n/**\n * Compact stat display chip with label and number.\n */\nexport function StatChip({ label, value, className = \"\" }: StatChipProps) {\n return (\n <div className={`flex-1 rounded-xl bg-zinc-100 dark:bg-zinc-900 px-3 py-3 text-center ${className}`}>\n <p className=\"text-[10px] text-zinc-500 dark:text-zinc-400 font-medium mb-0.5\">\n {label}\n </p>\n <p className=\"text-lg font-bold tabular-nums text-zinc-900 dark:text-white\">\n {value.toLocaleString()}\n </p>\n </div>\n );\n}\n","import { type ReactNode } from \"react\";\n\nexport interface EmptyStateProps {\n message: string;\n icon?: ReactNode;\n}\n\n/**\n * Empty state placeholder with icon and message.\n */\nexport function EmptyState({ message, icon }: EmptyStateProps) {\n return (\n <div className=\"flex flex-col items-center justify-center py-12 gap-2\">\n {icon || (\n <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\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M8 15h8\" />\n <circle cx=\"9\" cy=\"9\" r=\"1\" fill=\"currentColor\" stroke=\"none\" />\n <circle cx=\"15\" cy=\"9\" r=\"1\" fill=\"currentColor\" stroke=\"none\" />\n </svg>\n )}\n <p className=\"text-sm text-zinc-400 dark:text-zinc-500\">{message}</p>\n </div>\n );\n}\n","import { type ReactNode } from \"react\";\n\nexport interface WatermarkProps {\n children: ReactNode;\n /** Background color */\n color?: string;\n /** Watermark text. Default: \"m1k\" */\n text?: string;\n /** Max width of content area. Default: 430 */\n maxWidth?: number;\n /** Padding around the app shell. Default: 12px */\n padding?: number;\n}\n\nfunction buildSvgPattern(text: string, opacity: number = 0.08): string {\n const w = 220;\n const h = 120;\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${w}\" height=\"${h}\">\n <text x=\"10\" y=\"45\" font-family=\"system-ui,sans-serif\" font-size=\"44\" font-weight=\"900\" fill=\"white\" opacity=\"${opacity}\">${text}</text>\n <text x=\"120\" y=\"100\" font-family=\"system-ui,sans-serif\" font-size=\"44\" font-weight=\"900\" fill=\"white\" opacity=\"${opacity}\">${text}</text>\n </svg>`;\n return `url(\"data:image/svg+xml,${encodeURIComponent(svg)}\")`;\n}\n\n/**\n * Full-screen colored background with repeating text watermark pattern.\n * Wraps the AppShell and provides the \"floating app\" look.\n */\nexport function Watermark({\n children,\n color = \"#0f172a\",\n text = \"m1k\",\n maxWidth = 430,\n padding = 12,\n}: WatermarkProps) {\n return (\n <div\n className=\"h-dvh w-full relative overflow-hidden\"\n style={{ backgroundColor: color, transition: \"background-color 0.5s ease\" }}\n >\n <div\n className=\"absolute inset-0 pointer-events-none select-none\"\n style={{\n backgroundImage: buildSvgPattern(text),\n backgroundRepeat: \"repeat\",\n transform: \"rotate(-12deg) scale(1.5)\",\n transformOrigin: \"center center\",\n }}\n />\n <div\n className=\"relative z-10 h-full flex items-center justify-center mx-auto\"\n style={{ maxWidth, padding }}\n >\n {children}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/components/app-shell.tsx
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
function AppShell({
|
|
6
|
+
children,
|
|
7
|
+
className = "",
|
|
8
|
+
maxWidth = 430,
|
|
9
|
+
style
|
|
10
|
+
}) {
|
|
11
|
+
return /* @__PURE__ */ jsx(
|
|
12
|
+
"div",
|
|
13
|
+
{
|
|
14
|
+
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 ${className}`,
|
|
15
|
+
style: { maxWidth, ...style },
|
|
16
|
+
children
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
function AppShellHeader({ children, className = "" }) {
|
|
21
|
+
return /* @__PURE__ */ jsx(
|
|
22
|
+
"header",
|
|
23
|
+
{
|
|
24
|
+
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 ${className}`,
|
|
25
|
+
children
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
function AppShellContent({ children, className = "" }) {
|
|
30
|
+
return /* @__PURE__ */ jsx("div", { className: `flex-1 overflow-y-auto ${className}`, children });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/components/tab-bar.tsx
|
|
34
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
35
|
+
function TabBar({ children, className = "" }) {
|
|
36
|
+
return /* @__PURE__ */ jsx2(
|
|
37
|
+
"nav",
|
|
38
|
+
{
|
|
39
|
+
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 ${className}`,
|
|
40
|
+
children
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
function Tab({ active, onClick, icon, label, activeColor }) {
|
|
45
|
+
return /* @__PURE__ */ jsxs(
|
|
46
|
+
"button",
|
|
47
|
+
{
|
|
48
|
+
onClick,
|
|
49
|
+
className: `flex-1 flex flex-col items-center gap-0.5 py-2.5 transition-colors ${!active ? "text-zinc-300 dark:text-zinc-600" : ""}`,
|
|
50
|
+
style: active ? { color: activeColor } : void 0,
|
|
51
|
+
children: [
|
|
52
|
+
icon,
|
|
53
|
+
/* @__PURE__ */ jsx2("span", { className: "text-[10px] font-medium", children: label })
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// src/components/section.tsx
|
|
60
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
61
|
+
function Section({ children, className = "" }) {
|
|
62
|
+
return /* @__PURE__ */ jsx3("section", { className: `px-4 ${className}`, children });
|
|
63
|
+
}
|
|
64
|
+
function SectionHeader({ children }) {
|
|
65
|
+
return /* @__PURE__ */ jsx3("h2", { className: "text-[11px] font-semibold text-zinc-400 dark:text-zinc-500 uppercase tracking-wider mb-3", children });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/components/divider.tsx
|
|
69
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
70
|
+
function Divider({ className = "" }) {
|
|
71
|
+
return /* @__PURE__ */ jsx4("div", { className: `mx-4 my-6 h-px bg-zinc-200 dark:bg-zinc-800 ${className}` });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/components/stat-chip.tsx
|
|
75
|
+
import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
76
|
+
function StatChip({ label, value, className = "" }) {
|
|
77
|
+
return /* @__PURE__ */ jsxs2("div", { className: `flex-1 rounded-xl bg-zinc-100 dark:bg-zinc-900 px-3 py-3 text-center ${className}`, children: [
|
|
78
|
+
/* @__PURE__ */ jsx5("p", { className: "text-[10px] text-zinc-500 dark:text-zinc-400 font-medium mb-0.5", children: label }),
|
|
79
|
+
/* @__PURE__ */ jsx5("p", { className: "text-lg font-bold tabular-nums text-zinc-900 dark:text-white", children: value.toLocaleString() })
|
|
80
|
+
] });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/components/empty-state.tsx
|
|
84
|
+
import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
85
|
+
function EmptyState({ message, icon }) {
|
|
86
|
+
return /* @__PURE__ */ jsxs3("div", { className: "flex flex-col items-center justify-center py-12 gap-2", children: [
|
|
87
|
+
icon || /* @__PURE__ */ jsxs3("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: [
|
|
88
|
+
/* @__PURE__ */ jsx6("circle", { cx: "12", cy: "12", r: "10" }),
|
|
89
|
+
/* @__PURE__ */ jsx6("path", { d: "M8 15h8" }),
|
|
90
|
+
/* @__PURE__ */ jsx6("circle", { cx: "9", cy: "9", r: "1", fill: "currentColor", stroke: "none" }),
|
|
91
|
+
/* @__PURE__ */ jsx6("circle", { cx: "15", cy: "9", r: "1", fill: "currentColor", stroke: "none" })
|
|
92
|
+
] }),
|
|
93
|
+
/* @__PURE__ */ jsx6("p", { className: "text-sm text-zinc-400 dark:text-zinc-500", children: message })
|
|
94
|
+
] });
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/components/watermark.tsx
|
|
98
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
99
|
+
function buildSvgPattern(text, opacity = 0.08) {
|
|
100
|
+
const w = 220;
|
|
101
|
+
const h = 120;
|
|
102
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}">
|
|
103
|
+
<text x="10" y="45" font-family="system-ui,sans-serif" font-size="44" font-weight="900" fill="white" opacity="${opacity}">${text}</text>
|
|
104
|
+
<text x="120" y="100" font-family="system-ui,sans-serif" font-size="44" font-weight="900" fill="white" opacity="${opacity}">${text}</text>
|
|
105
|
+
</svg>`;
|
|
106
|
+
return `url("data:image/svg+xml,${encodeURIComponent(svg)}")`;
|
|
107
|
+
}
|
|
108
|
+
function Watermark({
|
|
109
|
+
children,
|
|
110
|
+
color = "#0f172a",
|
|
111
|
+
text = "m1k",
|
|
112
|
+
maxWidth = 430,
|
|
113
|
+
padding = 12
|
|
114
|
+
}) {
|
|
115
|
+
return /* @__PURE__ */ jsxs4(
|
|
116
|
+
"div",
|
|
117
|
+
{
|
|
118
|
+
className: "h-dvh w-full relative overflow-hidden",
|
|
119
|
+
style: { backgroundColor: color, transition: "background-color 0.5s ease" },
|
|
120
|
+
children: [
|
|
121
|
+
/* @__PURE__ */ jsx7(
|
|
122
|
+
"div",
|
|
123
|
+
{
|
|
124
|
+
className: "absolute inset-0 pointer-events-none select-none",
|
|
125
|
+
style: {
|
|
126
|
+
backgroundImage: buildSvgPattern(text),
|
|
127
|
+
backgroundRepeat: "repeat",
|
|
128
|
+
transform: "rotate(-12deg) scale(1.5)",
|
|
129
|
+
transformOrigin: "center center"
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
),
|
|
133
|
+
/* @__PURE__ */ jsx7(
|
|
134
|
+
"div",
|
|
135
|
+
{
|
|
136
|
+
className: "relative z-10 h-full flex items-center justify-center mx-auto",
|
|
137
|
+
style: { maxWidth, padding },
|
|
138
|
+
children
|
|
139
|
+
}
|
|
140
|
+
)
|
|
141
|
+
]
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
export {
|
|
146
|
+
AppShell,
|
|
147
|
+
AppShellContent,
|
|
148
|
+
AppShellHeader,
|
|
149
|
+
Divider,
|
|
150
|
+
EmptyState,
|
|
151
|
+
Section,
|
|
152
|
+
SectionHeader,
|
|
153
|
+
StatChip,
|
|
154
|
+
Tab,
|
|
155
|
+
TabBar,
|
|
156
|
+
Watermark
|
|
157
|
+
};
|
|
158
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/app-shell.tsx","../src/components/tab-bar.tsx","../src/components/section.tsx","../src/components/divider.tsx","../src/components/stat-chip.tsx","../src/components/empty-state.tsx","../src/components/watermark.tsx"],"sourcesContent":["import { type ReactNode, type CSSProperties } from \"react\";\n\nexport interface AppShellProps {\n children: ReactNode;\n className?: string;\n /** Max width of the shell. Default: 430px */\n maxWidth?: number;\n style?: CSSProperties;\n}\n\n/**\n * Mobile app-like container with rounded corners, shadow, and ring.\n * Centers content and constrains width for a phone-like viewport.\n */\nexport function AppShell({\n children,\n className = \"\",\n maxWidth = 430,\n style,\n}: AppShellProps) {\n return (\n <div\n 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 ${className}`}\n style={{ maxWidth, ...style }}\n >\n {children}\n </div>\n );\n}\n\nexport interface AppShellHeaderProps {\n children: ReactNode;\n className?: string;\n}\n\n/**\n * Sticky top header with blur backdrop.\n */\nexport function AppShellHeader({ children, className = \"\" }: AppShellHeaderProps) {\n return (\n <header\n 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 ${className}`}\n >\n {children}\n </header>\n );\n}\n\nexport interface AppShellContentProps {\n children: ReactNode;\n className?: string;\n}\n\n/**\n * Scrollable main content area.\n */\nexport function AppShellContent({ children, className = \"\" }: AppShellContentProps) {\n return (\n <div className={`flex-1 overflow-y-auto ${className}`}>\n {children}\n </div>\n );\n}\n","import { type ReactNode } from \"react\";\n\nexport interface TabBarProps {\n children: ReactNode;\n className?: string;\n}\n\n/**\n * Sticky bottom navigation tab bar.\n */\nexport function TabBar({ children, className = \"\" }: TabBarProps) {\n return (\n <nav\n 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 ${className}`}\n >\n {children}\n </nav>\n );\n}\n\nexport interface TabProps {\n active: boolean;\n onClick: () => void;\n icon: ReactNode;\n label: string;\n /** Active tab color. Default: current text color */\n activeColor?: string;\n}\n\n/**\n * Individual tab button for the TabBar.\n */\nexport function Tab({ active, onClick, icon, label, activeColor }: TabProps) {\n return (\n <button\n onClick={onClick}\n className={`flex-1 flex flex-col items-center gap-0.5 py-2.5 transition-colors ${\n !active ? \"text-zinc-300 dark:text-zinc-600\" : \"\"\n }`}\n style={active ? { color: activeColor } : undefined}\n >\n {icon}\n <span className=\"text-[10px] font-medium\">{label}</span>\n </button>\n );\n}\n","import { type ReactNode } from \"react\";\n\nexport interface SectionProps {\n children: ReactNode;\n className?: string;\n}\n\n/**\n * Padded section wrapper (px-4).\n */\nexport function Section({ children, className = \"\" }: SectionProps) {\n return <section className={`px-4 ${className}`}>{children}</section>;\n}\n\nexport interface SectionHeaderProps {\n children: ReactNode;\n}\n\n/**\n * Small uppercase section title.\n */\nexport function SectionHeader({ children }: SectionHeaderProps) {\n return (\n <h2 className=\"text-[11px] font-semibold text-zinc-400 dark:text-zinc-500 uppercase tracking-wider mb-3\">\n {children}\n </h2>\n );\n}\n","/**\n * Horizontal divider line with margin.\n */\nexport function Divider({ className = \"\" }: { className?: string }) {\n return <div className={`mx-4 my-6 h-px bg-zinc-200 dark:bg-zinc-800 ${className}`} />;\n}\n","export interface StatChipProps {\n label: string;\n value: number;\n className?: string;\n}\n\n/**\n * Compact stat display chip with label and number.\n */\nexport function StatChip({ label, value, className = \"\" }: StatChipProps) {\n return (\n <div className={`flex-1 rounded-xl bg-zinc-100 dark:bg-zinc-900 px-3 py-3 text-center ${className}`}>\n <p className=\"text-[10px] text-zinc-500 dark:text-zinc-400 font-medium mb-0.5\">\n {label}\n </p>\n <p className=\"text-lg font-bold tabular-nums text-zinc-900 dark:text-white\">\n {value.toLocaleString()}\n </p>\n </div>\n );\n}\n","import { type ReactNode } from \"react\";\n\nexport interface EmptyStateProps {\n message: string;\n icon?: ReactNode;\n}\n\n/**\n * Empty state placeholder with icon and message.\n */\nexport function EmptyState({ message, icon }: EmptyStateProps) {\n return (\n <div className=\"flex flex-col items-center justify-center py-12 gap-2\">\n {icon || (\n <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\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M8 15h8\" />\n <circle cx=\"9\" cy=\"9\" r=\"1\" fill=\"currentColor\" stroke=\"none\" />\n <circle cx=\"15\" cy=\"9\" r=\"1\" fill=\"currentColor\" stroke=\"none\" />\n </svg>\n )}\n <p className=\"text-sm text-zinc-400 dark:text-zinc-500\">{message}</p>\n </div>\n );\n}\n","import { type ReactNode } from \"react\";\n\nexport interface WatermarkProps {\n children: ReactNode;\n /** Background color */\n color?: string;\n /** Watermark text. Default: \"m1k\" */\n text?: string;\n /** Max width of content area. Default: 430 */\n maxWidth?: number;\n /** Padding around the app shell. Default: 12px */\n padding?: number;\n}\n\nfunction buildSvgPattern(text: string, opacity: number = 0.08): string {\n const w = 220;\n const h = 120;\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${w}\" height=\"${h}\">\n <text x=\"10\" y=\"45\" font-family=\"system-ui,sans-serif\" font-size=\"44\" font-weight=\"900\" fill=\"white\" opacity=\"${opacity}\">${text}</text>\n <text x=\"120\" y=\"100\" font-family=\"system-ui,sans-serif\" font-size=\"44\" font-weight=\"900\" fill=\"white\" opacity=\"${opacity}\">${text}</text>\n </svg>`;\n return `url(\"data:image/svg+xml,${encodeURIComponent(svg)}\")`;\n}\n\n/**\n * Full-screen colored background with repeating text watermark pattern.\n * Wraps the AppShell and provides the \"floating app\" look.\n */\nexport function Watermark({\n children,\n color = \"#0f172a\",\n text = \"m1k\",\n maxWidth = 430,\n padding = 12,\n}: WatermarkProps) {\n return (\n <div\n className=\"h-dvh w-full relative overflow-hidden\"\n style={{ backgroundColor: color, transition: \"background-color 0.5s ease\" }}\n >\n <div\n className=\"absolute inset-0 pointer-events-none select-none\"\n style={{\n backgroundImage: buildSvgPattern(text),\n backgroundRepeat: \"repeat\",\n transform: \"rotate(-12deg) scale(1.5)\",\n transformOrigin: \"center center\",\n }}\n />\n <div\n className=\"relative z-10 h-full flex items-center justify-center mx-auto\"\n style={{ maxWidth, padding }}\n >\n {children}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","jsx","jsx","jsx","jsxs","jsx","jsxs","jsx","jsxs"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@m1kapp/ui",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Mobile-first app shell UI components for side projects",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsup",
|
|
20
|
+
"dev": "tsup --watch",
|
|
21
|
+
"lint": "tsc --noEmit",
|
|
22
|
+
"demo": "cd demo && npm run dev",
|
|
23
|
+
"demo:build": "cd demo && npm run build"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"react": ">=18",
|
|
27
|
+
"react-dom": ">=18"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"react": "^19.0.0",
|
|
31
|
+
"react-dom": "^19.0.0",
|
|
32
|
+
"typescript": "^5.0.0",
|
|
33
|
+
"tsup": "^8.0.0",
|
|
34
|
+
"@types/react": "^19.0.0",
|
|
35
|
+
"@types/react-dom": "^19.0.0",
|
|
36
|
+
"tailwindcss": "^4.0.0"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"react",
|
|
40
|
+
"ui",
|
|
41
|
+
"mobile",
|
|
42
|
+
"app-shell",
|
|
43
|
+
"tailwind",
|
|
44
|
+
"side-project",
|
|
45
|
+
"m1k"
|
|
46
|
+
],
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "https://github.com/yoominho/m1k-ui"
|
|
51
|
+
},
|
|
52
|
+
"homepage": "https://m1k.app"
|
|
53
|
+
}
|