@happyvertical/smrt-analytics 0.30.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/AGENTS.md +68 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +7 -0
- package/README.md +131 -0
- package/dist/__smrt-register__.d.ts +2 -0
- package/dist/__smrt-register__.d.ts.map +1 -0
- package/dist/collections/AnalyticsDataStreamCollection.d.ts +69 -0
- package/dist/collections/AnalyticsDataStreamCollection.d.ts.map +1 -0
- package/dist/collections/AnalyticsEventCollection.d.ts +131 -0
- package/dist/collections/AnalyticsEventCollection.d.ts.map +1 -0
- package/dist/collections/AnalyticsPropertyCollection.d.ts +66 -0
- package/dist/collections/AnalyticsPropertyCollection.d.ts.map +1 -0
- package/dist/collections/AnalyticsReportCollection.d.ts +69 -0
- package/dist/collections/AnalyticsReportCollection.d.ts.map +1 -0
- package/dist/collections/index.d.ts +8 -0
- package/dist/collections/index.d.ts.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1623 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.json +4161 -0
- package/dist/models/AnalyticsDataStream.d.ts +94 -0
- package/dist/models/AnalyticsDataStream.d.ts.map +1 -0
- package/dist/models/AnalyticsEvent.d.ts +142 -0
- package/dist/models/AnalyticsEvent.d.ts.map +1 -0
- package/dist/models/AnalyticsProperty.d.ts +142 -0
- package/dist/models/AnalyticsProperty.d.ts.map +1 -0
- package/dist/models/AnalyticsReport.d.ts +206 -0
- package/dist/models/AnalyticsReport.d.ts.map +1 -0
- package/dist/models/index.d.ts +8 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/playground.d.ts +2 -0
- package/dist/playground.d.ts.map +1 -0
- package/dist/playground.js +99 -0
- package/dist/playground.js.map +1 -0
- package/dist/prompts.d.ts +57 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/smrt-knowledge.json +1570 -0
- package/dist/svelte/AnalyticsSummary.svelte +63 -0
- package/dist/svelte/AnalyticsSummary.svelte.d.ts +8 -0
- package/dist/svelte/AnalyticsSummary.svelte.d.ts.map +1 -0
- package/dist/svelte/EventsTable.svelte +161 -0
- package/dist/svelte/EventsTable.svelte.d.ts +16 -0
- package/dist/svelte/EventsTable.svelte.d.ts.map +1 -0
- package/dist/svelte/PropertyInfo.svelte +139 -0
- package/dist/svelte/PropertyInfo.svelte.d.ts +12 -0
- package/dist/svelte/PropertyInfo.svelte.d.ts.map +1 -0
- package/dist/svelte/PropertyStatusBadge.svelte +65 -0
- package/dist/svelte/PropertyStatusBadge.svelte.d.ts +7 -0
- package/dist/svelte/PropertyStatusBadge.svelte.d.ts.map +1 -0
- package/dist/svelte/StatCard.svelte +63 -0
- package/dist/svelte/StatCard.svelte.d.ts +11 -0
- package/dist/svelte/StatCard.svelte.d.ts.map +1 -0
- package/dist/svelte/TrendBadge.svelte +49 -0
- package/dist/svelte/TrendBadge.svelte.d.ts +8 -0
- package/dist/svelte/TrendBadge.svelte.d.ts.map +1 -0
- package/dist/svelte/i18n.d.ts +10 -0
- package/dist/svelte/i18n.d.ts.map +1 -0
- package/dist/svelte/i18n.js +10 -0
- package/dist/svelte/index.d.ts +29 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +39 -0
- package/dist/svelte/playground.d.ts +88 -0
- package/dist/svelte/playground.d.ts.map +1 -0
- package/dist/svelte/playground.js +95 -0
- package/dist/types/index.d.ts +267 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/ui.d.ts +10 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +79 -0
- package/dist/ui.js.map +1 -0
- package/package.json +95 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
3
|
+
import type { PropertyStatsWithTrend } from '../index.js';
|
|
4
|
+
import { M } from './i18n.js';
|
|
5
|
+
import StatCard from './StatCard.svelte';
|
|
6
|
+
|
|
7
|
+
const { t } = useI18n();
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
stats: PropertyStatsWithTrend | null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const { stats }: Props = $props();
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
{#if stats}
|
|
17
|
+
<div class="analytics-summary">
|
|
18
|
+
<StatCard
|
|
19
|
+
label="Pageviews Today"
|
|
20
|
+
value={stats.todayPageviews.toLocaleString()}
|
|
21
|
+
trend={stats.trend}
|
|
22
|
+
trendPercent={stats.trendPercent}
|
|
23
|
+
subtitle={`vs. yesterday (${stats.yesterdayPageviews.toLocaleString()})`}
|
|
24
|
+
/>
|
|
25
|
+
<StatCard
|
|
26
|
+
label="Users Today"
|
|
27
|
+
value={stats.todayUsers.toLocaleString()}
|
|
28
|
+
subtitle="unique visitors"
|
|
29
|
+
/>
|
|
30
|
+
<StatCard
|
|
31
|
+
label="Yesterday Pageviews"
|
|
32
|
+
value={stats.yesterdayPageviews.toLocaleString()}
|
|
33
|
+
/>
|
|
34
|
+
<StatCard
|
|
35
|
+
label="Yesterday Users"
|
|
36
|
+
value={stats.yesterdayUsers.toLocaleString()}
|
|
37
|
+
/>
|
|
38
|
+
</div>
|
|
39
|
+
{:else}
|
|
40
|
+
<div class="analytics-empty">
|
|
41
|
+
<p>{t(M['analytics.analytics_summary.empty'])}</p>
|
|
42
|
+
</div>
|
|
43
|
+
{/if}
|
|
44
|
+
|
|
45
|
+
<style>
|
|
46
|
+
.analytics-summary {
|
|
47
|
+
display: grid;
|
|
48
|
+
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
|
49
|
+
gap: 1rem;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.analytics-empty {
|
|
53
|
+
text-align: center;
|
|
54
|
+
padding: 2rem;
|
|
55
|
+
color: var(--color-text-secondary, #6b7280);
|
|
56
|
+
background: var(--color-neutral-bg, #f9fafb);
|
|
57
|
+
border-radius: 0.5rem;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.analytics-empty p {
|
|
61
|
+
margin: 0;
|
|
62
|
+
}
|
|
63
|
+
</style>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { PropertyStatsWithTrend } from '../index.js';
|
|
2
|
+
interface Props {
|
|
3
|
+
stats: PropertyStatsWithTrend | null;
|
|
4
|
+
}
|
|
5
|
+
declare const AnalyticsSummary: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type AnalyticsSummary = ReturnType<typeof AnalyticsSummary>;
|
|
7
|
+
export default AnalyticsSummary;
|
|
8
|
+
//# sourceMappingURL=AnalyticsSummary.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalyticsSummary.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/AnalyticsSummary.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAK1D,UAAU,KAAK;IACb,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAAC;CACtC;AA8BD,QAAA,MAAM,gBAAgB,2CAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
3
|
+
import { M } from './i18n.js';
|
|
4
|
+
|
|
5
|
+
const { t } = useI18n();
|
|
6
|
+
|
|
7
|
+
interface EventRow {
|
|
8
|
+
id: string;
|
|
9
|
+
eventName: string;
|
|
10
|
+
clientId: string;
|
|
11
|
+
pagePath?: string;
|
|
12
|
+
eventTimestamp: string;
|
|
13
|
+
status: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface Props {
|
|
17
|
+
events: EventRow[];
|
|
18
|
+
maxRows?: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const { events, maxRows = 20 }: Props = $props();
|
|
22
|
+
|
|
23
|
+
const displayEvents = $derived(events.slice(0, maxRows));
|
|
24
|
+
|
|
25
|
+
function formatTimestamp(ts: string): string {
|
|
26
|
+
const date = new Date(ts);
|
|
27
|
+
if (Number.isNaN(date.getTime())) return ts;
|
|
28
|
+
return date.toLocaleString();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function statusClass(status: string): string {
|
|
32
|
+
if (status === 'sent') return 'status-sent';
|
|
33
|
+
if (status === 'failed') return 'status-failed';
|
|
34
|
+
return 'status-pending';
|
|
35
|
+
}
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<div class="events-table-wrapper">
|
|
39
|
+
{#if displayEvents.length === 0}
|
|
40
|
+
<p class="events-empty">{t(M['analytics.events_table.empty'])}</p>
|
|
41
|
+
{:else}
|
|
42
|
+
<table class="events-table">
|
|
43
|
+
<thead>
|
|
44
|
+
<tr>
|
|
45
|
+
<th>Event</th>
|
|
46
|
+
<th>Page</th>
|
|
47
|
+
<th>Client</th>
|
|
48
|
+
<th>Time</th>
|
|
49
|
+
<th>Status</th>
|
|
50
|
+
</tr>
|
|
51
|
+
</thead>
|
|
52
|
+
<tbody>
|
|
53
|
+
{#each displayEvents as event (event.id)}
|
|
54
|
+
<tr>
|
|
55
|
+
<td class="event-name">{event.eventName}</td>
|
|
56
|
+
<td class="event-page">{event.pagePath ?? '-'}</td>
|
|
57
|
+
<td class="event-client" title={event.clientId}>{event.clientId.slice(0, 8)}</td>
|
|
58
|
+
<td class="event-time">{formatTimestamp(event.eventTimestamp)}</td>
|
|
59
|
+
<td><span class="status-pill {statusClass(event.status)}">{event.status}</span></td>
|
|
60
|
+
</tr>
|
|
61
|
+
{/each}
|
|
62
|
+
</tbody>
|
|
63
|
+
</table>
|
|
64
|
+
{#if events.length > maxRows}
|
|
65
|
+
<p class="events-overflow">{t(M['analytics.events_table.showing'], { maxRows, total: events.length })}</p>
|
|
66
|
+
{/if}
|
|
67
|
+
{/if}
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<style>
|
|
71
|
+
.events-table-wrapper {
|
|
72
|
+
overflow-x: auto;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.events-table {
|
|
76
|
+
width: 100%;
|
|
77
|
+
border-collapse: collapse;
|
|
78
|
+
font-size: var(--smrt-typography-body-medium-size, 0.8125rem);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.events-table th {
|
|
82
|
+
text-align: left;
|
|
83
|
+
padding: 0.5rem 0.75rem;
|
|
84
|
+
font-weight: var(--smrt-typography-weight-semibold, 600);
|
|
85
|
+
color: var(--color-text-secondary, #6b7280);
|
|
86
|
+
border-bottom: 2px solid var(--color-border, #e5e7eb);
|
|
87
|
+
font-size: var(--smrt-typography-label-medium-size, 0.75rem);
|
|
88
|
+
text-transform: uppercase;
|
|
89
|
+
letter-spacing: var(--smrt-typography-label-medium-tracking, 0.05em);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.events-table td {
|
|
93
|
+
padding: 0.5rem 0.75rem;
|
|
94
|
+
border-bottom: 1px solid var(--color-border-light, #f3f4f6);
|
|
95
|
+
color: var(--color-text-primary, #111827);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.events-table tbody tr:hover {
|
|
99
|
+
background: var(--color-hover, #f9fafb);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.event-name {
|
|
103
|
+
font-weight: var(--smrt-typography-weight-medium, 500);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.event-page {
|
|
107
|
+
max-width: 200px;
|
|
108
|
+
overflow: hidden;
|
|
109
|
+
text-overflow: ellipsis;
|
|
110
|
+
white-space: nowrap;
|
|
111
|
+
color: var(--color-text-secondary, #6b7280);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.event-client {
|
|
115
|
+
font-family: var(--smrt-font-family-mono, monospace);
|
|
116
|
+
font-size: var(--smrt-typography-body-small-size, 0.75rem);
|
|
117
|
+
color: var(--color-text-secondary, #6b7280);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.event-time {
|
|
121
|
+
white-space: nowrap;
|
|
122
|
+
color: var(--color-text-secondary, #6b7280);
|
|
123
|
+
font-size: var(--smrt-typography-label-medium-size, 0.75rem);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.status-pill {
|
|
127
|
+
display: inline-block;
|
|
128
|
+
padding: 0.125rem 0.5rem;
|
|
129
|
+
border-radius: var(--smrt-radius-full, 9999px);
|
|
130
|
+
font-size: var(--smrt-typography-label-small-size, 0.6875rem);
|
|
131
|
+
font-weight: var(--smrt-typography-weight-medium, 500);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.status-sent {
|
|
135
|
+
background: var(--color-success-bg, #dcfce7);
|
|
136
|
+
color: var(--color-success-text, #166534);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.status-failed {
|
|
140
|
+
background: var(--color-error-bg, #fee2e2);
|
|
141
|
+
color: var(--color-error-text, #991b1b);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.status-pending {
|
|
145
|
+
background: var(--color-warning-bg, #fef9c3);
|
|
146
|
+
color: var(--color-warning-text, #854d0e);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.events-empty {
|
|
150
|
+
text-align: center;
|
|
151
|
+
padding: 2rem;
|
|
152
|
+
color: var(--color-text-secondary, #6b7280);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.events-overflow {
|
|
156
|
+
text-align: center;
|
|
157
|
+
padding: 0.5rem;
|
|
158
|
+
color: var(--color-text-tertiary, #9ca3af);
|
|
159
|
+
font-size: var(--smrt-typography-body-small-size, 0.75rem);
|
|
160
|
+
}
|
|
161
|
+
</style>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
interface EventRow {
|
|
2
|
+
id: string;
|
|
3
|
+
eventName: string;
|
|
4
|
+
clientId: string;
|
|
5
|
+
pagePath?: string;
|
|
6
|
+
eventTimestamp: string;
|
|
7
|
+
status: string;
|
|
8
|
+
}
|
|
9
|
+
interface Props {
|
|
10
|
+
events: EventRow[];
|
|
11
|
+
maxRows?: number;
|
|
12
|
+
}
|
|
13
|
+
declare const EventsTable: import("svelte").Component<Props, {}, "">;
|
|
14
|
+
type EventsTable = ReturnType<typeof EventsTable>;
|
|
15
|
+
export default EventsTable;
|
|
16
|
+
//# sourceMappingURL=EventsTable.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventsTable.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/EventsTable.svelte.ts"],"names":[],"mappings":"AAOA,UAAU,QAAQ;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,KAAK;IACb,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA8DD,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
3
|
+
import { M } from './i18n.js';
|
|
4
|
+
import PropertyStatusBadge from './PropertyStatusBadge.svelte';
|
|
5
|
+
|
|
6
|
+
const { t } = useI18n();
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
propertyId: string | null;
|
|
10
|
+
measurementId: string | null;
|
|
11
|
+
provider: string | null;
|
|
12
|
+
status: 'active' | 'inactive' | 'pending';
|
|
13
|
+
lastSyncAt: string | null;
|
|
14
|
+
siteDomain?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const {
|
|
18
|
+
propertyId,
|
|
19
|
+
measurementId,
|
|
20
|
+
provider,
|
|
21
|
+
status,
|
|
22
|
+
lastSyncAt,
|
|
23
|
+
siteDomain,
|
|
24
|
+
}: Props = $props();
|
|
25
|
+
|
|
26
|
+
const PROVIDER_LABELS = new Map<string, string>([
|
|
27
|
+
['ga4', 'Google Analytics 4'],
|
|
28
|
+
['plausible', 'Plausible'],
|
|
29
|
+
['matomo', 'Matomo'],
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
const providerLabel = $derived(
|
|
33
|
+
provider ? (PROVIDER_LABELS.get(provider) ?? provider) : 'Unknown',
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const lastSyncFormatted = $derived.by(() => {
|
|
37
|
+
if (!lastSyncAt) return 'Never';
|
|
38
|
+
const parsed = new Date(lastSyncAt);
|
|
39
|
+
if (Number.isNaN(parsed.getTime())) return 'Never';
|
|
40
|
+
return parsed.toLocaleString();
|
|
41
|
+
});
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<div class="property-info">
|
|
45
|
+
<div class="property-header">
|
|
46
|
+
<h3>{t(M['analytics.property_info.title'])}</h3>
|
|
47
|
+
<PropertyStatusBadge {status} />
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
{#if propertyId}
|
|
51
|
+
<dl class="property-details">
|
|
52
|
+
<div class="detail-row">
|
|
53
|
+
<dt>Provider</dt>
|
|
54
|
+
<dd>{providerLabel}</dd>
|
|
55
|
+
</div>
|
|
56
|
+
{#if measurementId}
|
|
57
|
+
<div class="detail-row">
|
|
58
|
+
<dt>{t(M['analytics.property_info.measurement_id'])}</dt>
|
|
59
|
+
<dd><code>{measurementId}</code></dd>
|
|
60
|
+
</div>
|
|
61
|
+
{/if}
|
|
62
|
+
{#if siteDomain}
|
|
63
|
+
<div class="detail-row">
|
|
64
|
+
<dt>Domain</dt>
|
|
65
|
+
<dd>{siteDomain}</dd>
|
|
66
|
+
</div>
|
|
67
|
+
{/if}
|
|
68
|
+
<div class="detail-row">
|
|
69
|
+
<dt>{t(M['analytics.property_info.last_synced'])}</dt>
|
|
70
|
+
<dd>{lastSyncFormatted}</dd>
|
|
71
|
+
</div>
|
|
72
|
+
</dl>
|
|
73
|
+
{:else}
|
|
74
|
+
<p class="no-property">{t(M['analytics.property_info.no_property'])}</p>
|
|
75
|
+
{/if}
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<style>
|
|
79
|
+
.property-info {
|
|
80
|
+
padding: 1rem;
|
|
81
|
+
background: var(--color-surface, #fff);
|
|
82
|
+
border: 1px solid var(--color-border, #e5e7eb);
|
|
83
|
+
border-radius: 0.5rem;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.property-header {
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
justify-content: space-between;
|
|
90
|
+
margin-bottom: 0.75rem;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.property-header h3 {
|
|
94
|
+
margin: 0;
|
|
95
|
+
font-size: var(--smrt-typography-title-medium-size, 1rem);
|
|
96
|
+
font-weight: var(--smrt-typography-weight-semibold, 600);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.property-details {
|
|
100
|
+
margin: 0;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.detail-row {
|
|
104
|
+
display: flex;
|
|
105
|
+
justify-content: space-between;
|
|
106
|
+
padding: 0.375rem 0;
|
|
107
|
+
border-bottom: 1px solid var(--color-border-light, #f3f4f6);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.detail-row:last-child {
|
|
111
|
+
border-bottom: none;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
dt {
|
|
115
|
+
font-size: var(--smrt-typography-label-large-size, 0.8125rem);
|
|
116
|
+
color: var(--color-text-secondary, #6b7280);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
dd {
|
|
120
|
+
margin: 0;
|
|
121
|
+
font-size: var(--smrt-typography-body-medium-size, 0.8125rem);
|
|
122
|
+
font-weight: var(--smrt-typography-weight-medium, 500);
|
|
123
|
+
color: var(--color-text-primary, #111827);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
code {
|
|
127
|
+
font-family: var(--smrt-font-family-mono, monospace);
|
|
128
|
+
font-size: var(--smrt-typography-body-small-size, 0.75rem);
|
|
129
|
+
padding: 0.125rem 0.25rem;
|
|
130
|
+
background: var(--color-neutral-bg, #f3f4f6);
|
|
131
|
+
border-radius: 0.25rem;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.no-property {
|
|
135
|
+
margin: 0;
|
|
136
|
+
color: var(--color-text-secondary, #6b7280);
|
|
137
|
+
font-size: var(--smrt-typography-body-medium-size, 0.875rem);
|
|
138
|
+
}
|
|
139
|
+
</style>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
propertyId: string | null;
|
|
3
|
+
measurementId: string | null;
|
|
4
|
+
provider: string | null;
|
|
5
|
+
status: 'active' | 'inactive' | 'pending';
|
|
6
|
+
lastSyncAt: string | null;
|
|
7
|
+
siteDomain?: string;
|
|
8
|
+
}
|
|
9
|
+
declare const PropertyInfo: import("svelte").Component<Props, {}, "">;
|
|
10
|
+
type PropertyInfo = ReturnType<typeof PropertyInfo>;
|
|
11
|
+
export default PropertyInfo;
|
|
12
|
+
//# sourceMappingURL=PropertyInfo.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PropertyInfo.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/PropertyInfo.svelte.ts"],"names":[],"mappings":"AAQA,UAAU,KAAK;IACb,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;IAC1C,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA0ED,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
status: 'active' | 'inactive' | 'pending';
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const { status }: Props = $props();
|
|
7
|
+
|
|
8
|
+
const label = $derived(
|
|
9
|
+
status === 'active'
|
|
10
|
+
? 'Connected'
|
|
11
|
+
: status === 'pending'
|
|
12
|
+
? 'Pending'
|
|
13
|
+
: 'Disconnected',
|
|
14
|
+
);
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<span class="status-badge" class:connected={status === 'active'} class:pending={status === 'pending'} class:disconnected={status === 'inactive'}>
|
|
18
|
+
<span class="status-dot"></span>
|
|
19
|
+
{label}
|
|
20
|
+
</span>
|
|
21
|
+
|
|
22
|
+
<style>
|
|
23
|
+
.status-badge {
|
|
24
|
+
display: inline-flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
gap: 0.375rem;
|
|
27
|
+
padding: 0.25rem 0.625rem;
|
|
28
|
+
border-radius: var(--smrt-radius-full, 9999px);
|
|
29
|
+
font-size: var(--smrt-typography-label-medium-size, 0.75rem);
|
|
30
|
+
font-weight: var(--smrt-typography-weight-medium, 500);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.status-dot {
|
|
34
|
+
width: 0.5rem;
|
|
35
|
+
height: 0.5rem;
|
|
36
|
+
border-radius: var(--smrt-radius-full, 9999px);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.connected {
|
|
40
|
+
background: var(--color-success-bg, #dcfce7);
|
|
41
|
+
color: var(--color-success-text, #166534);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.connected .status-dot {
|
|
45
|
+
background: var(--color-success-main, #22c55e);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.pending {
|
|
49
|
+
background: var(--color-warning-bg, #fef9c3);
|
|
50
|
+
color: var(--color-warning-text, #854d0e);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.pending .status-dot {
|
|
54
|
+
background: var(--color-warning-main, #eab308);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.disconnected {
|
|
58
|
+
background: var(--color-neutral-bg, #f3f4f6);
|
|
59
|
+
color: var(--color-neutral-text, #4b5563);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.disconnected .status-dot {
|
|
63
|
+
background: var(--color-neutral-main, #9ca3af);
|
|
64
|
+
}
|
|
65
|
+
</style>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
status: 'active' | 'inactive' | 'pending';
|
|
3
|
+
}
|
|
4
|
+
declare const PropertyStatusBadge: import("svelte").Component<Props, {}, "">;
|
|
5
|
+
type PropertyStatusBadge = ReturnType<typeof PropertyStatusBadge>;
|
|
6
|
+
export default PropertyStatusBadge;
|
|
7
|
+
//# sourceMappingURL=PropertyStatusBadge.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PropertyStatusBadge.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/PropertyStatusBadge.svelte.ts"],"names":[],"mappings":"AAGA,UAAU,KAAK;IACb,MAAM,EAAE,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;CAC3C;AAwBD,QAAA,MAAM,mBAAmB,2CAAwC,CAAC;AAClE,KAAK,mBAAmB,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAClE,eAAe,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import TrendBadge from './TrendBadge.svelte';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
label: string;
|
|
6
|
+
value: number | string;
|
|
7
|
+
trend?: 'up' | 'down' | 'flat';
|
|
8
|
+
trendPercent?: number;
|
|
9
|
+
subtitle?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const { label, value, trend, trendPercent, subtitle }: Props = $props();
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<div class="stat-card">
|
|
16
|
+
<div class="stat-label">{label}</div>
|
|
17
|
+
<div class="stat-row">
|
|
18
|
+
<div class="stat-value">{value}</div>
|
|
19
|
+
{#if trend && trendPercent !== undefined}
|
|
20
|
+
<TrendBadge {trend} percent={trendPercent} />
|
|
21
|
+
{/if}
|
|
22
|
+
</div>
|
|
23
|
+
{#if subtitle}
|
|
24
|
+
<div class="stat-subtitle">{subtitle}</div>
|
|
25
|
+
{/if}
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<style>
|
|
29
|
+
.stat-card {
|
|
30
|
+
padding: 1rem;
|
|
31
|
+
background: var(--color-surface, #fff);
|
|
32
|
+
border: 1px solid var(--color-border, #e5e7eb);
|
|
33
|
+
border-radius: 0.5rem;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.stat-label {
|
|
37
|
+
font-size: var(--smrt-typography-label-medium-size, 0.75rem);
|
|
38
|
+
font-weight: var(--smrt-typography-weight-medium, 500);
|
|
39
|
+
color: var(--color-text-secondary, #6b7280);
|
|
40
|
+
text-transform: uppercase;
|
|
41
|
+
letter-spacing: var(--smrt-typography-label-medium-tracking, 0.05em);
|
|
42
|
+
margin-bottom: 0.25rem;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.stat-row {
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: baseline;
|
|
48
|
+
gap: 0.5rem;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.stat-value {
|
|
52
|
+
font-size: var(--smrt-typography-headline-small-size, 1.5rem);
|
|
53
|
+
font-weight: var(--smrt-typography-weight-bold, 700);
|
|
54
|
+
color: var(--color-text-primary, #111827);
|
|
55
|
+
line-height: var(--smrt-typography-headline-small-line-height, 1.2);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.stat-subtitle {
|
|
59
|
+
font-size: var(--smrt-typography-body-small-size, 0.75rem);
|
|
60
|
+
color: var(--color-text-tertiary, #9ca3af);
|
|
61
|
+
margin-top: 0.25rem;
|
|
62
|
+
}
|
|
63
|
+
</style>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
label: string;
|
|
3
|
+
value: number | string;
|
|
4
|
+
trend?: 'up' | 'down' | 'flat';
|
|
5
|
+
trendPercent?: number;
|
|
6
|
+
subtitle?: string;
|
|
7
|
+
}
|
|
8
|
+
declare const StatCard: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type StatCard = ReturnType<typeof StatCard>;
|
|
10
|
+
export default StatCard;
|
|
11
|
+
//# sourceMappingURL=StatCard.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatCard.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/StatCard.svelte.ts"],"names":[],"mappings":"AAMA,UAAU,KAAK;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAyBD,QAAA,MAAM,QAAQ,2CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
trend: 'up' | 'down' | 'flat';
|
|
4
|
+
percent: number;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const { trend, percent }: Props = $props();
|
|
8
|
+
|
|
9
|
+
const arrow = $derived(
|
|
10
|
+
trend === 'up' ? '\u2191' : trend === 'down' ? '\u2193' : '\u2192',
|
|
11
|
+
);
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<span class="trend-badge" class:up={trend === 'up'} class:down={trend === 'down'} class:flat={trend === 'flat'}>
|
|
15
|
+
<span class="trend-arrow">{arrow}</span>
|
|
16
|
+
<span class="trend-percent">{Math.abs(percent)}%</span>
|
|
17
|
+
</span>
|
|
18
|
+
|
|
19
|
+
<style>
|
|
20
|
+
.trend-badge {
|
|
21
|
+
display: inline-flex;
|
|
22
|
+
align-items: center;
|
|
23
|
+
gap: 0.25rem;
|
|
24
|
+
padding: 0.125rem 0.5rem;
|
|
25
|
+
border-radius: var(--smrt-radius-full, 9999px);
|
|
26
|
+
font-size: var(--smrt-typography-label-medium-size, 0.75rem);
|
|
27
|
+
font-weight: var(--smrt-typography-weight-semibold, 600);
|
|
28
|
+
line-height: 1;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.trend-badge.up {
|
|
32
|
+
background: var(--color-success-bg, #dcfce7);
|
|
33
|
+
color: var(--color-success-text, #166534);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.trend-badge.down {
|
|
37
|
+
background: var(--color-error-bg, #fee2e2);
|
|
38
|
+
color: var(--color-error-text, #991b1b);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.trend-badge.flat {
|
|
42
|
+
background: var(--color-neutral-bg, #f3f4f6);
|
|
43
|
+
color: var(--color-neutral-text, #4b5563);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.trend-arrow {
|
|
47
|
+
font-size: var(--smrt-typography-label-large-size, 0.875rem);
|
|
48
|
+
}
|
|
49
|
+
</style>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
trend: 'up' | 'down' | 'flat';
|
|
3
|
+
percent: number;
|
|
4
|
+
}
|
|
5
|
+
declare const TrendBadge: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type TrendBadge = ReturnType<typeof TrendBadge>;
|
|
7
|
+
export default TrendBadge;
|
|
8
|
+
//# sourceMappingURL=TrendBadge.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TrendBadge.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/TrendBadge.svelte.ts"],"names":[],"mappings":"AAGA,UAAU,KAAK;IACb,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;CACjB;AAoBD,QAAA,MAAM,UAAU,2CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const M: {
|
|
2
|
+
readonly 'analytics.analytics_summary.empty': "analytics.analytics_summary.empty";
|
|
3
|
+
readonly 'analytics.events_table.empty': "analytics.events_table.empty";
|
|
4
|
+
readonly 'analytics.events_table.showing': "analytics.events_table.showing";
|
|
5
|
+
readonly 'analytics.property_info.title': "analytics.property_info.title";
|
|
6
|
+
readonly 'analytics.property_info.measurement_id': "analytics.property_info.measurement_id";
|
|
7
|
+
readonly 'analytics.property_info.last_synced': "analytics.property_info.last_synced";
|
|
8
|
+
readonly 'analytics.property_info.no_property': "analytics.property_info.no_property";
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=i18n.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/svelte/i18n.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,CAAC;;;;;;;;CASZ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { defineMessages } from '@happyvertical/smrt-ui/i18n';
|
|
2
|
+
export const M = defineMessages({
|
|
3
|
+
'analytics.analytics_summary.empty': 'No analytics data available yet.',
|
|
4
|
+
'analytics.events_table.empty': 'No recent events.',
|
|
5
|
+
'analytics.events_table.showing': 'Showing {maxRows} of {total} events',
|
|
6
|
+
'analytics.property_info.title': 'Analytics Property',
|
|
7
|
+
'analytics.property_info.measurement_id': 'Measurement ID',
|
|
8
|
+
'analytics.property_info.last_synced': 'Last Synced',
|
|
9
|
+
'analytics.property_info.no_property': 'No analytics property configured for this site.',
|
|
10
|
+
});
|