@joewinke/jatui 0.1.10 → 0.1.19

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 (91) hide show
  1. package/README.md +123 -0
  2. package/package.json +3 -1
  3. package/src/lib/actions/railNav.ts +473 -0
  4. package/src/lib/components/AnnotationLayer.svelte +108 -0
  5. package/src/lib/components/AnnotationPanel.svelte +319 -0
  6. package/src/lib/components/AudioWaveform.svelte +9 -5
  7. package/src/lib/components/AvailabilityModal.svelte +7 -3
  8. package/src/lib/components/AvatarUpload.svelte +27 -4
  9. package/src/lib/components/BookingForm.svelte +11 -9
  10. package/src/lib/components/BurndownChart.svelte +778 -0
  11. package/src/lib/components/Button.svelte +10 -1
  12. package/src/lib/components/CalendarPicker.svelte +3 -3
  13. package/src/lib/components/Card.svelte +2 -2
  14. package/src/lib/components/ChipInput.svelte +21 -15
  15. package/src/lib/components/ColorSelector.svelte +17 -13
  16. package/src/lib/components/CommentThread.svelte +773 -0
  17. package/src/lib/components/ConfirmDialog.svelte +348 -0
  18. package/src/lib/components/ConfirmModal.svelte +78 -11
  19. package/src/lib/components/ContextMenu.svelte +188 -0
  20. package/src/lib/components/CountdownTimer.svelte +1 -1
  21. package/src/lib/components/DateRangePicker.svelte +6 -4
  22. package/src/lib/components/Drawer.svelte +36 -3
  23. package/src/lib/components/EntityPreviewCard.svelte +104 -0
  24. package/src/lib/components/FileDropzone.svelte +493 -0
  25. package/src/lib/components/FilePicker.svelte +83 -14
  26. package/src/lib/components/FileThumbnail.svelte +80 -0
  27. package/src/lib/components/FilterDropdown.svelte +11 -11
  28. package/src/lib/components/HunkDiffView.svelte +348 -0
  29. package/src/lib/components/ImageLightbox.svelte +274 -0
  30. package/src/lib/components/ImageUpload.svelte +58 -9
  31. package/src/lib/components/InlineEdit.svelte +15 -9
  32. package/src/lib/components/InputDialog.svelte +327 -0
  33. package/src/lib/components/LazyImage.svelte +1 -0
  34. package/src/lib/components/LinkShortener.svelte +1 -1
  35. package/src/lib/components/LoadingSpinner.svelte +6 -2
  36. package/src/lib/components/MarkupEditor.svelte +485 -0
  37. package/src/lib/components/MarkupOverlay.svelte +55 -0
  38. package/src/lib/components/MediaWorkbench.svelte +871 -0
  39. package/src/lib/components/MilestoneCard.svelte +1 -1
  40. package/src/lib/components/MilestoneTimeline.svelte +1 -1
  41. package/src/lib/components/Modal.svelte +39 -4
  42. package/src/lib/components/PDFViewer.svelte +105 -0
  43. package/src/lib/components/PdfThumbnail.svelte +3 -1
  44. package/src/lib/components/PhoneInput.svelte +183 -63
  45. package/src/lib/components/ResizablePanel.svelte +4 -4
  46. package/src/lib/components/SearchDropdown.svelte +26 -13
  47. package/src/lib/components/SelectInput.svelte +26 -4
  48. package/src/lib/components/SidebarUserFooter.svelte +1 -1
  49. package/src/lib/components/SignaturePad.svelte +8 -4
  50. package/src/lib/components/SmartImageEditor.svelte +720 -0
  51. package/src/lib/components/SortDropdown.svelte +9 -3
  52. package/src/lib/components/Sparkline.svelte +9 -0
  53. package/src/lib/components/StatusBadge.svelte +20 -18
  54. package/src/lib/components/TextArea.svelte +24 -5
  55. package/src/lib/components/TextInput.svelte +29 -6
  56. package/src/lib/components/ThemeSelector.svelte +15 -4
  57. package/src/lib/components/TimeSlotPicker.svelte +7 -7
  58. package/src/lib/components/UserAvatar.svelte +14 -1
  59. package/src/lib/components/VariablePicker.svelte +170 -0
  60. package/src/lib/components/VoicePlayer.svelte +4 -3
  61. package/src/lib/components/markup.ts +287 -0
  62. package/src/lib/components/messaging/ChannelInfoModal.svelte +9 -9
  63. package/src/lib/components/messaging/ChannelList.svelte +1 -1
  64. package/src/lib/components/messaging/ChannelMembersModal.svelte +1 -1
  65. package/src/lib/components/messaging/CreateChannelModal.svelte +1 -1
  66. package/src/lib/components/messaging/DirectMessageList.svelte +1 -1
  67. package/src/lib/components/messaging/EmojiSelector.svelte +2 -1
  68. package/src/lib/components/messaging/MentionAutocomplete.svelte +1 -1
  69. package/src/lib/components/messaging/MessageAttachment.svelte +3 -3
  70. package/src/lib/components/messaging/MessageAttachmentUpload.svelte +3 -3
  71. package/src/lib/components/messaging/MessageInput.svelte +1 -1
  72. package/src/lib/components/messaging/MessageItem.svelte +6 -3
  73. package/src/lib/components/messaging/NotificationSettingsModal.svelte +1 -1
  74. package/src/lib/components/messaging/QuotedMessageDisplay.svelte +6 -1
  75. package/src/lib/components/messaging/StartDMModal.svelte +1 -1
  76. package/src/lib/components/pipeline/Pipeline.svelte +4 -4
  77. package/src/lib/components/pipeline/PipelineCard.svelte +1 -1
  78. package/src/lib/components/pipeline/PipelineColumn.svelte +8 -3
  79. package/src/lib/index.ts +105 -1
  80. package/src/lib/stores/confirmDialog.svelte.ts +48 -0
  81. package/src/lib/stores/inputDialog.svelte.ts +51 -0
  82. package/src/lib/styles/rail.css +63 -0
  83. package/src/lib/types/annotation.ts +38 -0
  84. package/src/lib/types/comments.ts +97 -0
  85. package/src/lib/types/entityPreview.ts +45 -0
  86. package/src/lib/types/filePicker.ts +2 -0
  87. package/src/lib/types/smartImageEditor.ts +39 -0
  88. package/src/lib/types/templateVars.ts +36 -0
  89. package/src/lib/utils/dateFormatters.ts +12 -10
  90. package/src/lib/utils/phone.ts +80 -0
  91. package/src/lib/utils/taskUtils.ts +21 -7
