@adarsh.nishad/activityual-ui 0.0.0-stage → 0.2.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.
@@ -0,0 +1,140 @@
1
+ import { LitElement, html, css } from 'lit';
2
+ import './button.js';
3
+ export class ActivityualConfirmDialog extends LitElement {
4
+ constructor() {
5
+ super(...arguments);
6
+ this.open = false;
7
+ this.title = 'Confirm Action';
8
+ this.message = 'Are you sure you want to proceed?';
9
+ this.confirmText = 'Confirm';
10
+ this.cancelText = 'Cancel';
11
+ this.danger = false;
12
+ }
13
+ static { this.properties = {
14
+ open: { type: Boolean, reflect: true },
15
+ title: { type: String },
16
+ message: { type: String },
17
+ confirmText: { type: String },
18
+ cancelText: { type: String },
19
+ danger: { type: Boolean }
20
+ }; }
21
+ static { this.styles = css `
22
+ :host {
23
+ display: contents;
24
+ }
25
+
26
+ .backdrop {
27
+ position: fixed;
28
+ inset: 0;
29
+ background: rgba(8, 8, 8, 0.82);
30
+ backdrop-filter: blur(20px);
31
+ -webkit-backdrop-filter: blur(20px);
32
+ z-index: 999;
33
+ display: flex;
34
+ align-items: center;
35
+ justify-content: center;
36
+ padding: 1.5rem;
37
+ box-sizing: border-box;
38
+ animation: fadeIn 0.2s ease;
39
+ }
40
+
41
+ .dialog {
42
+ background: linear-gradient(145deg, rgba(38, 38, 38, 0.95) 0%, rgba(20, 20, 20, 0.98) 100%);
43
+ backdrop-filter: blur(28px);
44
+ -webkit-backdrop-filter: blur(28px);
45
+ border: 1px solid rgba(255, 255, 255, 0.08);
46
+ border-radius: 16px;
47
+ padding: 1.75rem;
48
+ max-width: 420px;
49
+ width: 100%;
50
+ box-shadow:
51
+ 0 25px 60px -15px rgba(0, 0, 0, 0.8),
52
+ 0 0 0 1px rgba(255, 255, 255, 0.05) inset;
53
+ font-family: Inter, 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
54
+ box-sizing: border-box;
55
+ animation: slideUp 0.25s cubic-bezier(0.16, 1, 0.3, 1);
56
+ }
57
+
58
+ .title {
59
+ font-size: 16px;
60
+ font-weight: 700;
61
+ color: #f5f5f5;
62
+ margin: 0 0 0.4rem 0;
63
+ letter-spacing: -0.01em;
64
+ }
65
+
66
+ .message {
67
+ font-size: 12.5px;
68
+ color: #a5a5a5;
69
+ line-height: 1.5;
70
+ margin: 0 0 1.25rem 0;
71
+ }
72
+
73
+ .actions {
74
+ display: flex;
75
+ align-items: center;
76
+ justify-content: flex-end;
77
+ gap: 0.65rem;
78
+ }
79
+
80
+ @keyframes fadeIn {
81
+ from {
82
+ opacity: 0;
83
+ }
84
+ to {
85
+ opacity: 1;
86
+ }
87
+ }
88
+
89
+ @keyframes slideUp {
90
+ from {
91
+ opacity: 0;
92
+ transform: translateY(10px) scale(0.98);
93
+ }
94
+ to {
95
+ opacity: 1;
96
+ transform: translateY(0) scale(1);
97
+ }
98
+ }
99
+ `; }
100
+ handleConfirm() {
101
+ this.dispatchEvent(new CustomEvent('confirm', { bubbles: true, composed: true }));
102
+ this.open = false;
103
+ }
104
+ handleCancel() {
105
+ this.dispatchEvent(new CustomEvent('cancel', { bubbles: true, composed: true }));
106
+ this.open = false;
107
+ }
108
+ render() {
109
+ if (!this.open)
110
+ return html ``;
111
+ return html `
112
+ <div
113
+ class="backdrop"
114
+ @click="${(e) => {
115
+ if (e.target === e.currentTarget)
116
+ this.handleCancel();
117
+ }}"
118
+ >
119
+ <div class="dialog" role="dialog" aria-modal="true" aria-labelledby="dialog-title">
120
+ <h3 class="title" id="dialog-title">${this.title}</h3>
121
+ <p class="message">${this.message}</p>
122
+ <div class="actions">
123
+ <activityual-button variant="secondary" @click="${this.handleCancel}">
124
+ ${this.cancelText}
125
+ </activityual-button>
126
+ <activityual-button
127
+ variant="${this.danger ? 'danger' : 'primary'}"
128
+ @click="${this.handleConfirm}"
129
+ >
130
+ ${this.confirmText}
131
+ </activityual-button>
132
+ </div>
133
+ </div>
134
+ </div>
135
+ `;
136
+ }
137
+ }
138
+ if (!customElements.get('activityual-confirm-dialog')) {
139
+ customElements.define('activityual-confirm-dialog', ActivityualConfirmDialog);
140
+ }
@@ -0,0 +1,25 @@
1
+ import { LitElement } from 'lit';
2
+ import './button.js';
3
+ export declare class ActivityualEmptyState extends LitElement {
4
+ static properties: {
5
+ title: {
6
+ type: StringConstructor;
7
+ };
8
+ message: {
9
+ type: StringConstructor;
10
+ };
11
+ actionText: {
12
+ type: StringConstructor;
13
+ };
14
+ icon: {
15
+ type: StringConstructor;
16
+ };
17
+ };
18
+ title: string;
19
+ message: string;
20
+ actionText: string;
21
+ icon: string;
22
+ static styles: import("lit").CSSResult;
23
+ handleAction(): void;
24
+ render(): import("lit-html").TemplateResult<1>;
25
+ }
@@ -0,0 +1,95 @@
1
+ import { LitElement, html, css } from 'lit';
2
+ import './button.js';
3
+ export class ActivityualEmptyState extends LitElement {
4
+ constructor() {
5
+ super(...arguments);
6
+ this.title = 'No habits tracked yet';
7
+ this.message = 'Start by creating your first daily ritual to build momentum.';
8
+ this.actionText = 'Create Habit';
9
+ this.icon = '🌱';
10
+ }
11
+ static { this.properties = {
12
+ title: { type: String },
13
+ message: { type: String },
14
+ actionText: { type: String },
15
+ icon: { type: String }
16
+ }; }
17
+ static { this.styles = css `
18
+ :host {
19
+ display: block;
20
+ box-sizing: border-box;
21
+ }
22
+
23
+ .empty-box {
24
+ background: linear-gradient(145deg, rgba(38, 38, 38, 0.5) 0%, rgba(20, 20, 20, 0.7) 100%);
25
+ backdrop-filter: blur(16px);
26
+ -webkit-backdrop-filter: blur(16px);
27
+ border: 1px dashed rgba(255, 255, 255, 0.12);
28
+ border-radius: 16px;
29
+ padding: 2.5rem 1.75rem;
30
+ text-align: center;
31
+ display: flex;
32
+ flex-direction: column;
33
+ align-items: center;
34
+ justify-content: center;
35
+ gap: 0.85rem;
36
+ font-family: Inter, 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
37
+ box-sizing: border-box;
38
+ }
39
+
40
+ .icon-pod {
41
+ width: 52px;
42
+ height: 52px;
43
+ border-radius: 50%;
44
+ background: rgba(255, 67, 5, 0.12);
45
+ border: 1px solid rgba(255, 67, 5, 0.25);
46
+ display: flex;
47
+ align-items: center;
48
+ justify-content: center;
49
+ font-size: 24px;
50
+ margin-bottom: 0.25rem;
51
+ box-shadow: 0 0 16px rgba(255, 67, 5, 0.18);
52
+ }
53
+
54
+ .title {
55
+ font-size: 16px;
56
+ font-weight: 700;
57
+ color: #f5f5f5;
58
+ margin: 0;
59
+ letter-spacing: -0.01em;
60
+ }
61
+
62
+ .message {
63
+ font-size: 12.5px;
64
+ color: #a5a5a5;
65
+ max-width: 360px;
66
+ line-height: 1.5;
67
+ margin: 0 0 0.5rem 0;
68
+ }
69
+ `; }
70
+ handleAction() {
71
+ this.dispatchEvent(new CustomEvent('action-click', {
72
+ bubbles: true,
73
+ composed: true
74
+ }));
75
+ }
76
+ render() {
77
+ return html `
78
+ <div class="empty-box">
79
+ <div class="icon-pod" aria-hidden="true">${this.icon}</div>
80
+ <h3 class="title">${this.title}</h3>
81
+ <p class="message">${this.message}</p>
82
+ ${this.actionText
83
+ ? html `
84
+ <activityual-button variant="primary" @click="${this.handleAction}">
85
+ + ${this.actionText}
86
+ </activityual-button>
87
+ `
88
+ : ''}
89
+ </div>
90
+ `;
91
+ }
92
+ }
93
+ if (!customElements.get('activityual-empty-state')) {
94
+ customElements.define('activityual-empty-state', ActivityualEmptyState);
95
+ }
@@ -0,0 +1,40 @@
1
+ import { LitElement } from 'lit';
2
+ export declare class ActivityualFormField extends LitElement {
3
+ static properties: {
4
+ label: {
5
+ type: StringConstructor;
6
+ };
7
+ name: {
8
+ type: StringConstructor;
9
+ };
10
+ type: {
11
+ type: StringConstructor;
12
+ };
13
+ value: {
14
+ type: StringConstructor;
15
+ };
16
+ placeholder: {
17
+ type: StringConstructor;
18
+ };
19
+ error: {
20
+ type: StringConstructor;
21
+ };
22
+ required: {
23
+ type: BooleanConstructor;
24
+ };
25
+ disabled: {
26
+ type: BooleanConstructor;
27
+ };
28
+ };
29
+ label: string;
30
+ name: string;
31
+ type: string;
32
+ value: string;
33
+ placeholder: string;
34
+ error: string;
35
+ required: boolean;
36
+ disabled: boolean;
37
+ static styles: import("lit").CSSResult;
38
+ handleInput(e: Event): void;
39
+ render(): import("lit-html").TemplateResult<1>;
40
+ }
@@ -0,0 +1,144 @@
1
+ import { LitElement, html, css } from 'lit';
2
+ export class ActivityualFormField extends LitElement {
3
+ constructor() {
4
+ super(...arguments);
5
+ this.label = '';
6
+ this.name = '';
7
+ this.type = 'text';
8
+ this.value = '';
9
+ this.placeholder = '';
10
+ this.error = '';
11
+ this.required = false;
12
+ this.disabled = false;
13
+ }
14
+ static { this.properties = {
15
+ label: { type: String },
16
+ name: { type: String },
17
+ type: { type: String },
18
+ value: { type: String },
19
+ placeholder: { type: String },
20
+ error: { type: String },
21
+ required: { type: Boolean },
22
+ disabled: { type: Boolean }
23
+ }; }
24
+ static { this.styles = css `
25
+ :host {
26
+ display: block;
27
+ box-sizing: border-box;
28
+ margin-bottom: 1.15rem;
29
+ }
30
+
31
+ .field-group {
32
+ display: flex;
33
+ flex-direction: column;
34
+ gap: 0.35rem;
35
+ font-family: Inter, 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
36
+ }
37
+
38
+ label {
39
+ font-size: 11.5px;
40
+ font-weight: 600;
41
+ color: #f5f5f5;
42
+ display: flex;
43
+ align-items: center;
44
+ gap: 0.25rem;
45
+ }
46
+
47
+ .required-star {
48
+ color: #ff3434;
49
+ }
50
+
51
+ .input-trough {
52
+ background: #121212;
53
+ border: 1px solid rgba(255, 255, 255, 0.06);
54
+ border-radius: 10px;
55
+ padding: 0 0.85rem;
56
+ height: 40px;
57
+ display: flex;
58
+ align-items: center;
59
+ box-shadow:
60
+ inset 0 2px 4px rgba(0, 0, 0, 0.5),
61
+ 0 1px 1px rgba(255, 255, 255, 0.02);
62
+ transition: all 0.2s ease;
63
+ }
64
+
65
+ .input-trough:focus-within {
66
+ border-color: #ff4305;
67
+ box-shadow:
68
+ 0 0 0 2px rgba(255, 67, 5, 0.25),
69
+ inset 0 1px 2px rgba(0, 0, 0, 0.4);
70
+ }
71
+
72
+ .has-error {
73
+ border-color: #ff3434 !important;
74
+ background: rgba(255, 52, 52, 0.06) !important;
75
+ box-shadow: 0 0 0 2px rgba(255, 52, 52, 0.2) !important;
76
+ }
77
+
78
+ input {
79
+ width: 100%;
80
+ background: transparent;
81
+ border: none;
82
+ outline: none;
83
+ font-family: inherit;
84
+ font-size: 13px;
85
+ font-weight: 500;
86
+ color: #f5f5f5;
87
+ }
88
+
89
+ input::placeholder {
90
+ color: #707070;
91
+ }
92
+
93
+ input:disabled {
94
+ opacity: 0.35;
95
+ cursor: not-allowed;
96
+ }
97
+
98
+ .error-message {
99
+ font-size: 10.5px;
100
+ font-weight: 500;
101
+ color: #ff3434;
102
+ margin-top: 0.2rem;
103
+ }
104
+ `; }
105
+ handleInput(e) {
106
+ const target = e.target;
107
+ this.value = target.value;
108
+ this.dispatchEvent(new CustomEvent('input-change', {
109
+ detail: { name: this.name, value: this.value },
110
+ bubbles: true,
111
+ composed: true
112
+ }));
113
+ }
114
+ render() {
115
+ return html `
116
+ <div class="field-group">
117
+ ${this.label
118
+ ? html `
119
+ <label for="${this.name}">
120
+ <span>${this.label}</span>
121
+ ${this.required ? html `<span class="required-star" aria-hidden="true">*</span>` : ''}
122
+ </label>
123
+ `
124
+ : ''}
125
+ <div class="input-trough ${this.error ? 'has-error' : ''}">
126
+ <input
127
+ id="${this.name}"
128
+ name="${this.name}"
129
+ type="${this.type}"
130
+ .value="${this.value}"
131
+ placeholder="${this.placeholder}"
132
+ ?required="${this.required}"
133
+ ?disabled="${this.disabled}"
134
+ @input="${this.handleInput}"
135
+ />
136
+ </div>
137
+ ${this.error ? html `<span class="error-message" role="alert">${this.error}</span>` : ''}
138
+ </div>
139
+ `;
140
+ }
141
+ }
142
+ if (!customElements.get('activityual-form-field')) {
143
+ customElements.define('activityual-form-field', ActivityualFormField);
144
+ }
@@ -0,0 +1,13 @@
1
+ export * from './tokens.js';
2
+ export * from './button.js';
3
+ export * from './card.js';
4
+ export * from './status-pill.js';
5
+ export * from './streak-badge.js';
6
+ export * from './progress-ring.js';
7
+ export * from './stat-card.js';
8
+ export * from './activity-card.js';
9
+ export * from './chart-panel.js';
10
+ export * from './recommendation-banner.js';
11
+ export * from './empty-state.js';
12
+ export * from './confirm-dialog.js';
13
+ export * from './form-field.js';
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ export * from './tokens.js';
2
+ export * from './button.js';
3
+ export * from './card.js';
4
+ export * from './status-pill.js';
5
+ export * from './streak-badge.js';
6
+ export * from './progress-ring.js';
7
+ export * from './stat-card.js';
8
+ export * from './activity-card.js';
9
+ export * from './chart-panel.js';
10
+ export * from './recommendation-banner.js';
11
+ export * from './empty-state.js';
12
+ export * from './confirm-dialog.js';
13
+ export * from './form-field.js';
@@ -0,0 +1,23 @@
1
+ import { LitElement } from 'lit';
2
+ export declare class ActivityualProgressRing extends LitElement {
3
+ static properties: {
4
+ percentage: {
5
+ type: NumberConstructor;
6
+ };
7
+ size: {
8
+ type: NumberConstructor;
9
+ };
10
+ strokeWidth: {
11
+ type: NumberConstructor;
12
+ };
13
+ label: {
14
+ type: StringConstructor;
15
+ };
16
+ };
17
+ percentage: number;
18
+ size: number;
19
+ strokeWidth: number;
20
+ label: string;
21
+ static styles: import("lit").CSSResult;
22
+ render(): import("lit-html").TemplateResult<1>;
23
+ }
@@ -0,0 +1,124 @@
1
+ import { LitElement, html, css } from 'lit';
2
+ export class ActivityualProgressRing extends LitElement {
3
+ constructor() {
4
+ super(...arguments);
5
+ this.percentage = 0;
6
+ this.size = 120;
7
+ this.strokeWidth = 10;
8
+ this.label = 'Rhythm';
9
+ }
10
+ static { this.properties = {
11
+ percentage: { type: Number },
12
+ size: { type: Number },
13
+ strokeWidth: { type: Number },
14
+ label: { type: String }
15
+ }; }
16
+ static { this.styles = css `
17
+ :host {
18
+ display: inline-block;
19
+ vertical-align: middle;
20
+ }
21
+
22
+ .container {
23
+ position: relative;
24
+ display: inline-flex;
25
+ align-items: center;
26
+ justify-content: center;
27
+ font-family: Inter, 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
28
+ user-select: none;
29
+ }
30
+
31
+ svg {
32
+ transform: rotate(-90deg);
33
+ }
34
+
35
+ .bg-circle {
36
+ fill: none;
37
+ stroke: rgba(255, 255, 255, 0.05);
38
+ }
39
+
40
+ .progress-circle {
41
+ fill: none;
42
+ stroke: #ff4305;
43
+ stroke-linecap: round;
44
+ transition: stroke-dashoffset 0.5s cubic-bezier(0.16, 1, 0.3, 1);
45
+ filter: drop-shadow(0 0 6px rgba(255, 67, 5, 0.4));
46
+ }
47
+
48
+ .progress-circle.complete {
49
+ stroke: #25d366;
50
+ filter: drop-shadow(0 0 6px rgba(37, 211, 102, 0.4));
51
+ }
52
+
53
+ .content {
54
+ position: absolute;
55
+ display: flex;
56
+ flex-direction: column;
57
+ align-items: center;
58
+ justify-content: center;
59
+ text-align: center;
60
+ }
61
+
62
+ .value {
63
+ font-size: 20px;
64
+ font-weight: 700;
65
+ color: #f5f5f5;
66
+ line-height: 1;
67
+ font-family: 'JetBrains Mono', monospace;
68
+ font-variant-numeric: tabular-nums;
69
+ }
70
+
71
+ .label-text {
72
+ font-size: 9.5px;
73
+ font-weight: 600;
74
+ color: #707070;
75
+ text-transform: uppercase;
76
+ letter-spacing: 0.05em;
77
+ margin-top: 3px;
78
+ }
79
+ `; }
80
+ render() {
81
+ const radius = (this.size - this.strokeWidth) / 2;
82
+ const circumference = 2 * Math.PI * radius;
83
+ const clampedPercent = Math.min(Math.max(this.percentage, 0), 100);
84
+ const strokeDashoffset = circumference - (clampedPercent / 100) * circumference;
85
+ const isComplete = clampedPercent >= 100;
86
+ return html `
87
+ <div
88
+ class="container"
89
+ style="width: ${this.size}px; height: ${this.size}px;"
90
+ role="progressbar"
91
+ aria-valuenow="${clampedPercent}"
92
+ aria-valuemin="0"
93
+ aria-valuemax="100"
94
+ aria-label="${this.label}: ${clampedPercent}%"
95
+ >
96
+ <svg width="${this.size}" height="${this.size}">
97
+ <circle
98
+ class="bg-circle"
99
+ cx="${this.size / 2}"
100
+ cy="${this.size / 2}"
101
+ r="${radius}"
102
+ stroke-width="${this.strokeWidth}"
103
+ ></circle>
104
+ <circle
105
+ class="progress-circle ${isComplete ? 'complete' : ''}"
106
+ cx="${this.size / 2}"
107
+ cy="${this.size / 2}"
108
+ r="${radius}"
109
+ stroke-width="${this.strokeWidth}"
110
+ stroke-dasharray="${circumference}"
111
+ stroke-dashoffset="${strokeDashoffset}"
112
+ ></circle>
113
+ </svg>
114
+ <div class="content">
115
+ <span class="value">${clampedPercent}%</span>
116
+ <span class="label-text">${this.label}</span>
117
+ </div>
118
+ </div>
119
+ `;
120
+ }
121
+ }
122
+ if (!customElements.get('activityual-progress-ring')) {
123
+ customElements.define('activityual-progress-ring', ActivityualProgressRing);
124
+ }
@@ -0,0 +1,31 @@
1
+ import { LitElement } from 'lit';
2
+ export declare class ActivityualRecommendationBanner extends LitElement {
3
+ static properties: {
4
+ activityTitle: {
5
+ type: StringConstructor;
6
+ };
7
+ suggestedTime: {
8
+ type: StringConstructor;
9
+ };
10
+ reason: {
11
+ type: StringConstructor;
12
+ };
13
+ sampleSize: {
14
+ type: NumberConstructor;
15
+ };
16
+ status: {
17
+ type: StringConstructor;
18
+ };
19
+ generatedAt: {
20
+ type: StringConstructor;
21
+ };
22
+ };
23
+ activityTitle: string;
24
+ suggestedTime: string;
25
+ reason: string;
26
+ sampleSize: number;
27
+ status: 'available' | 'insufficient_history';
28
+ generatedAt: string;
29
+ static styles: import("lit").CSSResult;
30
+ render(): import("lit-html").TemplateResult<1>;
31
+ }