@happyvertical/smrt-messages 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.
Files changed (153) hide show
  1. package/AGENTS.md +31 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +7 -0
  4. package/README.md +103 -0
  5. package/dist/__smrt-register__.d.ts +2 -0
  6. package/dist/__smrt-register__.d.ts.map +1 -0
  7. package/dist/collections/AccountCollection.d.ts +42 -0
  8. package/dist/collections/AccountCollection.d.ts.map +1 -0
  9. package/dist/collections/AttachmentCollection.d.ts +67 -0
  10. package/dist/collections/AttachmentCollection.d.ts.map +1 -0
  11. package/dist/collections/BlacklistCollection.d.ts +14 -0
  12. package/dist/collections/BlacklistCollection.d.ts.map +1 -0
  13. package/dist/collections/EmailAccountCollection.d.ts +74 -0
  14. package/dist/collections/EmailAccountCollection.d.ts.map +1 -0
  15. package/dist/collections/EmailAttachmentCollection.d.ts +38 -0
  16. package/dist/collections/EmailAttachmentCollection.d.ts.map +1 -0
  17. package/dist/collections/EmailCollection.d.ts +81 -0
  18. package/dist/collections/EmailCollection.d.ts.map +1 -0
  19. package/dist/collections/EmailFolderCollection.d.ts +85 -0
  20. package/dist/collections/EmailFolderCollection.d.ts.map +1 -0
  21. package/dist/collections/MessageCollection.d.ts +74 -0
  22. package/dist/collections/MessageCollection.d.ts.map +1 -0
  23. package/dist/collections/WhitelistCollection.d.ts +18 -0
  24. package/dist/collections/WhitelistCollection.d.ts.map +1 -0
  25. package/dist/index.d.ts +27 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +3068 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/manifest.json +10576 -0
  30. package/dist/models/Account.d.ts +47 -0
  31. package/dist/models/Account.d.ts.map +1 -0
  32. package/dist/models/Attachment.d.ts +48 -0
  33. package/dist/models/Attachment.d.ts.map +1 -0
  34. package/dist/models/Blacklist.d.ts +21 -0
  35. package/dist/models/Blacklist.d.ts.map +1 -0
  36. package/dist/models/Email.d.ts +98 -0
  37. package/dist/models/Email.d.ts.map +1 -0
  38. package/dist/models/EmailAccount.d.ts +65 -0
  39. package/dist/models/EmailAccount.d.ts.map +1 -0
  40. package/dist/models/EmailAttachment.d.ts +19 -0
  41. package/dist/models/EmailAttachment.d.ts.map +1 -0
  42. package/dist/models/EmailFolder.d.ts +65 -0
  43. package/dist/models/EmailFolder.d.ts.map +1 -0
  44. package/dist/models/Message.d.ts +105 -0
  45. package/dist/models/Message.d.ts.map +1 -0
  46. package/dist/models/SlackAccount.d.ts +13 -0
  47. package/dist/models/SlackAccount.d.ts.map +1 -0
  48. package/dist/models/SlackMessage.d.ts +34 -0
  49. package/dist/models/SlackMessage.d.ts.map +1 -0
  50. package/dist/models/Tweet.d.ts +31 -0
  51. package/dist/models/Tweet.d.ts.map +1 -0
  52. package/dist/models/TwitterAccount.d.ts +12 -0
  53. package/dist/models/TwitterAccount.d.ts.map +1 -0
  54. package/dist/models/Whitelist.d.ts +21 -0
  55. package/dist/models/Whitelist.d.ts.map +1 -0
  56. package/dist/playground.d.ts +2 -0
  57. package/dist/playground.d.ts.map +1 -0
  58. package/dist/playground.js +176 -0
  59. package/dist/playground.js.map +1 -0
  60. package/dist/senders/EmailSender.d.ts +13 -0
  61. package/dist/senders/EmailSender.d.ts.map +1 -0
  62. package/dist/senders/SlackSender.d.ts +11 -0
  63. package/dist/senders/SlackSender.d.ts.map +1 -0
  64. package/dist/senders/TweetSender.d.ts +11 -0
  65. package/dist/senders/TweetSender.d.ts.map +1 -0
  66. package/dist/smrt-knowledge.json +4234 -0
  67. package/dist/svelte/components/AccountAvatar.svelte +107 -0
  68. package/dist/svelte/components/AccountAvatar.svelte.d.ts +12 -0
  69. package/dist/svelte/components/AccountAvatar.svelte.d.ts.map +1 -0
  70. package/dist/svelte/components/AccountCard.svelte +173 -0
  71. package/dist/svelte/components/AccountCard.svelte.d.ts +12 -0
  72. package/dist/svelte/components/AccountCard.svelte.d.ts.map +1 -0
  73. package/dist/svelte/components/AccountList.svelte +90 -0
  74. package/dist/svelte/components/AccountList.svelte.d.ts +12 -0
  75. package/dist/svelte/components/AccountList.svelte.d.ts.map +1 -0
  76. package/dist/svelte/components/AttachmentChip.svelte +99 -0
  77. package/dist/svelte/components/AttachmentChip.svelte.d.ts +12 -0
  78. package/dist/svelte/components/AttachmentChip.svelte.d.ts.map +1 -0
  79. package/dist/svelte/components/AttachmentUpload.svelte +160 -0
  80. package/dist/svelte/components/AttachmentUpload.svelte.d.ts +11 -0
  81. package/dist/svelte/components/AttachmentUpload.svelte.d.ts.map +1 -0
  82. package/dist/svelte/components/ComposeForm.svelte +387 -0
  83. package/dist/svelte/components/ComposeForm.svelte.d.ts +13 -0
  84. package/dist/svelte/components/ComposeForm.svelte.d.ts.map +1 -0
  85. package/dist/svelte/components/EmailAccountManager.svelte +690 -0
  86. package/dist/svelte/components/EmailAccountManager.svelte.d.ts +15 -0
  87. package/dist/svelte/components/EmailAccountManager.svelte.d.ts.map +1 -0
  88. package/dist/svelte/components/EmailFilterManager.svelte +687 -0
  89. package/dist/svelte/components/EmailFilterManager.svelte.d.ts +14 -0
  90. package/dist/svelte/components/EmailFilterManager.svelte.d.ts.map +1 -0
  91. package/dist/svelte/components/FolderNav.svelte +171 -0
  92. package/dist/svelte/components/FolderNav.svelte.d.ts +11 -0
  93. package/dist/svelte/components/FolderNav.svelte.d.ts.map +1 -0
  94. package/dist/svelte/components/ForwardForm.svelte +166 -0
  95. package/dist/svelte/components/ForwardForm.svelte.d.ts +10 -0
  96. package/dist/svelte/components/ForwardForm.svelte.d.ts.map +1 -0
  97. package/dist/svelte/components/MessageCard.svelte +336 -0
  98. package/dist/svelte/components/MessageCard.svelte.d.ts +20 -0
  99. package/dist/svelte/components/MessageCard.svelte.d.ts.map +1 -0
  100. package/dist/svelte/components/MessageDetail.svelte +309 -0
  101. package/dist/svelte/components/MessageDetail.svelte.d.ts +18 -0
  102. package/dist/svelte/components/MessageDetail.svelte.d.ts.map +1 -0
  103. package/dist/svelte/components/MessageFilters.svelte +228 -0
  104. package/dist/svelte/components/MessageFilters.svelte.d.ts +13 -0
  105. package/dist/svelte/components/MessageFilters.svelte.d.ts.map +1 -0
  106. package/dist/svelte/components/MessageList.svelte +101 -0
  107. package/dist/svelte/components/MessageList.svelte.d.ts +23 -0
  108. package/dist/svelte/components/MessageList.svelte.d.ts.map +1 -0
  109. package/dist/svelte/components/MessageStatusIndicator.svelte +82 -0
  110. package/dist/svelte/components/MessageStatusIndicator.svelte.d.ts +11 -0
  111. package/dist/svelte/components/MessageStatusIndicator.svelte.d.ts.map +1 -0
  112. package/dist/svelte/components/MessageToolbar.svelte +131 -0
  113. package/dist/svelte/components/MessageToolbar.svelte.d.ts +14 -0
  114. package/dist/svelte/components/MessageToolbar.svelte.d.ts.map +1 -0
  115. package/dist/svelte/components/MessageTypeBadge.svelte +59 -0
  116. package/dist/svelte/components/MessageTypeBadge.svelte.d.ts +9 -0
  117. package/dist/svelte/components/MessageTypeBadge.svelte.d.ts.map +1 -0
  118. package/dist/svelte/components/RecipientInput.svelte +150 -0
  119. package/dist/svelte/components/RecipientInput.svelte.d.ts +11 -0
  120. package/dist/svelte/components/RecipientInput.svelte.d.ts.map +1 -0
  121. package/dist/svelte/components/ReplyForm.svelte +159 -0
  122. package/dist/svelte/components/ReplyForm.svelte.d.ts +11 -0
  123. package/dist/svelte/components/ReplyForm.svelte.d.ts.map +1 -0
  124. package/dist/svelte/components/SendStatusBadge.svelte +64 -0
  125. package/dist/svelte/components/SendStatusBadge.svelte.d.ts +8 -0
  126. package/dist/svelte/components/SendStatusBadge.svelte.d.ts.map +1 -0
  127. package/dist/svelte/components/ThreadView.svelte +240 -0
  128. package/dist/svelte/components/ThreadView.svelte.d.ts +12 -0
  129. package/dist/svelte/components/ThreadView.svelte.d.ts.map +1 -0
  130. package/dist/svelte/i18n.d.ts +42 -0
  131. package/dist/svelte/i18n.d.ts.map +1 -0
  132. package/dist/svelte/i18n.js +60 -0
  133. package/dist/svelte/i18n.messages.d.ts +32 -0
  134. package/dist/svelte/i18n.messages.d.ts.map +1 -0
  135. package/dist/svelte/i18n.messages.js +46 -0
  136. package/dist/svelte/index.d.ts +54 -0
  137. package/dist/svelte/index.d.ts.map +1 -0
  138. package/dist/svelte/index.js +44 -0
  139. package/dist/svelte/playground.d.ts +341 -0
  140. package/dist/svelte/playground.d.ts.map +1 -0
  141. package/dist/svelte/playground.js +171 -0
  142. package/dist/svelte/types.d.ts +195 -0
  143. package/dist/svelte/types.d.ts.map +1 -0
  144. package/dist/svelte/types.js +6 -0
  145. package/dist/types.d.ts +316 -0
  146. package/dist/types.d.ts.map +1 -0
  147. package/dist/types.js +2 -0
  148. package/dist/types.js.map +1 -0
  149. package/dist/ui.d.ts +4 -0
  150. package/dist/ui.d.ts.map +1 -0
  151. package/dist/ui.js +103 -0
  152. package/dist/ui.js.map +1 -0
  153. package/package.json +104 -0