@@ -24,9 +24,11 @@ export function normalizeTimestamp(timestamp: string): string {
24
24
 
25
25
  /**
26
26
  * Parse a potentially non-standard timestamp into a Date object.
27
+ * Accepts a Date (returned by postgres.js), ISO string, or null/undefined.
27
28
  */
28
- export function parseTimestamp(timestamp: string | null | undefined): Date | null {
29
+ export function parseTimestamp(timestamp: Date | string | null | undefined): Date | null {
29
30
  if (!timestamp) return null;
31
+ if (timestamp instanceof Date) return isNaN(timestamp.getTime()) ? null : timestamp;
30
32
 
31
33
  const normalized = normalizeTimestamp(timestamp);
32
34
  const date = new Date(normalized);
@@ -38,7 +40,7 @@ export function parseTimestamp(timestamp: string | null | undefined): Date | nul
38
40
  * Format relative time (e.g., "2d", "3mo", "1y").
39
41
  * Compact format suitable for tables and compact UIs.
40
42
  */
41
- export function formatRelativeTime(dateStr: string | null | undefined): string {
43
+ export function formatRelativeTime(dateStr: Date | string | null | undefined): string {
42
44
  if (!dateStr) return '-';
43
45
 
44
46
  const date = parseTimestamp(dateStr);
@@ -65,7 +67,7 @@ export function formatRelativeTime(dateStr: string | null | undefined): string {
65
67
  /**
66
68
  * Format full date and time for tooltips and detailed views.
67
69
  */
68
- export function formatFullDate(dateStr: string | null | undefined): string {
70
+ export function formatFullDate(dateStr: Date | string | null | undefined): string {
69
71
  if (!dateStr) return '';
70
72
 
71
73
  const date = parseTimestamp(dateStr);
@@ -83,7 +85,7 @@ export function formatFullDate(dateStr: string | null | undefined): string {
83
85
  /**
84
86
  * Format short date for compact displays (e.g., date range picker).
85
87
  */
86
- export function formatShortDate(dateStr: string | null | undefined): string {
88
+ export function formatShortDate(dateStr: Date | string | null | undefined): string {
87
89
  if (!dateStr) return '';
88
90
 
89
91
  const date = parseTimestamp(dateStr);
@@ -96,7 +98,7 @@ export function formatShortDate(dateStr: string | null | undefined): string {
96
98
  * Format last activity time for agent cards.
97
99
  * Shows "Just now", "Xm ago", "Xh ago", or "Xd ago".
98
100
  */
99
- export function formatLastActivity(timestamp: string | null | undefined): string {
101
+ export function formatLastActivity(timestamp: Date | string | null | undefined): string {
100
102
  if (!timestamp) return 'Never';
101
103
 
102
104
  const date = parseTimestamp(timestamp);
@@ -117,7 +119,7 @@ export function formatLastActivity(timestamp: string | null | undefined): string
117
119
  /**
118
120
  * Format date for display (simple locale string).
119
121
  */
120
- export function formatDate(dateString: string | null | undefined): string {
122
+ export function formatDate(dateString: Date | string | null | undefined): string {
121
123
  if (!dateString) return 'N/A';
122
124
 
123
125
  const date = parseTimestamp(dateString);
@@ -129,7 +131,7 @@ export function formatDate(dateString: string | null | undefined): string {
129
131
  /**
130
132
  * Get milliseconds since timestamp (for calculations).
131
133
  */
132
- export function getTimeSinceMs(timestamp: string | null | undefined): number {
134
+ export function getTimeSinceMs(timestamp: Date | string | null | undefined): number {
133
135
  if (!timestamp) return Infinity;
134
136
 
135
137
  const date = parseTimestamp(timestamp);
@@ -141,14 +143,14 @@ export function getTimeSinceMs(timestamp: string | null | undefined): number {
141
143
  /**
142
144
  * Get minutes since timestamp.
143
145
  */
144
- export function getTimeSinceMinutes(timestamp: string | null | undefined): number {
146
+ export function getTimeSinceMinutes(timestamp: Date | string | null | undefined): number {
145
147
  return getTimeSinceMs(timestamp) / 60000;
146
148
  }
147
149
 
148
150
  /**
149
151
  * Check if timestamp is within a given number of minutes.
150
152
  */
151
- export function isWithinMinutes(timestamp: string | null | undefined, minutes: number): boolean {
153
+ export function isWithinMinutes(timestamp: Date | string | null | undefined, minutes: number): boolean {
152
154
  return getTimeSinceMinutes(timestamp) < minutes;
153
155
  }
154
156
 
@@ -156,7 +158,7 @@ export function isWithinMinutes(timestamp: string | null | undefined, minutes: n
156
158
  * Format date + time for detail views (e.g. "Jan 5, 2:30 PM").
157
159
  * No year — use formatFullDate when year is needed.
158
160
  */
159
- export function formatDateTime(dateStr: string | null | undefined): string {
161
+ export function formatDateTime(dateStr: Date | string | null | undefined): string {
160
162
  if (!dateStr) return '';
161
163
  const date = parseTimestamp(dateStr);
162
164
  if (!date) return '';
@@ -0,0 +1,80 @@
1
+ import {
2
+ parsePhoneNumberFromString,
3
+ type CountryCode,
4
+ getCountries,
5
+ getCountryCallingCode,
6
+ } from "libphonenumber-js";
7
+
8
+ export const DEFAULT_COUNTRY: CountryCode = "US";
9
+
10
+ export function toE164(
11
+ raw: string | null | undefined,
12
+ defaultCountry: CountryCode = DEFAULT_COUNTRY,
13
+ ): string | null {
14
+ if (!raw) return null;
15
+ const trimmed = raw.trim();
16
+ if (!trimmed) return null;
17
+ const parsed = parsePhoneNumberFromString(trimmed, defaultCountry);
18
+ if (parsed?.isValid()) return parsed.number;
19
+ return null;
20
+ }
21
+
22
+ export function formatPhoneForDisplay(e164: string | null | undefined): string {
23
+ if (!e164) return "";
24
+ const parsed = parsePhoneNumberFromString(e164);
25
+ if (!parsed) return e164;
26
+ return parsed.country === DEFAULT_COUNTRY ? parsed.formatNational() : parsed.formatInternational();
27
+ }
28
+
29
+ export function isValidPhone(
30
+ raw: string | null | undefined,
31
+ defaultCountry: CountryCode = DEFAULT_COUNTRY,
32
+ ): boolean {
33
+ if (!raw) return false;
34
+ const parsed = parsePhoneNumberFromString(raw.trim(), defaultCountry);
35
+ return parsed?.isValid() ?? false;
36
+ }
37
+
38
+ export type CountryOption = {
39
+ code: CountryCode;
40
+ name: string;
41
+ dialCode: string;
42
+ flag: string;
43
+ };
44
+
45
+ const COUNTRY_NAMES: Record<string, string> = {
46
+ US: "United States", CA: "Canada", GB: "United Kingdom", AU: "Australia", NZ: "New Zealand",
47
+ IE: "Ireland", DE: "Germany", FR: "France", ES: "Spain", IT: "Italy", NL: "Netherlands",
48
+ BE: "Belgium", CH: "Switzerland", AT: "Austria", SE: "Sweden", NO: "Norway", DK: "Denmark",
49
+ FI: "Finland", PT: "Portugal", PL: "Poland", CZ: "Czechia", GR: "Greece", MX: "Mexico",
50
+ BR: "Brazil", AR: "Argentina", CL: "Chile", CO: "Colombia", PE: "Peru", JP: "Japan",
51
+ KR: "South Korea", CN: "China", HK: "Hong Kong", TW: "Taiwan", SG: "Singapore", MY: "Malaysia",
52
+ TH: "Thailand", PH: "Philippines", ID: "Indonesia", VN: "Vietnam", IN: "India", PK: "Pakistan",
53
+ BD: "Bangladesh", IL: "Israel", AE: "UAE", SA: "Saudi Arabia", TR: "Turkey", EG: "Egypt",
54
+ ZA: "South Africa", NG: "Nigeria", KE: "Kenya", RU: "Russia", UA: "Ukraine",
55
+ };
56
+
57
+ function flagEmoji(code: string): string {
58
+ return code
59
+ .toUpperCase()
60
+ .split("")
61
+ .map((c) => String.fromCodePoint(127397 + c.charCodeAt(0)))
62
+ .join("");
63
+ }
64
+
65
+ let countriesCache: CountryOption[] | null = null;
66
+ export function listCountries(): CountryOption[] {
67
+ if (countriesCache) return countriesCache;
68
+ const all = getCountries()
69
+ .map((code) => ({
70
+ code,
71
+ name: COUNTRY_NAMES[code] ?? code,
72
+ dialCode: `+${getCountryCallingCode(code)}`,
73
+ flag: flagEmoji(code),
74
+ }))
75
+ .sort((a, b) => a.name.localeCompare(b.name));
76
+ countriesCache = all;
77
+ return all;
78
+ }
79
+
80
+ export const PRIORITY_COUNTRIES: CountryCode[] = ["US", "CA", "GB", "AU", "MX"];
@@ -6,17 +6,31 @@
6
6
  /**
7
7
  * DaisyUI badge class for a task status value.
8
8
  * Usage: <span class="badge {statusColor(task.status)}">...</span>
9
+ *
10
+ * Aligned to the canonical JAT TASK_STATUS palette
11
+ * (jat/ide/src/lib/config/statusColors.ts → TASK_STATUS_VISUALS) and the
12
+ * committed JST portal palette (jst/src/lib/components/portal/portalStatus.ts
13
+ * → TASK_BADGE) so a task renders the same semantics in JAT-style admin
14
+ * surfaces, the JST portal, and the JAT IDE:
15
+ * open=ghost(neutral) · in_progress=info(blue) · blocked=warning(amber) ·
16
+ * closed=success(green). Paused / mid-flight states (waiting, review) and
17
+ * post-completion states (submitted, accepted, deployed) use the outline
18
+ * variants JAT applies. Where JAT and JST agree (open/in_progress/closed/
19
+ * waiting), this matches both; JAT's statusColors.ts is canonical otherwise.
9
20
  */
10
21
  export function statusColor(status: string): string {
11
22
  switch (status) {
12
23
  case 'open': return 'badge-ghost';
13
- case 'in_progress': return 'badge-warning';
14
- case 'waiting': return 'badge-warning badge-outline';
15
- case 'blocked': return 'badge-error badge-outline';
16
- case 'submitted': return 'badge-info';
17
- case 'accepted': return 'badge-success';
18
- case 'deployed': return 'badge-success badge-outline';
19
- case 'closed': return 'badge-neutral';
24
+ case 'in_progress': return 'badge-info';
25
+ case 'waiting': return 'badge-info badge-outline';
26
+ case 'review': return 'badge-info badge-outline';
27
+ case 'blocked': return 'badge-warning';
28
+ case 'submitted': return 'badge-secondary badge-outline';
29
+ case 'accepted': return 'badge-success badge-outline';
30
+ case 'deployed': return 'badge-primary badge-outline';
31
+ case 'rejected': return 'badge-warning badge-outline';
32
+ case 'reopened': return 'badge-warning badge-outline';
33
+ case 'closed': return 'badge-success';
20
34
  case 'dev': return 'badge-ghost badge-outline';
21
35
  default: return 'badge-ghost';
22
36
  }