@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.
- package/README.md +123 -0
- package/package.json +3 -1
- package/src/lib/actions/railNav.ts +473 -0
- package/src/lib/components/AnnotationLayer.svelte +108 -0
- package/src/lib/components/AnnotationPanel.svelte +319 -0
- package/src/lib/components/AudioWaveform.svelte +9 -5
- package/src/lib/components/AvailabilityModal.svelte +7 -3
- package/src/lib/components/AvatarUpload.svelte +27 -4
- package/src/lib/components/BookingForm.svelte +11 -9
- package/src/lib/components/BurndownChart.svelte +778 -0
- package/src/lib/components/Button.svelte +10 -1
- package/src/lib/components/CalendarPicker.svelte +3 -3
- package/src/lib/components/Card.svelte +2 -2
- package/src/lib/components/ChipInput.svelte +21 -15
- package/src/lib/components/ColorSelector.svelte +17 -13
- package/src/lib/components/CommentThread.svelte +773 -0
- package/src/lib/components/ConfirmDialog.svelte +348 -0
- package/src/lib/components/ConfirmModal.svelte +78 -11
- package/src/lib/components/ContextMenu.svelte +188 -0
- package/src/lib/components/CountdownTimer.svelte +1 -1
- package/src/lib/components/DateRangePicker.svelte +6 -4
- package/src/lib/components/Drawer.svelte +36 -3
- package/src/lib/components/EntityPreviewCard.svelte +104 -0
- package/src/lib/components/FileDropzone.svelte +493 -0
- package/src/lib/components/FilePicker.svelte +83 -14
- package/src/lib/components/FileThumbnail.svelte +80 -0
- package/src/lib/components/FilterDropdown.svelte +11 -11
- package/src/lib/components/HunkDiffView.svelte +348 -0
- package/src/lib/components/ImageLightbox.svelte +274 -0
- package/src/lib/components/ImageUpload.svelte +58 -9
- package/src/lib/components/InlineEdit.svelte +15 -9
- package/src/lib/components/InputDialog.svelte +327 -0
- package/src/lib/components/LazyImage.svelte +1 -0
- package/src/lib/components/LinkShortener.svelte +1 -1
- package/src/lib/components/LoadingSpinner.svelte +6 -2
- package/src/lib/components/MarkupEditor.svelte +485 -0
- package/src/lib/components/MarkupOverlay.svelte +55 -0
- package/src/lib/components/MediaWorkbench.svelte +871 -0
- package/src/lib/components/MilestoneCard.svelte +1 -1
- package/src/lib/components/MilestoneTimeline.svelte +1 -1
- package/src/lib/components/Modal.svelte +39 -4
- package/src/lib/components/PDFViewer.svelte +105 -0
- package/src/lib/components/PdfThumbnail.svelte +3 -1
- package/src/lib/components/PhoneInput.svelte +183 -63
- package/src/lib/components/ResizablePanel.svelte +4 -4
- package/src/lib/components/SearchDropdown.svelte +26 -13
- package/src/lib/components/SelectInput.svelte +26 -4
- package/src/lib/components/SidebarUserFooter.svelte +1 -1
- package/src/lib/components/SignaturePad.svelte +8 -4
- package/src/lib/components/SmartImageEditor.svelte +720 -0
- package/src/lib/components/SortDropdown.svelte +9 -3
- package/src/lib/components/Sparkline.svelte +9 -0
- package/src/lib/components/StatusBadge.svelte +20 -18
- package/src/lib/components/TextArea.svelte +24 -5
- package/src/lib/components/TextInput.svelte +29 -6
- package/src/lib/components/ThemeSelector.svelte +15 -4
- package/src/lib/components/TimeSlotPicker.svelte +7 -7
- package/src/lib/components/UserAvatar.svelte +14 -1
- package/src/lib/components/VariablePicker.svelte +170 -0
- package/src/lib/components/VoicePlayer.svelte +4 -3
- package/src/lib/components/markup.ts +287 -0
- package/src/lib/components/messaging/ChannelInfoModal.svelte +9 -9
- package/src/lib/components/messaging/ChannelList.svelte +1 -1
- package/src/lib/components/messaging/ChannelMembersModal.svelte +1 -1
- package/src/lib/components/messaging/CreateChannelModal.svelte +1 -1
- package/src/lib/components/messaging/DirectMessageList.svelte +1 -1
- package/src/lib/components/messaging/EmojiSelector.svelte +2 -1
- package/src/lib/components/messaging/MentionAutocomplete.svelte +1 -1
- package/src/lib/components/messaging/MessageAttachment.svelte +3 -3
- package/src/lib/components/messaging/MessageAttachmentUpload.svelte +3 -3
- package/src/lib/components/messaging/MessageInput.svelte +1 -1
- package/src/lib/components/messaging/MessageItem.svelte +6 -3
- package/src/lib/components/messaging/NotificationSettingsModal.svelte +1 -1
- package/src/lib/components/messaging/QuotedMessageDisplay.svelte +6 -1
- package/src/lib/components/messaging/StartDMModal.svelte +1 -1
- package/src/lib/components/pipeline/Pipeline.svelte +4 -4
- package/src/lib/components/pipeline/PipelineCard.svelte +1 -1
- package/src/lib/components/pipeline/PipelineColumn.svelte +8 -3
- package/src/lib/index.ts +105 -1
- package/src/lib/stores/confirmDialog.svelte.ts +48 -0
- package/src/lib/stores/inputDialog.svelte.ts +51 -0
- package/src/lib/styles/rail.css +63 -0
- package/src/lib/types/annotation.ts +38 -0
- package/src/lib/types/comments.ts +97 -0
- package/src/lib/types/entityPreview.ts +45 -0
- package/src/lib/types/filePicker.ts +2 -0
- package/src/lib/types/smartImageEditor.ts +39 -0
- package/src/lib/types/templateVars.ts +36 -0
- package/src/lib/utils/dateFormatters.ts +12 -10
- package/src/lib/utils/phone.ts +80 -0
- 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-
|
|
14
|
-
case 'waiting': return 'badge-
|
|
15
|
-
case '
|
|
16
|
-
case '
|
|
17
|
-
case '
|
|
18
|
-
case '
|
|
19
|
-
case '
|
|
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
|
}
|