@@ -0,0 +1,690 @@
1
+ <script lang="ts">
2
+ /**
3
+ * EmailAccountManager - Manage IMAP/SMTP email accounts
4
+ *
5
+ * Reusable component for adding, editing, testing, and removing
6
+ * email accounts. Works with any backend via callback props.
7
+ */
8
+ import { useI18n } from '@happyvertical/smrt-ui/i18n';
9
+ import { M } from '../i18n.js';
10
+ import type { EmailAccountData } from '../types.js';
11
+
12
+ const { t } = useI18n();
13
+
14
+ export interface Props {
15
+ accounts: EmailAccountData[];
16
+ readonly?: boolean;
17
+ onsave?: (data: Partial<EmailAccountData>, id?: string) => Promise<void>;
18
+ ondelete?: (account: EmailAccountData) => Promise<void>;
19
+ ontest?: (
20
+ account: EmailAccountData,
21
+ ) => Promise<{ success: boolean; error?: string }>;
22
+ }
23
+
24
+ const {
25
+ accounts,
26
+ readonly: isReadonly = false,
27
+ onsave,
28
+ ondelete,
29
+ ontest,
30
+ }: Props = $props();
31
+
32
+ let showForm = $state(false);
33
+ let editingId = $state<string | null>(null);
34
+ let saving = $state(false);
35
+ let testingId = $state<string | null>(null);
36
+ let testResult = $state<{ success: boolean; error?: string } | null>(null);
37
+
38
+ // Form state
39
+ let maName = $state('');
40
+ let maEmail = $state('');
41
+ let maProviderType = $state<'imap' | 'exchange' | 'gmail' | 'outlook'>('imap');
42
+ let maIsActive = $state(true);
43
+ let maImapHost = $state('');
44
+ let maImapPort = $state(993);
45
+ let maImapSecurity = $state<'ssl' | 'starttls' | 'none'>('ssl');
46
+ let maSmtpHost = $state('');
47
+ let maSmtpPort = $state(465);
48
+ let maSmtpSecurity = $state<'ssl' | 'starttls' | 'none'>('ssl');
49
+ let maUsername = $state('');
50
+ let maPassword = $state('');
51
+
52
+ function resetForm() {
53
+ maName = '';
54
+ maEmail = '';
55
+ maProviderType = 'imap';
56
+ maIsActive = true;
57
+ maImapHost = '';
58
+ maImapPort = 993;
59
+ maImapSecurity = 'ssl';
60
+ maSmtpHost = '';
61
+ maSmtpPort = 465;
62
+ maSmtpSecurity = 'ssl';
63
+ maUsername = '';
64
+ maPassword = '';
65
+ editingId = null;
66
+ showForm = false;
67
+ testResult = null;
68
+ }
69
+
70
+ function startEdit(acct: EmailAccountData) {
71
+ if (isReadonly) return;
72
+ maName = acct.name;
73
+ maEmail = acct.email;
74
+ maProviderType = acct.providerType;
75
+ maIsActive = acct.isActive;
76
+ maImapHost = acct.imapHost ?? '';
77
+ maImapPort = acct.imapPort ?? 993;
78
+ maImapSecurity = acct.imapSecurity ?? 'ssl';
79
+ maSmtpHost = acct.smtpHost ?? '';
80
+ maSmtpPort = acct.smtpPort ?? 465;
81
+ maSmtpSecurity = acct.smtpSecurity ?? 'ssl';
82
+ maUsername = acct.username ?? '';
83
+ maPassword = acct.password ?? '';
84
+ editingId = acct.id;
85
+ showForm = true;
86
+ testResult = null;
87
+ }
88
+
89
+ async function save() {
90
+ if (!maName.trim() || !maEmail.trim() || !onsave) return;
91
+ try {
92
+ saving = true;
93
+ const data: Partial<EmailAccountData> = {
94
+ name: maName.trim(),
95
+ email: maEmail.trim(),
96
+ providerType: maProviderType,
97
+ isActive: maIsActive,
98
+ imapHost: maImapHost.trim(),
99
+ imapPort: maImapPort,
100
+ imapSecurity: maImapSecurity,
101
+ smtpHost: maSmtpHost.trim(),
102
+ smtpPort: maSmtpPort,
103
+ smtpSecurity: maSmtpSecurity,
104
+ username: maUsername.trim(),
105
+ };
106
+ if (!editingId || maPassword) {
107
+ data.password = maPassword;
108
+ }
109
+ await onsave(data, editingId ?? undefined);
110
+ resetForm();
111
+ } catch (e) {
112
+ } finally {
113
+ saving = false;
114
+ }
115
+ }
116
+
117
+ async function remove(acct: EmailAccountData) {
118
+ if (isReadonly || !ondelete) return;
119
+ try {
120
+ await ondelete(acct);
121
+ if (editingId === acct.id) resetForm();
122
+ } catch (e) {}
123
+ }
124
+
125
+ async function testConnection(acct: EmailAccountData) {
126
+ if (!ontest) return;
127
+ try {
128
+ testingId = acct.id;
129
+ testResult = null;
130
+ testResult = await ontest(acct);
131
+ } catch (e) {
132
+ testResult = {
133
+ success: false,
134
+ error: e instanceof Error ? e.message : String(e),
135
+ };
136
+ } finally {
137
+ testingId = null;
138
+ }
139
+ }
140
+
141
+ function getProviderLabel(type: string): string {
142
+ switch (type) {
143
+ case 'imap':
144
+ return 'IMAP';
145
+ case 'exchange':
146
+ return 'Exchange';
147
+ case 'gmail':
148
+ return 'Gmail';
149
+ case 'outlook':
150
+ return 'Outlook';
151
+ default:
152
+ return type;
153
+ }
154
+ }
155
+ </script>
156
+
157
+ <div class="email-account-manager">
158
+ <div class="section-header-row">
159
+ <div class="section-description">
160
+ {t(M['messages.email_account_manager.section_description'])}
161
+ </div>
162
+ {#if !isReadonly && onsave}
163
+ <button
164
+ class="add-btn"
165
+ onclick={() => { resetForm(); showForm = true; }}
166
+ >{t(M['messages.email_account_manager.add_account'])}</button>
167
+ {/if}
168
+ </div>
169
+
170
+ {#if showForm}
171
+ <div class="entry-form">
172
+ <div class="form-title">{editingId ? 'Edit' : 'Add'} {t(M['messages.email_account_manager.mail_account'])}</div>
173
+
174
+ <div class="form-row">
175
+ <div class="form-field" style="flex: 1;">
176
+ <label class="form-label" for="ea-name">{t(M['messages.email_account_manager.account_name'])}</label>
177
+ <input id="ea-name" class="form-input" type="text" bind:value={maName} placeholder={t(M['messages.email_account_manager.account_name_placeholder'])} />
178
+ </div>
179
+ <div class="form-field" style="flex: 1;">
180
+ <label class="form-label" for="ea-email">{t(M['messages.email_account_manager.email_address'])}</label>
181
+ <input id="ea-email" class="form-input" type="email" bind:value={maEmail} placeholder={t(M['messages.email_account_manager.email_placeholder'])} />
182
+ </div>
183
+ <div class="form-field" style="flex: 0 0 130px;">
184
+ <label class="form-label" for="ea-provider">Provider</label>
185
+ <select id="ea-provider" class="form-select" bind:value={maProviderType}>
186
+ <option value="imap">IMAP</option>
187
+ <option value="gmail">Gmail</option>
188
+ <option value="outlook">Outlook</option>
189
+ <option value="exchange">Exchange</option>
190
+ </select>
191
+ </div>
192
+ </div>
193
+
194
+ <div class="form-section-label">{t(M['messages.email_account_manager.incoming_mail'])}</div>
195
+ <div class="form-row">
196
+ <div class="form-field" style="flex: 2;">
197
+ <label class="form-label" for="ea-imap-host">Host</label>
198
+ <input id="ea-imap-host" class="form-input" type="text" bind:value={maImapHost} placeholder={t(M['messages.email_account_manager.imap_host_placeholder'])} />
199
+ </div>
200
+ <div class="form-field" style="flex: 0 0 90px;">
201
+ <label class="form-label" for="ea-imap-port">Port</label>
202
+ <input id="ea-imap-port" class="form-input" type="number" bind:value={maImapPort} />
203
+ </div>
204
+ <div class="form-field" style="flex: 0 0 120px;">
205
+ <label class="form-label" for="ea-imap-sec">Security</label>
206
+ <select id="ea-imap-sec" class="form-select" bind:value={maImapSecurity}>
207
+ <option value="ssl">SSL/TLS</option>
208
+ <option value="starttls">STARTTLS</option>
209
+ <option value="none">None</option>
210
+ </select>
211
+ </div>
212
+ </div>
213
+
214
+ <div class="form-section-label">{t(M['messages.email_account_manager.outgoing_mail'])}</div>
215
+ <div class="form-row">
216
+ <div class="form-field" style="flex: 2;">
217
+ <label class="form-label" for="ea-smtp-host">Host</label>
218
+ <input id="ea-smtp-host" class="form-input" type="text" bind:value={maSmtpHost} placeholder={t(M['messages.email_account_manager.smtp_host_placeholder'])} />
219
+ </div>
220
+ <div class="form-field" style="flex: 0 0 90px;">
221
+ <label class="form-label" for="ea-smtp-port">Port</label>
222
+ <input id="ea-smtp-port" class="form-input" type="number" bind:value={maSmtpPort} />
223
+ </div>
224
+ <div class="form-field" style="flex: 0 0 120px;">
225
+ <label class="form-label" for="ea-smtp-sec">Security</label>
226
+ <select id="ea-smtp-sec" class="form-select" bind:value={maSmtpSecurity}>
227
+ <option value="ssl">SSL/TLS</option>
228
+ <option value="starttls">STARTTLS</option>
229
+ <option value="none">None</option>
230
+ </select>
231
+ </div>
232
+ </div>
233
+
234
+ <div class="form-section-label">Credentials</div>
235
+ <div class="form-row">
236
+ <div class="form-field" style="flex: 1;">
237
+ <label class="form-label" for="ea-username">Username</label>
238
+ <input id="ea-username" class="form-input" type="text" bind:value={maUsername} placeholder={t(M['messages.email_account_manager.username_placeholder'])} />
239
+ </div>
240
+ <div class="form-field" style="flex: 1;">
241
+ <label class="form-label" for="ea-password">Password</label>
242
+ <input id="ea-password" class="form-input" type="password" bind:value={maPassword} placeholder={editingId ? '(unchanged)' : ''} />
243
+ </div>
244
+ <div class="form-field checkbox-field">
245
+ <label class="form-label checkbox-label">
246
+ <input type="checkbox" bind:checked={maIsActive} />
247
+ Active
248
+ </label>
249
+ </div>
250
+ </div>
251
+
252
+ <div class="form-actions">
253
+ <button class="cancel-btn" onclick={resetForm} disabled={saving}>Cancel</button>
254
+ <button class="save-btn" onclick={save} disabled={saving || !maName.trim() || !maEmail.trim()}>
255
+ {saving ? 'Saving...' : editingId ? 'Update' : 'Add Account'}
256
+ </button>
257
+ </div>
258
+ </div>
259
+ {/if}
260
+
261
+ {#if testResult}
262
+ <div class="test-result" class:success={testResult.success} class:failure={!testResult.success}>
263
+ {#if testResult.success}
264
+ {t(M['messages.email_account_manager.connection_successful'])}
265
+ {:else}
266
+ {t(M['messages.email_account_manager.connection_failed'])} {testResult.error ?? 'Unknown error'}
267
+ {/if}
268
+ <button class="dismiss-btn" onclick={() => testResult = null}>&times;</button>
269
+ </div>
270
+ {/if}
271
+
272
+ {#if accounts.length === 0 && !showForm}
273
+ <p class="placeholder">{t(M['messages.email_account_manager.empty'])}</p>
274
+ {:else}
275
+ <div class="entries-list">
276
+ {#each accounts as acct}
277
+ <div
278
+ class="entry-card mail-account"
279
+ class:editing={editingId === acct.id}
280
+ class:inactive={!acct.isActive}
281
+ role="button"
282
+ tabindex="0"
283
+ onclick={() => startEdit(acct)}
284
+ onkeydown={(e) => {
285
+ if (e.key === 'Enter' || e.key === ' ') {
286
+ e.preventDefault();
287
+ startEdit(acct);
288
+ }
289
+ }}
290
+ >
291
+ <div class="entry-main">
292
+ <span class="type-badge provider" title={acct.providerType}>{getProviderLabel(acct.providerType)}</span>
293
+ <div class="entry-info">
294
+ <span class="entry-pattern">{acct.name}</span>
295
+ <span class="entry-description">{acct.email}</span>
296
+ </div>
297
+ {#if acct.imapHost}
298
+ <span class="host-tag" title={t(M['messages.email_account_manager.imap_host_title'], { host: acct.imapHost, port: acct.imapPort })}>{acct.imapHost}</span>
299
+ {/if}
300
+ {#if !acct.isActive}
301
+ <span class="inactive-tag">inactive</span>
302
+ {/if}
303
+ </div>
304
+ {#if !isReadonly}
305
+ <div class="entry-actions">
306
+ {#if ontest}
307
+ <button
308
+ class="test-btn"
309
+ onclick={(e) => { e.stopPropagation(); testConnection(acct); }}
310
+ disabled={testingId === acct.id}
311
+ title={t(M['messages.email_account_manager.test_connection'])}
312
+ >
313
+ {testingId === acct.id ? '...' : 'Test'}
314
+ </button>
315
+ {/if}
316
+ {#if ondelete}
317
+ <button
318
+ class="delete-btn"
319
+ onclick={(e) => { e.stopPropagation(); remove(acct); }}
320
+ title={t(M['messages.email_account_manager.remove'])}
321
+ >&times;</button>
322
+ {/if}
323
+ </div>
324
+ {/if}
325
+ </div>
326
+ {/each}
327
+ </div>
328
+ {/if}
329
+ </div>
330
+
331
+ <style>
332
+ .email-account-manager {
333
+ display: flex;
334
+ flex-direction: column;
335
+ gap: 0.75rem;
336
+ }
337
+
338
+ .section-header-row {
339
+ display: flex;
340
+ align-items: center;
341
+ justify-content: space-between;
342
+ gap: 1rem;
343
+ }
344
+
345
+ .section-description {
346
+ font-size: var(--smrt-typography-body-medium-size, 0.8125rem);
347
+ color: var(--smrt-color-on-surface-variant, #43474e);
348
+ }
349
+
350
+ .add-btn {
351
+ padding: 0.375rem 0.75rem;
352
+ border-radius: var(--smrt-radius-md, 8px);
353
+ border: 1px solid var(--smrt-color-primary, #005ac1);
354
+ background: transparent;
355
+ color: var(--smrt-color-primary, #005ac1);
356
+ cursor: pointer;
357
+ font-size: var(--smrt-typography-label-large-size, 0.8125rem);
358
+ font-family: inherit;
359
+ font-weight: var(--smrt-typography-weight-medium, 500);
360
+ transition: all 150ms ease;
361
+ flex-shrink: 0;
362
+ }
363
+
364
+ .add-btn:hover {
365
+ background: var(--smrt-color-primary, #005ac1);
366
+ color: var(--smrt-color-on-primary, #fff);
367
+ }
368
+
369
+ .entry-form {
370
+ background: var(--smrt-color-surface-container, #f0f1f9);
371
+ border: 1px solid var(--smrt-color-primary, #005ac1);
372
+ border-radius: var(--smrt-radius-md, 8px);
373
+ padding: 1rem;
374
+ display: flex;
375
+ flex-direction: column;
376
+ gap: 0.75rem;
377
+ }
378
+
379
+ .form-title {
380
+ font-size: var(--smrt-typography-title-small-size, 0.875rem);
381
+ font-weight: var(--smrt-typography-weight-semibold, 600);
382
+ color: var(--smrt-color-primary, #005ac1);
383
+ }
384
+
385
+ .form-section-label {
386
+ font-size: var(--smrt-typography-label-medium-size, 0.75rem);
387
+ font-weight: var(--smrt-typography-weight-semibold, 600);
388
+ color: var(--smrt-color-on-surface-variant, #43474e);
389
+ text-transform: uppercase;
390
+ letter-spacing: var(--smrt-typography-label-medium-tracking, 0.05em);
391
+ padding-top: 0.25rem;
392
+ }
393
+
394
+ .form-row {
395
+ display: flex;
396
+ gap: 0.75rem;
397
+ align-items: flex-end;
398
+ }
399
+
400
+ .form-field {
401
+ display: flex;
402
+ flex-direction: column;
403
+ gap: 0.25rem;
404
+ }
405
+
406
+ .form-label {
407
+ font-size: var(--smrt-typography-label-medium-size, 0.75rem);
408
+ font-weight: var(--smrt-typography-weight-medium, 500);
409
+ color: var(--smrt-color-on-surface-variant, #43474e);
410
+ }
411
+
412
+ .form-input,
413
+ .form-select {
414
+ padding: 0.5rem 0.625rem;
415
+ border-radius: var(--smrt-radius-md, 8px);
416
+ border: 1px solid var(--smrt-color-outline-variant, #c2c7cf);
417
+ background: var(--smrt-color-surface, #fefbff);
418
+ color: var(--smrt-color-on-surface, #1a1c1e);
419
+ font-size: var(--smrt-typography-body-medium-size, 0.8125rem);
420
+ font-family: inherit;
421
+ transition: border-color 150ms ease;
422
+ }
423
+
424
+ .form-input:focus,
425
+ .form-select:focus {
426
+ outline: none;
427
+ border-color: var(--smrt-color-primary, #005ac1);
428
+ }
429
+
430
+ .form-input::placeholder {
431
+ color: var(--smrt-color-on-surface-variant, #43474e);
432
+ opacity: 0.5;
433
+ }
434
+
435
+ .checkbox-field {
436
+ justify-content: flex-end;
437
+ padding-bottom: 0.5rem;
438
+ }
439
+
440
+ .checkbox-label {
441
+ display: flex;
442
+ align-items: center;
443
+ gap: 0.5rem;
444
+ cursor: pointer;
445
+ font-size: var(--smrt-typography-body-medium-size, 0.8125rem);
446
+ color: var(--smrt-color-on-surface, #1a1c1e);
447
+ white-space: nowrap;
448
+ }
449
+
450
+ .checkbox-label input[type="checkbox"] {
451
+ accent-color: var(--smrt-color-primary, #005ac1);
452
+ }
453
+
454
+ .form-actions {
455
+ display: flex;
456
+ justify-content: flex-end;
457
+ gap: 0.5rem;
458
+ padding-top: 0.25rem;
459
+ }
460
+
461
+ .cancel-btn {
462
+ padding: 0.375rem 0.75rem;
463
+ border-radius: var(--smrt-radius-md, 8px);
464
+ border: 1px solid var(--smrt-color-outline-variant, #c2c7cf);
465
+ background: transparent;
466
+ color: var(--smrt-color-on-surface-variant, #43474e);
467
+ cursor: pointer;
468
+ font-size: var(--smrt-typography-label-large-size, 0.8125rem);
469
+ font-family: inherit;
470
+ transition: all 150ms ease;
471
+ }
472
+
473
+ .cancel-btn:hover {
474
+ background: var(--smrt-color-surface-container-high, #e6e7ef);
475
+ }
476
+
477
+ .save-btn {
478
+ padding: 0.375rem 0.75rem;
479
+ border-radius: var(--smrt-radius-md, 8px);
480
+ border: 1px solid var(--smrt-color-primary, #005ac1);
481
+ background: var(--smrt-color-primary, #005ac1);
482
+ color: var(--smrt-color-on-primary, #fff);
483
+ cursor: pointer;
484
+ font-size: var(--smrt-typography-label-large-size, 0.8125rem);
485
+ font-family: inherit;
486
+ font-weight: var(--smrt-typography-weight-medium, 500);
487
+ transition: all 150ms ease;
488
+ }
489
+
490
+ .save-btn:hover:not(:disabled) {
491
+ opacity: 0.9;
492
+ }
493
+
494
+ .save-btn:disabled {
495
+ opacity: 0.5;
496
+ cursor: not-allowed;
497
+ }
498
+
499
+ .test-result {
500
+ padding: 0.5rem 0.75rem;
501
+ border-radius: var(--smrt-radius-md, 8px);
502
+ font-size: var(--smrt-typography-body-medium-size, 0.8125rem);
503
+ display: flex;
504
+ align-items: center;
505
+ justify-content: space-between;
506
+ }
507
+
508
+ .test-result.success {
509
+ background: var(--smrt-color-success-container, #dcfce7);
510
+ color: var(--smrt-color-success, #16a34a);
511
+ }
512
+
513
+ .test-result.failure {
514
+ background: var(--smrt-color-error-container, #fce4ec);
515
+ color: var(--smrt-color-error, #ba1a1a);
516
+ }
517
+
518
+ .dismiss-btn {
519
+ background: transparent;
520
+ border: none;
521
+ font-size: var(--smrt-typography-body-large-size, 1rem);
522
+ cursor: pointer;
523
+ color: inherit;
524
+ padding: 0 0.25rem;
525
+ }
526
+
527
+ .entries-list {
528
+ display: flex;
529
+ flex-direction: column;
530
+ gap: 0.5rem;
531
+ }
532
+
533
+ .entry-card {
534
+ display: flex;
535
+ align-items: center;
536
+ justify-content: space-between;
537
+ background: var(--smrt-color-surface-container, #f0f1f9);
538
+ border: 1px solid var(--smrt-color-outline-variant, #c2c7cf);
539
+ border-radius: var(--smrt-radius-md, 8px);
540
+ padding: 0.75rem 1rem;
541
+ cursor: pointer;
542
+ transition: background 150ms ease, border-color 150ms ease;
543
+ }
544
+
545
+ .entry-card:hover {
546
+ background: var(--smrt-color-surface-container-high, #e6e7ef);
547
+ }
548
+
549
+ .entry-card.mail-account:hover {
550
+ border-color: var(--smrt-color-primary, #005ac1);
551
+ }
552
+
553
+ .entry-card.editing {
554
+ border-color: var(--smrt-color-primary, #005ac1);
555
+ background: var(--smrt-color-surface-container-high, #e6e7ef);
556
+ }
557
+
558
+ .entry-card.inactive {
559
+ opacity: 0.5;
560
+ }
561
+
562
+ .entry-main {
563
+ display: flex;
564
+ align-items: center;
565
+ gap: 0.75rem;
566
+ flex: 1;
567
+ min-width: 0;
568
+ }
569
+
570
+ .entry-actions {
571
+ display: flex;
572
+ align-items: center;
573
+ gap: 0.375rem;
574
+ flex-shrink: 0;
575
+ }
576
+
577
+ .type-badge {
578
+ font-size: var(--smrt-typography-label-small-size, 0.6875rem);
579
+ font-weight: var(--smrt-typography-weight-semibold, 600);
580
+ font-family: var(--smrt-font-family-mono, monospace);
581
+ background: var(--smrt-color-surface, #fefbff);
582
+ border: 1px solid var(--smrt-color-outline-variant, #c2c7cf);
583
+ padding: 0.25rem 0.5rem;
584
+ border-radius: var(--smrt-radius-sm, 4px);
585
+ flex-shrink: 0;
586
+ min-width: 2rem;
587
+ text-align: center;
588
+ }
589
+
590
+ .type-badge.provider {
591
+ font-family: inherit;
592
+ font-size: var(--smrt-typography-label-small-size, 0.625rem);
593
+ text-transform: uppercase;
594
+ letter-spacing: var(--smrt-typography-label-small-tracking, 0.05em);
595
+ background: var(--smrt-color-primary-container, #d8e2ff);
596
+ color: var(--smrt-color-primary, #005ac1);
597
+ border-color: transparent;
598
+ min-width: 3rem;
599
+ }
600
+
601
+ .entry-info {
602
+ display: flex;
603
+ flex-direction: column;
604
+ gap: 0.125rem;
605
+ flex: 1;
606
+ min-width: 0;
607
+ }
608
+
609
+ .entry-pattern {
610
+ font-weight: var(--smrt-typography-weight-medium, 500);
611
+ font-size: var(--smrt-typography-title-small-size, 0.875rem);
612
+ overflow: hidden;
613
+ text-overflow: ellipsis;
614
+ white-space: nowrap;
615
+ }
616
+
617
+ .entry-description {
618
+ font-size: var(--smrt-typography-body-small-size, 0.75rem);
619
+ color: var(--smrt-color-on-surface-variant, #43474e);
620
+ }
621
+
622
+ .host-tag {
623
+ font-size: var(--smrt-typography-label-small-size, 0.6875rem);
624
+ font-family: var(--smrt-font-family-mono, monospace);
625
+ color: var(--smrt-color-on-surface-variant, #43474e);
626
+ background: var(--smrt-color-surface, #fefbff);
627
+ padding: 0.125rem 0.5rem;
628
+ border-radius: var(--smrt-radius-sm, 4px);
629
+ flex-shrink: 0;
630
+ }
631
+
632
+ .inactive-tag {
633
+ font-size: var(--smrt-typography-label-small-size, 0.6875rem);
634
+ color: var(--smrt-color-on-surface-variant, #43474e);
635
+ background: var(--smrt-color-surface-container-high, #e6e7ef);
636
+ padding: 0.125rem 0.5rem;
637
+ border-radius: var(--smrt-radius-full, 9999px);
638
+ flex-shrink: 0;
639
+ }
640
+
641
+ .test-btn {
642
+ padding: 0.25rem 0.5rem;
643
+ border-radius: var(--smrt-radius-sm, 4px);
644
+ border: 1px solid var(--smrt-color-outline-variant, #c2c7cf);
645
+ background: transparent;
646
+ color: var(--smrt-color-on-surface-variant, #43474e);
647
+ cursor: pointer;
648
+ font-size: var(--smrt-typography-label-small-size, 0.6875rem);
649
+ font-family: inherit;
650
+ transition: all 150ms ease;
651
+ }
652
+
653
+ .test-btn:hover:not(:disabled) {
654
+ border-color: var(--smrt-color-primary, #005ac1);
655
+ color: var(--smrt-color-primary, #005ac1);
656
+ }
657
+
658
+ .test-btn:disabled {
659
+ opacity: 0.5;
660
+ cursor: not-allowed;
661
+ }
662
+
663
+ .delete-btn {
664
+ font-size: var(--smrt-typography-body-large-size, 1rem);
665
+ line-height: 1;
666
+ padding: 0.125rem 0.5rem;
667
+ border-radius: var(--smrt-radius-full, 9999px);
668
+ border: 1px solid transparent;
669
+ background: transparent;
670
+ color: var(--smrt-color-on-surface-variant, #43474e);
671
+ cursor: pointer;
672
+ font-family: inherit;
673
+ transition: all 150ms ease;
674
+ flex-shrink: 0;
675
+ }
676
+
677
+ .delete-btn:hover {
678
+ background: var(--smrt-color-error-container, #fce4ec);
679
+ color: var(--smrt-color-error, #ba1a1a);
680
+ border-color: var(--smrt-color-error, #ba1a1a);
681
+ }
682
+
683
+ .placeholder {
684
+ padding: 2rem;
685
+ text-align: center;
686
+ color: var(--smrt-color-on-surface-variant, #43474e);
687
+ background: var(--smrt-color-surface-container, #f0f1f9);
688
+ border-radius: var(--smrt-radius-md, 8px);
689
+ }
690
+ </style>
@@ -0,0 +1,15 @@
1
+ import type { EmailAccountData } from '../types.js';
2
+ export interface Props {
3
+ accounts: EmailAccountData[];
4
+ readonly?: boolean;
5
+ onsave?: (data: Partial<EmailAccountData>, id?: string) => Promise<void>;
6
+ ondelete?: (account: EmailAccountData) => Promise<void>;
7
+ ontest?: (account: EmailAccountData) => Promise<{
8
+ success: boolean;
9
+ error?: string;
10
+ }>;
11
+ }
12
+ declare const EmailAccountManager: import("svelte").Component<Props, {}, "">;
13
+ type EmailAccountManager = ReturnType<typeof EmailAccountManager>;
14
+ export default EmailAccountManager;
15
+ //# sourceMappingURL=EmailAccountManager.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmailAccountManager.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/EmailAccountManager.svelte.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGpD,MAAM,WAAW,KAAK;IACpB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,gBAAgB,CAAC,EAAE,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,MAAM,CAAC,EAAE,CACP,OAAO,EAAE,gBAAgB,KACtB,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD;AA6SD,QAAA,MAAM,mBAAmB,2CAAwC,CAAC;AAClE,KAAK,mBAAmB,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAClE,eAAe,mBAAmB,CAAC"}