@adarsh.nishad/activityual-ui 0.0.0-stage → 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/README.md +105 -2
- package/dist/activity-card.d.ts +43 -0
- package/dist/activity-card.js +302 -0
- package/dist/button.d.ts +32 -0
- package/dist/button.js +184 -0
- package/dist/card.d.ts +16 -0
- package/dist/card.js +99 -0
- package/dist/chart-panel.d.ts +26 -0
- package/dist/chart-panel.js +247 -0
- package/dist/confirm-dialog.d.ts +35 -0
- package/dist/confirm-dialog.js +140 -0
- package/dist/empty-state.d.ts +25 -0
- package/dist/empty-state.js +95 -0
- package/dist/form-field.d.ts +40 -0
- package/dist/form-field.js +144 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +13 -0
- package/dist/progress-ring.d.ts +23 -0
- package/dist/progress-ring.js +124 -0
- package/dist/recommendation-banner.d.ts +31 -0
- package/dist/recommendation-banner.js +192 -0
- package/dist/stat-card.d.ts +27 -0
- package/dist/stat-card.js +137 -0
- package/dist/status-pill.d.ts +16 -0
- package/dist/status-pill.js +96 -0
- package/dist/streak-badge.d.ts +19 -0
- package/dist/streak-badge.js +89 -0
- package/dist/tokens.d.ts +174 -0
- package/dist/tokens.js +125 -0
- package/package.json +35 -4
package/README.md
CHANGED
|
@@ -1,3 +1,106 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Activityual UI Component Library (`@adarsh.nishad/activityual-ui`)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A reusable, accessible web component library built with **Lit** for the **Activityual** cloud-native personal habit tracker.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Components
|
|
8
|
+
|
|
9
|
+
| Component | Custom Element Tag | Description |
|
|
10
|
+
| :--- | :--- | :--- |
|
|
11
|
+
| **Button** | `<activityual-button>` | Interactive button (`primary`, `secondary`, `amber`, `charcoal`, `ghost`, `danger`) with loading states |
|
|
12
|
+
| **Card** | `<activityual-card>` | Obsidian glass container card with subtle borders and glow |
|
|
13
|
+
| **Activity Card** | `<activityual-activity-card>` | Core habit/activity card with streak badges, actions, and progress |
|
|
14
|
+
| **Stat Card** | `<activityual-stat-card>` | Metrics and KPI display card with sparkline and delta indicators |
|
|
15
|
+
| **Progress Ring** | `<activityual-progress-ring>` | Circular SVG progress ring with animated stroke and target values |
|
|
16
|
+
| **Streak Badge** | `<activityual-streak-badge>` | Visual flame streak badge displaying active day streaks |
|
|
17
|
+
| **Status Pill** | `<activityual-status-pill>` | Activity status indicators (`active`, `paused`, `archived`, `completed`) |
|
|
18
|
+
| **Chart Panel** | `<activityual-chart-panel>` | Analytics and visualization container panel with filters |
|
|
19
|
+
| **Recommendation Banner**| `<activityual-recommendation-banner>` | AI-driven habit suggestion and nudge banner |
|
|
20
|
+
| **Empty State** | `<activityual-empty-state>` | Placeholder presentation for empty lists and initial states |
|
|
21
|
+
| **Confirm Dialog** | `<activityual-confirm-dialog>` | Modal confirmation dialog with backdrop blur |
|
|
22
|
+
| **Form Field** | `<activityual-form-field>` | Styled input / select / textarea wrapper with validation |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Installation & Consumption
|
|
27
|
+
|
|
28
|
+
### In SvelteKit / Web Applications
|
|
29
|
+
|
|
30
|
+
Install the package:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install @adarsh.nishad/activityual-ui
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Register all custom elements in your root layout (`src/routes/+layout.svelte`):
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import '@adarsh.nishad/activityual-ui';
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Or import design tokens directly:
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { tokens } from '@adarsh.nishad/activityual-ui';
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Building & Publishing to npm
|
|
51
|
+
|
|
52
|
+
Follow these steps whenever you make changes to `packages/activityual-ui` and want to publish a new release:
|
|
53
|
+
|
|
54
|
+
### Step 1: Verify npm Authentication
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm whoami
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
If not logged in, run:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npm login
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Step 2: Build the Library
|
|
67
|
+
|
|
68
|
+
Compile all custom elements and TypeScript type definitions into `dist/`:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# From repository root:
|
|
72
|
+
npm run build:ui
|
|
73
|
+
|
|
74
|
+
# Or directly in this directory:
|
|
75
|
+
npm run build
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Step 3: Bump Version
|
|
79
|
+
|
|
80
|
+
Bump the semantic version (`patch`, `minor`, or `major`):
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# From repository root:
|
|
84
|
+
npm run version:ui:patch # e.g. 0.1.0 -> 0.1.1
|
|
85
|
+
# or
|
|
86
|
+
npm run version:ui:minor # e.g. 0.1.0 -> 0.2.0
|
|
87
|
+
# or
|
|
88
|
+
npm run version:ui:major # e.g. 0.1.0 -> 1.0.0
|
|
89
|
+
|
|
90
|
+
# Or navigate directly:
|
|
91
|
+
cd packages/activityual-ui
|
|
92
|
+
npm version patch # or minor / major
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Step 4: Publish to npm
|
|
96
|
+
|
|
97
|
+
Since it is a scoped package (`@adarsh.nishad/...`), publish with public access:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# From repository root:
|
|
101
|
+
npm run publish:ui
|
|
102
|
+
|
|
103
|
+
# Or navigate directly:
|
|
104
|
+
cd packages/activityual-ui
|
|
105
|
+
npm publish --access public
|
|
106
|
+
```
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
import './status-pill.js';
|
|
3
|
+
import './button.js';
|
|
4
|
+
export declare class ActivityualActivityCard extends LitElement {
|
|
5
|
+
static properties: {
|
|
6
|
+
activityId: {
|
|
7
|
+
type: StringConstructor;
|
|
8
|
+
};
|
|
9
|
+
title: {
|
|
10
|
+
type: StringConstructor;
|
|
11
|
+
};
|
|
12
|
+
category: {
|
|
13
|
+
type: StringConstructor;
|
|
14
|
+
};
|
|
15
|
+
frequency: {
|
|
16
|
+
type: StringConstructor;
|
|
17
|
+
};
|
|
18
|
+
status: {
|
|
19
|
+
type: StringConstructor;
|
|
20
|
+
};
|
|
21
|
+
streak: {
|
|
22
|
+
type: NumberConstructor;
|
|
23
|
+
};
|
|
24
|
+
notes: {
|
|
25
|
+
type: StringConstructor;
|
|
26
|
+
};
|
|
27
|
+
readOnly: {
|
|
28
|
+
type: BooleanConstructor;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
activityId: string;
|
|
32
|
+
title: string;
|
|
33
|
+
category: string;
|
|
34
|
+
frequency: string;
|
|
35
|
+
status: 'done' | 'missed' | 'pending';
|
|
36
|
+
streak: number;
|
|
37
|
+
notes: string;
|
|
38
|
+
readOnly: boolean;
|
|
39
|
+
static styles: import("lit").CSSResult;
|
|
40
|
+
getCategoryIcon(cat: string): string;
|
|
41
|
+
handleAction(status: 'done' | 'missed'): void;
|
|
42
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
43
|
+
}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { LitElement, html, css } from 'lit';
|
|
2
|
+
import './status-pill.js';
|
|
3
|
+
import './button.js';
|
|
4
|
+
export class ActivityualActivityCard extends LitElement {
|
|
5
|
+
constructor() {
|
|
6
|
+
super(...arguments);
|
|
7
|
+
this.activityId = '';
|
|
8
|
+
this.title = '';
|
|
9
|
+
this.category = 'General';
|
|
10
|
+
this.frequency = 'Daily';
|
|
11
|
+
this.status = 'pending';
|
|
12
|
+
this.streak = 0;
|
|
13
|
+
this.notes = '';
|
|
14
|
+
this.readOnly = false;
|
|
15
|
+
}
|
|
16
|
+
static { this.properties = {
|
|
17
|
+
activityId: { type: String },
|
|
18
|
+
title: { type: String },
|
|
19
|
+
category: { type: String },
|
|
20
|
+
frequency: { type: String },
|
|
21
|
+
status: { type: String },
|
|
22
|
+
streak: { type: Number },
|
|
23
|
+
notes: { type: String },
|
|
24
|
+
readOnly: { type: Boolean }
|
|
25
|
+
}; }
|
|
26
|
+
static { this.styles = css `
|
|
27
|
+
:host {
|
|
28
|
+
display: block;
|
|
29
|
+
box-sizing: border-box;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.card {
|
|
33
|
+
background: linear-gradient(145deg, rgba(42, 42, 42, 0.65) 0%, rgba(24, 24, 24, 0.8) 100%);
|
|
34
|
+
backdrop-filter: blur(20px);
|
|
35
|
+
-webkit-backdrop-filter: blur(20px);
|
|
36
|
+
border: 1px solid rgba(255, 255, 255, 0.05);
|
|
37
|
+
border-radius: 14px;
|
|
38
|
+
padding: 1rem 1.25rem;
|
|
39
|
+
box-shadow:
|
|
40
|
+
0 8px 24px -4px rgba(0, 0, 0, 0.45),
|
|
41
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.08);
|
|
42
|
+
font-family: Inter, 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
43
|
+
display: flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
justify-content: space-between;
|
|
46
|
+
gap: 1rem;
|
|
47
|
+
transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1);
|
|
48
|
+
box-sizing: border-box;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.card:hover {
|
|
52
|
+
background: linear-gradient(145deg, rgba(48, 48, 48, 0.75) 0%, rgba(28, 28, 28, 0.88) 100%);
|
|
53
|
+
transform: translateY(-1px);
|
|
54
|
+
border-color: rgba(255, 255, 255, 0.1);
|
|
55
|
+
box-shadow:
|
|
56
|
+
0 14px 32px -6px rgba(0, 0, 0, 0.55),
|
|
57
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.12);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.left-cluster {
|
|
61
|
+
display: flex;
|
|
62
|
+
align-items: center;
|
|
63
|
+
gap: 0.85rem;
|
|
64
|
+
min-width: 0;
|
|
65
|
+
flex: 1;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.category-icon {
|
|
69
|
+
width: 38px;
|
|
70
|
+
height: 38px;
|
|
71
|
+
border-radius: 10px;
|
|
72
|
+
background: rgba(255, 67, 5, 0.1);
|
|
73
|
+
border: 1px solid rgba(255, 67, 5, 0.2);
|
|
74
|
+
color: #ff4305;
|
|
75
|
+
display: flex;
|
|
76
|
+
align-items: center;
|
|
77
|
+
justify-content: center;
|
|
78
|
+
font-size: 16px;
|
|
79
|
+
flex-shrink: 0;
|
|
80
|
+
box-shadow: 0 0 10px rgba(255, 67, 5, 0.15);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.info {
|
|
84
|
+
display: flex;
|
|
85
|
+
flex-direction: column;
|
|
86
|
+
gap: 0.2rem;
|
|
87
|
+
min-width: 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.title-row {
|
|
91
|
+
display: flex;
|
|
92
|
+
align-items: center;
|
|
93
|
+
gap: 0.5rem;
|
|
94
|
+
flex-wrap: wrap;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.title {
|
|
98
|
+
font-size: 13.5px;
|
|
99
|
+
font-weight: 600;
|
|
100
|
+
color: #f5f5f5;
|
|
101
|
+
margin: 0;
|
|
102
|
+
white-space: nowrap;
|
|
103
|
+
overflow: hidden;
|
|
104
|
+
text-overflow: ellipsis;
|
|
105
|
+
letter-spacing: -0.01em;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.meta {
|
|
109
|
+
display: flex;
|
|
110
|
+
align-items: center;
|
|
111
|
+
gap: 0.55rem;
|
|
112
|
+
font-size: 11px;
|
|
113
|
+
color: #a5a5a5;
|
|
114
|
+
font-family: 'JetBrains Mono', monospace;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.meta-tag {
|
|
118
|
+
display: inline-flex;
|
|
119
|
+
align-items: center;
|
|
120
|
+
gap: 0.25rem;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.streak-tag {
|
|
124
|
+
color: #ff4305;
|
|
125
|
+
font-weight: 600;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.notes {
|
|
129
|
+
font-size: 11.5px;
|
|
130
|
+
color: #707070;
|
|
131
|
+
margin: 0.2rem 0 0 0;
|
|
132
|
+
display: -webkit-box;
|
|
133
|
+
-webkit-line-clamp: 1;
|
|
134
|
+
-webkit-box-orient: vertical;
|
|
135
|
+
overflow: hidden;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.dot-trail {
|
|
139
|
+
display: flex;
|
|
140
|
+
align-items: center;
|
|
141
|
+
gap: 4px;
|
|
142
|
+
margin-top: 4px;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.dot {
|
|
146
|
+
width: 6px;
|
|
147
|
+
height: 6px;
|
|
148
|
+
border-radius: 50%;
|
|
149
|
+
background: rgba(255, 255, 255, 0.12);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.dot.done {
|
|
153
|
+
background: #25d366;
|
|
154
|
+
box-shadow: 0 0 6px rgba(37, 211, 102, 0.4);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.dot.missed {
|
|
158
|
+
background: #ff3434;
|
|
159
|
+
box-shadow: 0 0 6px rgba(255, 52, 52, 0.4);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.right-cluster {
|
|
163
|
+
display: flex;
|
|
164
|
+
align-items: center;
|
|
165
|
+
gap: 0.65rem;
|
|
166
|
+
flex-shrink: 0;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.action-btn {
|
|
170
|
+
width: 32px;
|
|
171
|
+
height: 32px;
|
|
172
|
+
border-radius: 9999px;
|
|
173
|
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
174
|
+
background: rgba(255, 255, 255, 0.04);
|
|
175
|
+
display: flex;
|
|
176
|
+
align-items: center;
|
|
177
|
+
justify-content: center;
|
|
178
|
+
cursor: pointer;
|
|
179
|
+
font-size: 13px;
|
|
180
|
+
font-weight: 700;
|
|
181
|
+
color: #a5a5a5;
|
|
182
|
+
transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
|
|
183
|
+
outline: none;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.action-btn:focus-visible {
|
|
187
|
+
box-shadow: 0 0 0 2px rgba(255, 67, 5, 0.4);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.action-done:hover {
|
|
191
|
+
background: rgba(37, 211, 102, 0.2);
|
|
192
|
+
border-color: #25d366;
|
|
193
|
+
color: #25d366;
|
|
194
|
+
box-shadow: 0 0 10px rgba(37, 211, 102, 0.3);
|
|
195
|
+
transform: scale(1.05);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.action-done.active {
|
|
199
|
+
background: #25d366;
|
|
200
|
+
border-color: #25d366;
|
|
201
|
+
color: #ffffff;
|
|
202
|
+
box-shadow: 0 0 12px rgba(37, 211, 102, 0.4);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.action-missed:hover {
|
|
206
|
+
background: rgba(255, 52, 52, 0.2);
|
|
207
|
+
border-color: #ff3434;
|
|
208
|
+
color: #ff3434;
|
|
209
|
+
box-shadow: 0 0 10px rgba(255, 52, 52, 0.3);
|
|
210
|
+
transform: scale(1.05);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.action-missed.active {
|
|
214
|
+
background: #ff3434;
|
|
215
|
+
border-color: #ff3434;
|
|
216
|
+
color: #ffffff;
|
|
217
|
+
box-shadow: 0 0 12px rgba(255, 52, 52, 0.4);
|
|
218
|
+
}
|
|
219
|
+
`; }
|
|
220
|
+
getCategoryIcon(cat) {
|
|
221
|
+
const lower = cat.toLowerCase();
|
|
222
|
+
if (lower.includes('health') || lower.includes('hydration') || lower.includes('water'))
|
|
223
|
+
return '💧';
|
|
224
|
+
if (lower.includes('fit') || lower.includes('workout') || lower.includes('sport'))
|
|
225
|
+
return '⚡';
|
|
226
|
+
if (lower.includes('mind') || lower.includes('read') || lower.includes('meditat'))
|
|
227
|
+
return '📖';
|
|
228
|
+
if (lower.includes('code') || lower.includes('deep') || lower.includes('work'))
|
|
229
|
+
return '🎯';
|
|
230
|
+
return '✨';
|
|
231
|
+
}
|
|
232
|
+
handleAction(status) {
|
|
233
|
+
this.dispatchEvent(new CustomEvent('status-change', {
|
|
234
|
+
detail: { activityId: this.activityId, status },
|
|
235
|
+
bubbles: true,
|
|
236
|
+
composed: true
|
|
237
|
+
}));
|
|
238
|
+
}
|
|
239
|
+
render() {
|
|
240
|
+
return html `
|
|
241
|
+
<div class="card">
|
|
242
|
+
<div class="left-cluster">
|
|
243
|
+
<div class="category-icon" aria-hidden="true">
|
|
244
|
+
${this.getCategoryIcon(this.category)}
|
|
245
|
+
</div>
|
|
246
|
+
<div class="info">
|
|
247
|
+
<div class="title-row">
|
|
248
|
+
<h3 class="title">${this.title}</h3>
|
|
249
|
+
</div>
|
|
250
|
+
<div class="meta">
|
|
251
|
+
<span class="meta-tag">${this.category}</span>
|
|
252
|
+
<span>•</span>
|
|
253
|
+
<span class="meta-tag">${this.frequency}</span>
|
|
254
|
+
${this.streak > 0
|
|
255
|
+
? html `
|
|
256
|
+
<span>•</span>
|
|
257
|
+
<span class="meta-tag streak-tag">🔥 ${this.streak}d streak</span>
|
|
258
|
+
`
|
|
259
|
+
: ''}
|
|
260
|
+
</div>
|
|
261
|
+
${this.notes ? html `<p class="notes">${this.notes}</p>` : ''}
|
|
262
|
+
<div class="dot-trail" aria-label="Recent consistency">
|
|
263
|
+
<span class="dot done"></span>
|
|
264
|
+
<span class="dot done"></span>
|
|
265
|
+
<span class="dot done"></span>
|
|
266
|
+
<span class="dot done"></span>
|
|
267
|
+
<span class="dot ${this.status === 'done' ? 'done' : this.status === 'missed' ? 'missed' : ''}"></span>
|
|
268
|
+
</div>
|
|
269
|
+
</div>
|
|
270
|
+
</div>
|
|
271
|
+
|
|
272
|
+
<div class="right-cluster">
|
|
273
|
+
<activityual-status-pill .status="${this.status}" size="sm"></activityual-status-pill>
|
|
274
|
+
|
|
275
|
+
${!this.readOnly
|
|
276
|
+
? html `
|
|
277
|
+
<button
|
|
278
|
+
class="action-btn action-done ${this.status === 'done' ? 'active' : ''}"
|
|
279
|
+
title="Mark Done"
|
|
280
|
+
aria-label="Mark ${this.title} Done"
|
|
281
|
+
@click="${() => this.handleAction('done')}"
|
|
282
|
+
>
|
|
283
|
+
✓
|
|
284
|
+
</button>
|
|
285
|
+
<button
|
|
286
|
+
class="action-btn action-missed ${this.status === 'missed' ? 'active' : ''}"
|
|
287
|
+
title="Mark Missed"
|
|
288
|
+
aria-label="Mark ${this.title} Missed"
|
|
289
|
+
@click="${() => this.handleAction('missed')}"
|
|
290
|
+
>
|
|
291
|
+
✕
|
|
292
|
+
</button>
|
|
293
|
+
`
|
|
294
|
+
: ''}
|
|
295
|
+
</div>
|
|
296
|
+
</div>
|
|
297
|
+
`;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (!customElements.get('activityual-activity-card')) {
|
|
301
|
+
customElements.define('activityual-activity-card', ActivityualActivityCard);
|
|
302
|
+
}
|
package/dist/button.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
export type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger' | 'charcoal' | 'amber';
|
|
3
|
+
export type ButtonSize = 'sm' | 'md' | 'lg';
|
|
4
|
+
export declare class ActivityualButton extends LitElement {
|
|
5
|
+
static properties: {
|
|
6
|
+
variant: {
|
|
7
|
+
type: StringConstructor;
|
|
8
|
+
};
|
|
9
|
+
size: {
|
|
10
|
+
type: StringConstructor;
|
|
11
|
+
};
|
|
12
|
+
disabled: {
|
|
13
|
+
type: BooleanConstructor;
|
|
14
|
+
reflect: boolean;
|
|
15
|
+
};
|
|
16
|
+
loading: {
|
|
17
|
+
type: BooleanConstructor;
|
|
18
|
+
reflect: boolean;
|
|
19
|
+
};
|
|
20
|
+
type: {
|
|
21
|
+
type: StringConstructor;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
variant: ButtonVariant;
|
|
25
|
+
size: ButtonSize;
|
|
26
|
+
disabled: boolean;
|
|
27
|
+
loading: boolean;
|
|
28
|
+
type: string;
|
|
29
|
+
static styles: import("lit").CSSResult;
|
|
30
|
+
handleClick(e: MouseEvent): void;
|
|
31
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
32
|
+
}
|
package/dist/button.js
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { LitElement, html, css } from 'lit';
|
|
2
|
+
export class ActivityualButton extends LitElement {
|
|
3
|
+
constructor() {
|
|
4
|
+
super(...arguments);
|
|
5
|
+
this.variant = 'primary';
|
|
6
|
+
this.size = 'md';
|
|
7
|
+
this.disabled = false;
|
|
8
|
+
this.loading = false;
|
|
9
|
+
this.type = 'button';
|
|
10
|
+
}
|
|
11
|
+
static { this.properties = {
|
|
12
|
+
variant: { type: String },
|
|
13
|
+
size: { type: String },
|
|
14
|
+
disabled: { type: Boolean, reflect: true },
|
|
15
|
+
loading: { type: Boolean, reflect: true },
|
|
16
|
+
type: { type: String }
|
|
17
|
+
}; }
|
|
18
|
+
static { this.styles = css `
|
|
19
|
+
:host {
|
|
20
|
+
display: inline-block;
|
|
21
|
+
vertical-align: middle;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
button {
|
|
25
|
+
display: inline-flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
justify-content: center;
|
|
28
|
+
gap: 0.5rem;
|
|
29
|
+
font-family: Inter, 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
30
|
+
font-weight: 600;
|
|
31
|
+
letter-spacing: -0.01em;
|
|
32
|
+
border-radius: 9999px;
|
|
33
|
+
cursor: pointer;
|
|
34
|
+
transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
|
|
35
|
+
box-sizing: border-box;
|
|
36
|
+
width: 100%;
|
|
37
|
+
text-decoration: none;
|
|
38
|
+
outline: none;
|
|
39
|
+
user-select: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
button:focus-visible {
|
|
43
|
+
box-shadow: 0 0 0 2px rgba(255, 67, 5, 0.4);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Sizes */
|
|
47
|
+
button.sm {
|
|
48
|
+
height: 30px;
|
|
49
|
+
padding: 0 12px;
|
|
50
|
+
font-size: 11px;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
button.md {
|
|
54
|
+
height: 36px;
|
|
55
|
+
padding: 0 16px;
|
|
56
|
+
font-size: 12px;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
button.lg {
|
|
60
|
+
height: 42px;
|
|
61
|
+
padding: 0 22px;
|
|
62
|
+
font-size: 14px;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Primary: Vaulto solid vibrant orange */
|
|
66
|
+
button.primary,
|
|
67
|
+
button.amber {
|
|
68
|
+
background: #ff4305;
|
|
69
|
+
color: #ffffff;
|
|
70
|
+
border: 1px solid rgba(255, 255, 255, 0.15);
|
|
71
|
+
box-shadow:
|
|
72
|
+
0 4px 14px rgba(255, 67, 5, 0.35),
|
|
73
|
+
inset 0 1px 1px rgba(255, 255, 255, 0.2);
|
|
74
|
+
}
|
|
75
|
+
button.primary:hover:not(:disabled),
|
|
76
|
+
button.amber:hover:not(:disabled) {
|
|
77
|
+
background: #e93b00;
|
|
78
|
+
transform: translateY(-1px);
|
|
79
|
+
box-shadow:
|
|
80
|
+
0 6px 18px rgba(255, 67, 5, 0.45),
|
|
81
|
+
inset 0 1px 1px rgba(255, 255, 255, 0.3);
|
|
82
|
+
}
|
|
83
|
+
button.primary:active:not(:disabled),
|
|
84
|
+
button.amber:active:not(:disabled) {
|
|
85
|
+
transform: translateY(1px);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Secondary: Vaulto dark translucent obsidian */
|
|
89
|
+
button.secondary,
|
|
90
|
+
button.charcoal {
|
|
91
|
+
background: rgba(255, 255, 255, 0.05);
|
|
92
|
+
color: #f5f5f5;
|
|
93
|
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
94
|
+
backdrop-filter: blur(12px);
|
|
95
|
+
-webkit-backdrop-filter: blur(12px);
|
|
96
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
|
97
|
+
}
|
|
98
|
+
button.secondary:hover:not(:disabled),
|
|
99
|
+
button.charcoal:hover:not(:disabled) {
|
|
100
|
+
background: rgba(255, 255, 255, 0.09);
|
|
101
|
+
border-color: rgba(255, 255, 255, 0.14);
|
|
102
|
+
transform: translateY(-1px);
|
|
103
|
+
}
|
|
104
|
+
button.secondary:active:not(:disabled),
|
|
105
|
+
button.charcoal:active:not(:disabled) {
|
|
106
|
+
transform: translateY(1px);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* Ghost */
|
|
110
|
+
button.ghost {
|
|
111
|
+
background: transparent;
|
|
112
|
+
color: #a5a5a5;
|
|
113
|
+
border: 1px solid transparent;
|
|
114
|
+
}
|
|
115
|
+
button.ghost:hover:not(:disabled) {
|
|
116
|
+
background: rgba(255, 255, 255, 0.05);
|
|
117
|
+
color: #ffffff;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Danger */
|
|
121
|
+
button.danger {
|
|
122
|
+
background: #ff3434;
|
|
123
|
+
color: #ffffff;
|
|
124
|
+
border: 1px solid rgba(255, 255, 255, 0.15);
|
|
125
|
+
box-shadow: 0 4px 14px rgba(255, 52, 52, 0.35);
|
|
126
|
+
}
|
|
127
|
+
button.danger:hover:not(:disabled) {
|
|
128
|
+
background: #e02020;
|
|
129
|
+
transform: translateY(-1px);
|
|
130
|
+
box-shadow: 0 6px 18px rgba(255, 52, 52, 0.45);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
button:disabled {
|
|
134
|
+
opacity: 0.35;
|
|
135
|
+
cursor: not-allowed;
|
|
136
|
+
transform: none !important;
|
|
137
|
+
box-shadow: none !important;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.spinner {
|
|
141
|
+
width: 14px;
|
|
142
|
+
height: 14px;
|
|
143
|
+
border: 2px solid rgba(255, 255, 255, 0.3);
|
|
144
|
+
border-radius: 50%;
|
|
145
|
+
border-top-color: currentColor;
|
|
146
|
+
animation: spin 0.8s linear infinite;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
@keyframes spin {
|
|
150
|
+
to {
|
|
151
|
+
transform: rotate(360deg);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
`; }
|
|
155
|
+
handleClick(e) {
|
|
156
|
+
if (this.disabled || this.loading) {
|
|
157
|
+
e.preventDefault();
|
|
158
|
+
e.stopPropagation();
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (this.type === 'submit') {
|
|
162
|
+
const form = this.closest('form');
|
|
163
|
+
if (form) {
|
|
164
|
+
form.requestSubmit();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
render() {
|
|
169
|
+
return html `
|
|
170
|
+
<button
|
|
171
|
+
class="${this.variant} ${this.size}"
|
|
172
|
+
?disabled="${this.disabled || this.loading}"
|
|
173
|
+
type="${this.type}"
|
|
174
|
+
@click="${this.handleClick}"
|
|
175
|
+
>
|
|
176
|
+
${this.loading ? html `<span class="spinner" aria-hidden="true"></span>` : ''}
|
|
177
|
+
<slot></slot>
|
|
178
|
+
</button>
|
|
179
|
+
`;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (!customElements.get('activityual-button')) {
|
|
183
|
+
customElements.define('activityual-button', ActivityualButton);
|
|
184
|
+
}
|
package/dist/card.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
export type CardVariant = 'default' | 'amber' | 'inset' | 'shell';
|
|
3
|
+
export declare class ActivityualCard extends LitElement {
|
|
4
|
+
static properties: {
|
|
5
|
+
variant: {
|
|
6
|
+
type: StringConstructor;
|
|
7
|
+
};
|
|
8
|
+
padding: {
|
|
9
|
+
type: StringConstructor;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
variant: CardVariant;
|
|
13
|
+
padding: 'none' | 'sm' | 'md' | 'lg';
|
|
14
|
+
static styles: import("lit").CSSResult;
|
|
15
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
16
|
+
}
|