@myrjfa/ui 2.0.1 → 2.1.1
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/LICENSE +201 -201
- package/README.md +2 -2
- package/dist/chat/ChatMain.d.ts +3 -1
- package/dist/chat/ChatMain.d.ts.map +1 -1
- package/dist/chat/ChatMain.js +2 -1
- package/dist/chat/MessageBubble.js +4 -4
- package/dist/chat/MessageInput.d.ts +1 -1
- package/dist/chat/MessageInput.d.ts.map +1 -1
- package/dist/chat/components/ParticipantSelector.d.ts +1 -1
- package/dist/chat/components/ParticipantSelector.d.ts.map +1 -1
- package/dist/dashboard/app-sidebar.js +3 -3
- package/dist/dashboard/data-table.d.ts +2 -1
- package/dist/dashboard/data-table.d.ts.map +1 -1
- package/dist/dashboard/data-table.js +3 -3
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/main/navbar.js +5 -5
- package/dist/main/review-page.d.ts +1 -1
- package/dist/main/review-page.d.ts.map +1 -1
- package/dist/main/review-page.js +49 -9
- package/dist/misc/alertdialogclaude.d.ts.map +1 -1
- package/dist/misc/alertdialogclaude.js +1 -1
- package/dist/misc/command.js +1 -1
- package/dist/misc/dashboard/action-buttons.js +31 -0
- package/dist/misc/document-upload-button.d.ts +12 -0
- package/dist/misc/document-upload-button.d.ts.map +1 -0
- package/dist/misc/document-upload-button.js +27 -0
- package/dist/misc/empty-state.d.ts +10 -0
- package/dist/misc/empty-state.d.ts.map +1 -0
- package/dist/misc/empty-state.js +5 -0
- package/dist/misc/filter.d.ts.map +1 -1
- package/dist/misc/filter.js +1 -1
- package/dist/misc/image-compressor.d.ts +29 -0
- package/dist/misc/image-compressor.d.ts.map +1 -0
- package/dist/misc/image-compressor.js +70 -0
- package/dist/misc/image-cropper.d.ts +10 -0
- package/dist/misc/image-cropper.d.ts.map +1 -0
- package/dist/misc/image-cropper.js +44 -0
- package/dist/misc/input.d.ts.map +1 -1
- package/dist/misc/input.js +1 -1
- package/dist/misc/misc/alertdialogclaude.js +221 -0
- package/dist/misc/misc/button.js +46 -0
- package/dist/misc/misc/dropdown-menu.js +136 -0
- package/dist/misc/multiImageUploader.d.ts +2 -1
- package/dist/misc/multiImageUploader.d.ts.map +1 -1
- package/dist/misc/multiImageUploader.js +26 -2
- package/dist/misc/newsLetter.js +1 -1
- package/dist/misc/notification.js +2 -2
- package/dist/misc/popover.d.ts.map +1 -1
- package/dist/misc/popover.js +1 -1
- package/dist/misc/pwa-install-button.d.ts +9 -0
- package/dist/misc/pwa-install-button.d.ts.map +1 -0
- package/dist/misc/pwa-install-button.js +158 -0
- package/dist/misc/select.d.ts.map +1 -1
- package/dist/misc/select.js +3 -3
- package/dist/misc/skeleton.d.ts +36 -1
- package/dist/misc/skeleton.d.ts.map +1 -1
- package/dist/misc/skeleton.js +40 -3
- package/dist/misc/tile.js +3 -3
- package/dist/misc/whatsapp-help.d.ts +9 -0
- package/dist/misc/whatsapp-help.d.ts.map +1 -0
- package/dist/misc/whatsapp-help.js +13 -0
- package/dist/profile/socialLink.d.ts +1 -1
- package/dist/profile/socialLink.d.ts.map +1 -1
- package/dist/profile/socialLink.js +49 -19
- package/package.json +5 -4
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef, useState } from 'react';
|
|
4
|
+
import Image from 'next/image';
|
|
5
|
+
/**
|
|
6
|
+
* #9 — Floating PWA Install Button
|
|
7
|
+
* Premium banner aligned with Trippeaze brand.
|
|
8
|
+
* - Only shows on mobile (beforeinstallprompt)
|
|
9
|
+
* - Auto-hides after 10 s
|
|
10
|
+
* - Animated entrance / exit
|
|
11
|
+
*/
|
|
12
|
+
export function PwaInstallButton() {
|
|
13
|
+
const [show, setShow] = useState(false);
|
|
14
|
+
const [hiding, setHiding] = useState(false);
|
|
15
|
+
const promptRef = useRef(null);
|
|
16
|
+
const timerRef = useRef(null);
|
|
17
|
+
const dismiss = () => {
|
|
18
|
+
setHiding(true);
|
|
19
|
+
setTimeout(() => setShow(false), 350);
|
|
20
|
+
};
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
|
23
|
+
if (!isMobile)
|
|
24
|
+
return;
|
|
25
|
+
const handler = (e) => {
|
|
26
|
+
e.preventDefault();
|
|
27
|
+
promptRef.current = e;
|
|
28
|
+
setShow(true);
|
|
29
|
+
setHiding(false);
|
|
30
|
+
timerRef.current = setTimeout(dismiss, 10000);
|
|
31
|
+
};
|
|
32
|
+
window.addEventListener('beforeinstallprompt', handler);
|
|
33
|
+
return () => {
|
|
34
|
+
window.removeEventListener('beforeinstallprompt', handler);
|
|
35
|
+
if (timerRef.current)
|
|
36
|
+
clearTimeout(timerRef.current);
|
|
37
|
+
};
|
|
38
|
+
}, []);
|
|
39
|
+
const handleInstall = async () => {
|
|
40
|
+
if (!promptRef.current)
|
|
41
|
+
return;
|
|
42
|
+
if (timerRef.current)
|
|
43
|
+
clearTimeout(timerRef.current);
|
|
44
|
+
promptRef.current.prompt();
|
|
45
|
+
const { outcome } = await promptRef.current.userChoice;
|
|
46
|
+
if (outcome === 'accepted')
|
|
47
|
+
dismiss();
|
|
48
|
+
};
|
|
49
|
+
if (!show)
|
|
50
|
+
return null;
|
|
51
|
+
return (_jsxs(_Fragment, { children: [_jsx("style", { children: `
|
|
52
|
+
@keyframes tpz-slide-up {
|
|
53
|
+
from { opacity: 0; transform: translateX(-50%) translateY(20px); }
|
|
54
|
+
to { opacity: 1; transform: translateX(-50%) translateY(0); }
|
|
55
|
+
}
|
|
56
|
+
@keyframes tpz-slide-down {
|
|
57
|
+
from { opacity: 1; transform: translateX(-50%) translateY(0); }
|
|
58
|
+
to { opacity: 0; transform: translateX(-50%) translateY(20px); }
|
|
59
|
+
}
|
|
60
|
+
@keyframes tpz-orbit {
|
|
61
|
+
from { transform: rotate(0deg) translateX(22px) rotate(0deg); }
|
|
62
|
+
to { transform: rotate(360deg) translateX(22px) rotate(-360deg); }
|
|
63
|
+
}
|
|
64
|
+
@keyframes tpz-shimmer {
|
|
65
|
+
0% { background-position: -200% center; }
|
|
66
|
+
100% { background-position: 200% center; }
|
|
67
|
+
}
|
|
68
|
+
` }), _jsxs("div", { style: {
|
|
69
|
+
position: 'fixed',
|
|
70
|
+
bottom: '88px',
|
|
71
|
+
left: '50%',
|
|
72
|
+
transform: 'translateX(-50%)',
|
|
73
|
+
zIndex: 9999,
|
|
74
|
+
animation: hiding
|
|
75
|
+
? 'tpz-slide-down 0.35s cubic-bezier(.4,0,.2,1) forwards'
|
|
76
|
+
: 'tpz-slide-up 0.4s cubic-bezier(.16,1,.3,1) forwards',
|
|
77
|
+
// Prevent layout shift during animation
|
|
78
|
+
willChange: 'transform, opacity',
|
|
79
|
+
}, children: [_jsx("div", { style: {
|
|
80
|
+
position: 'absolute',
|
|
81
|
+
inset: '-3px',
|
|
82
|
+
borderRadius: '9999px',
|
|
83
|
+
background: 'linear-gradient(135deg, #f97316, #fb923c, #22d3ee, #0891b2)',
|
|
84
|
+
opacity: 0.3,
|
|
85
|
+
filter: 'blur(8px)',
|
|
86
|
+
zIndex: 0,
|
|
87
|
+
} }), _jsxs("button", { onClick: handleInstall, style: {
|
|
88
|
+
position: 'relative',
|
|
89
|
+
zIndex: 1,
|
|
90
|
+
display: 'flex',
|
|
91
|
+
alignItems: 'center',
|
|
92
|
+
gap: '10px',
|
|
93
|
+
padding: '10px 18px 10px 12px',
|
|
94
|
+
borderRadius: '9999px',
|
|
95
|
+
border: '1px solid rgba(0,0,0,0.06)',
|
|
96
|
+
background: 'linear-gradient(135deg, #ffffff 0%, #f8fafc 100%)',
|
|
97
|
+
boxShadow: '0 12px 32px rgba(0,0,0,0.12), inset 0 1px 0 rgba(255,255,255,0.9)',
|
|
98
|
+
cursor: 'pointer',
|
|
99
|
+
whiteSpace: 'nowrap',
|
|
100
|
+
backdropFilter: 'blur(8px)',
|
|
101
|
+
}, children: [_jsx("div", { style: {
|
|
102
|
+
width: '36px',
|
|
103
|
+
height: '36px',
|
|
104
|
+
borderRadius: '50%',
|
|
105
|
+
overflow: 'hidden',
|
|
106
|
+
flexShrink: 0,
|
|
107
|
+
boxShadow: '0 2px 8px rgba(249,115,22,0.2)',
|
|
108
|
+
}, children: _jsx(Image, { src: "/images/logoicon.webp", alt: "Trippeaze", width: 36, height: 36, style: { objectFit: 'cover' } }) }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: '1px' }, children: [_jsx("span", { style: {
|
|
109
|
+
fontSize: '11px',
|
|
110
|
+
fontWeight: 500,
|
|
111
|
+
letterSpacing: '0.08em',
|
|
112
|
+
textTransform: 'uppercase',
|
|
113
|
+
color: '#64748b',
|
|
114
|
+
lineHeight: 1,
|
|
115
|
+
}, children: "Get the app" }), _jsx("span", { style: {
|
|
116
|
+
fontSize: '15px',
|
|
117
|
+
fontWeight: 700,
|
|
118
|
+
letterSpacing: '-0.01em',
|
|
119
|
+
lineHeight: 1.2,
|
|
120
|
+
// Shimmer text using logo colors
|
|
121
|
+
background: 'linear-gradient(90deg, #fb923c, #fbbf24, #22d3ee, #fb923c)',
|
|
122
|
+
backgroundSize: '200% auto',
|
|
123
|
+
WebkitBackgroundClip: 'text',
|
|
124
|
+
WebkitTextFillColor: 'transparent',
|
|
125
|
+
backgroundClip: 'text',
|
|
126
|
+
animation: 'tpz-shimmer 3s linear infinite',
|
|
127
|
+
}, children: "Install Trippeaze" })] }), _jsx("div", { style: {
|
|
128
|
+
marginLeft: '4px',
|
|
129
|
+
width: '28px',
|
|
130
|
+
height: '28px',
|
|
131
|
+
borderRadius: '50%',
|
|
132
|
+
background: 'linear-gradient(135deg, #f97316, #dc2626)',
|
|
133
|
+
display: 'flex',
|
|
134
|
+
alignItems: 'center',
|
|
135
|
+
justifyContent: 'center',
|
|
136
|
+
flexShrink: 0,
|
|
137
|
+
boxShadow: '0 2px 8px rgba(249,115,22,0.5)',
|
|
138
|
+
}, children: _jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", children: _jsx("path", { d: "M7 2v7M4 6.5l3 3 3-3M2.5 11h9", stroke: "white", strokeWidth: "1.7", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] }), _jsx("button", { onClick: (e) => { e.stopPropagation(); dismiss(); }, "aria-label": "Dismiss", style: {
|
|
139
|
+
position: 'absolute',
|
|
140
|
+
top: '-6px',
|
|
141
|
+
right: '-6px',
|
|
142
|
+
zIndex: 2,
|
|
143
|
+
width: '20px',
|
|
144
|
+
height: '20px',
|
|
145
|
+
borderRadius: '50%',
|
|
146
|
+
background: '#ffffff',
|
|
147
|
+
border: '1px solid rgba(0,0,0,0.1)',
|
|
148
|
+
color: '#64748b',
|
|
149
|
+
fontSize: '11px',
|
|
150
|
+
lineHeight: '20px',
|
|
151
|
+
textAlign: 'center',
|
|
152
|
+
cursor: 'pointer',
|
|
153
|
+
display: 'flex',
|
|
154
|
+
alignItems: 'center',
|
|
155
|
+
justifyContent: 'center',
|
|
156
|
+
boxShadow: '0 2px 6px rgba(0,0,0,0.1)',
|
|
157
|
+
}, children: "\u2715" })] })] }));
|
|
158
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../src/misc/select.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAA;AAKzD,iBAAS,MAAM,CAAC,EACd,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,2CAEnD;AAED,iBAAS,WAAW,CAAC,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,2CAEpD;AAED,iBAAS,WAAW,CAAC,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,2CAEpD;AAED,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,OAAO,CAAC,2CAgBtD;AAED,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,QAAQ,EACR,QAAmB,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../src/misc/select.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAA;AAKzD,iBAAS,MAAM,CAAC,EACd,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,2CAEnD;AAED,iBAAS,WAAW,CAAC,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,2CAEpD;AAED,iBAAS,WAAW,CAAC,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,2CAEpD;AAED,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,OAAO,CAAC,2CAgBtD;AAED,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,QAAQ,EACR,QAAmB,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,OAAO,CAAC,2CA6BtD;AAED,iBAAS,WAAW,CAAC,EACnB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,2CAQpD;AAED,iBAAS,UAAU,CAAC,EAClB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,2CAkBnD;AAED,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,SAAS,CAAC,2CAQxD;AAED,iBAAS,oBAAoB,CAAC,EAC5B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,cAAc,CAAC,2CAa7D;AAED,iBAAS,sBAAsB,CAAC,EAC9B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,gBAAgB,CAAC,2CAa/D;AAED,OAAO,EACL,MAAM,EACN,aAAa,EACb,WAAW,EACX,UAAU,EACV,WAAW,EACX,sBAAsB,EACtB,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,WAAW,GACZ,CAAA"}
|
package/dist/misc/select.js
CHANGED
|
@@ -16,9 +16,9 @@ function SelectTrigger({ className, children, ...props }) {
|
|
|
16
16
|
return (_jsxs(SelectPrimitive.Trigger, { "data-slot": "select-trigger", className: cn("border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive flex h-9 w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className), ...props, children: [children, _jsx(SelectPrimitive.Icon, { asChild: true, children: _jsx(ChevronDownIcon, { className: "size-4 opacity-50" }) })] }));
|
|
17
17
|
}
|
|
18
18
|
function SelectContent({ className, children, position = "popper", ...props }) {
|
|
19
|
-
return (_jsx(SelectPrimitive.Portal, { children: _jsxs(SelectPrimitive.Content, { "data-slot": "select-content", className: cn("bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-
|
|
20
|
-
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", className), position: position, ...props, children: [_jsx(SelectScrollUpButton, {}), _jsx(SelectPrimitive.Viewport, { className: cn("p-1", position === "popper" &&
|
|
21
|
-
"h-[var(--radix-select-
|
|
19
|
+
return (_jsx(SelectPrimitive.Portal, { children: _jsxs(SelectPrimitive.Content, { "data-slot": "select-content", className: cn("bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-[310] max-h-96 min-w-[8rem] overflow-hidden rounded-md border shadow-md pointer-events-auto", position === "popper" &&
|
|
20
|
+
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", className), position: position, onWheel: (e) => e.stopPropagation(), ...props, children: [_jsx(SelectScrollUpButton, {}), _jsx(SelectPrimitive.Viewport, { className: cn("p-1", position === "popper" &&
|
|
21
|
+
"h-full max-h-[var(--radix-select-content-available-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1 overflow-y-auto touch-pan-y"), children: children }), _jsx(SelectScrollDownButton, {})] }) }));
|
|
22
22
|
}
|
|
23
23
|
function SelectLabel({ className, ...props }) {
|
|
24
24
|
return (_jsx(SelectPrimitive.Label, { "data-slot": "select-label", className: cn("px-2 py-1.5 text-sm font-medium", className), ...props }));
|
package/dist/misc/skeleton.d.ts
CHANGED
|
@@ -1,3 +1,38 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Base Skeleton component
|
|
4
|
+
* Centralized pulse animation and color.
|
|
5
|
+
*/
|
|
1
6
|
declare function Skeleton({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
2
|
-
|
|
7
|
+
/** Horizontal Tile pattern */
|
|
8
|
+
declare function SkeletonTile({ className }: {
|
|
9
|
+
className?: string;
|
|
10
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
/** Vertical List pattern */
|
|
12
|
+
declare function SkeletonList({ count, className }: {
|
|
13
|
+
count?: number;
|
|
14
|
+
className?: string;
|
|
15
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
/**
|
|
17
|
+
* Full-page loading skeleton (Default Export)
|
|
18
|
+
* Displayed while data is loading.
|
|
19
|
+
*/
|
|
20
|
+
export default function LoadingSkeleton({ count }: {
|
|
21
|
+
count?: number;
|
|
22
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
/** Card skeleton for feed-style layouts */
|
|
24
|
+
declare function CardSkeleton({ className }: {
|
|
25
|
+
className?: string;
|
|
26
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
/** Feed grid skeleton (6 cards by default) */
|
|
28
|
+
declare function FeedSkeleton({ count }: {
|
|
29
|
+
count?: number;
|
|
30
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
/** Page-level skeleton for detail pages (opportunity/package/blog) */
|
|
32
|
+
declare function DetailPageSkeleton(): import("react/jsx-runtime").JSX.Element;
|
|
33
|
+
/** Form field skeleton */
|
|
34
|
+
declare function FormSkeleton({ fields }: {
|
|
35
|
+
fields?: number;
|
|
36
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
37
|
+
export { Skeleton, CardSkeleton, SkeletonTile, SkeletonList, DetailPageSkeleton, FormSkeleton, FeedSkeleton };
|
|
3
38
|
//# sourceMappingURL=skeleton.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skeleton.d.ts","sourceRoot":"","sources":["../../src/misc/skeleton.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"skeleton.d.ts","sourceRoot":"","sources":["../../src/misc/skeleton.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B;;;GAGG;AACH,iBAAS,QAAQ,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAQrE;AAED,8BAA8B;AAC9B,iBAAS,YAAY,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,2CAY1D;AAED,4BAA4B;AAC5B,iBAAS,YAAY,CAAC,EAAE,KAAS,EAAE,SAAS,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,2CAQrF;AAED;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EAAE,KAAS,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,2CAiBxE;AAED,2CAA2C;AAC3C,iBAAS,YAAY,CAAC,EAAE,SAAc,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,2CAe/D;AAED,8CAA8C;AAC9C,iBAAS,YAAY,CAAC,EAAE,KAAS,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,2CAQtD;AAED,sEAAsE;AACtE,iBAAS,kBAAkB,4CA8C1B;AAED,0BAA0B;AAC1B,iBAAS,YAAY,CAAC,EAAE,MAAU,EAAE,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,2CAYxD;AAGD,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,YAAY,EACb,CAAA"}
|
package/dist/misc/skeleton.js
CHANGED
|
@@ -1,6 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from "@myrjfa/state/dist/lib/utils";
|
|
4
|
+
/**
|
|
5
|
+
* Base Skeleton component
|
|
6
|
+
* Centralized pulse animation and color.
|
|
7
|
+
*/
|
|
3
8
|
function Skeleton({ className, ...props }) {
|
|
4
9
|
return (_jsx("div", { "data-slot": "skeleton", className: cn("bg-primary/10 animate-pulse rounded-md", className), ...props }));
|
|
5
10
|
}
|
|
6
|
-
|
|
11
|
+
/** Horizontal Tile pattern */
|
|
12
|
+
function SkeletonTile({ className }) {
|
|
13
|
+
return (_jsxs("div", { className: cn("flex gap-3 items-start p-3 rounded-lg border border-border", className), children: [_jsx(Skeleton, { className: "h-20 w-20 rounded-lg shrink-0" }), _jsxs("div", { className: "flex-1 space-y-2", children: [_jsx(Skeleton, { className: "h-4 w-2/3" }), _jsx(Skeleton, { className: "h-3 w-full" }), _jsx(Skeleton, { className: "h-3 w-4/5" }), _jsx(Skeleton, { className: "h-5 w-24 rounded-full" })] })] }));
|
|
14
|
+
}
|
|
15
|
+
/** Vertical List pattern */
|
|
16
|
+
function SkeletonList({ count = 4, className }) {
|
|
17
|
+
return (_jsx("div", { className: cn("space-y-3", className), children: Array.from({ length: count }).map((_, i) => (_jsx(SkeletonTile, {}, i))) }));
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Full-page loading skeleton (Default Export)
|
|
21
|
+
* Displayed while data is loading.
|
|
22
|
+
*/
|
|
23
|
+
export default function LoadingSkeleton({ count = 4 }) {
|
|
24
|
+
return (_jsx("div", { className: "w-full h-screen flex items-center justify-center", children: _jsx("div", { className: "w-full max-w-2xl p-6 space-y-4", children: Array.from({ length: count }).map((_, i) => (_jsxs("div", { className: "animate-pulse space-y-3", children: [_jsx("div", { className: "h-4 bg-muted rounded w-3/4" }), _jsx("div", { className: "h-4 bg-muted rounded w-1/2" }), _jsx("div", { className: "h-3 bg-muted rounded w-full" })] }, i))) }) }));
|
|
25
|
+
}
|
|
26
|
+
/** Card skeleton for feed-style layouts */
|
|
27
|
+
function CardSkeleton({ className = '' }) {
|
|
28
|
+
return (_jsxs("div", { className: `rounded-xl overflow-hidden border border-border animate-pulse ${className}`, children: [_jsx("div", { className: "h-48 bg-muted w-full" }), _jsxs("div", { className: "p-4 space-y-3", children: [_jsx("div", { className: "h-4 bg-muted rounded w-3/4" }), _jsx("div", { className: "h-3 bg-muted rounded w-full" }), _jsx("div", { className: "h-3 bg-muted rounded w-5/6" }), _jsxs("div", { className: "flex gap-2 pt-2", children: [_jsx("div", { className: "h-6 bg-muted rounded-full w-16" }), _jsx("div", { className: "h-6 bg-muted rounded-full w-16" })] })] })] }));
|
|
29
|
+
}
|
|
30
|
+
/** Feed grid skeleton (6 cards by default) */
|
|
31
|
+
function FeedSkeleton({ count = 6 }) {
|
|
32
|
+
return (_jsx("div", { className: "w-full p-6 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4", children: Array.from({ length: count }).map((_, i) => (_jsx(CardSkeleton, {}, i))) }));
|
|
33
|
+
}
|
|
34
|
+
/** Page-level skeleton for detail pages (opportunity/package/blog) */
|
|
35
|
+
function DetailPageSkeleton() {
|
|
36
|
+
return (_jsx("div", { className: "min-h-screen bg-slate-50 mt-15", children: _jsxs("div", { className: "container mx-auto px-4 py-6 flex flex-col lg:flex-row gap-10", children: [_jsx("div", { className: "lg:w-80 shrink-0", children: _jsxs("div", { className: "bg-white rounded-lg shadow-sm p-4 animate-pulse space-y-3", children: [_jsx("div", { className: "h-5 bg-muted rounded w-1/2" }), [1, 2, 3, 4, 5].map(i => (_jsx("div", { className: "h-4 bg-muted rounded w-3/4" }, i)))] }) }), _jsxs("main", { className: "flex-1 lg:pr-5 flex flex-col gap-6", children: [_jsxs("div", { className: "bg-white rounded-lg shadow-sm overflow-hidden animate-pulse", children: [_jsx("div", { className: "h-72 bg-muted" }), _jsxs("div", { className: "p-6 space-y-3", children: [_jsx("div", { className: "h-6 bg-muted rounded w-2/3" }), _jsx("div", { className: "h-4 bg-muted rounded w-1/2" })] })] }), _jsxs("div", { className: "bg-white rounded-lg shadow-sm p-6 animate-pulse space-y-4", children: [_jsx("div", { className: "h-5 bg-muted rounded w-1/4" }), _jsx("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4", children: [1, 2, 3].map(i => (_jsxs("div", { className: "space-y-2", children: [_jsx("div", { className: "h-4 bg-muted rounded w-1/2" }), _jsx("div", { className: "h-3 bg-muted rounded w-3/4" })] }, i))) })] }), _jsxs("div", { className: "bg-white rounded-lg shadow-sm p-6 animate-pulse space-y-3", children: [_jsx("div", { className: "h-5 bg-muted rounded w-1/4" }), [1, 2, 3, 4].map(i => (_jsx("div", { className: "h-3 bg-muted rounded", style: { width: `${60 + Math.random() * 40}%` } }, i)))] })] })] }) }));
|
|
37
|
+
}
|
|
38
|
+
/** Form field skeleton */
|
|
39
|
+
function FormSkeleton({ fields = 4 }) {
|
|
40
|
+
return (_jsxs("div", { className: "space-y-6", children: [Array.from({ length: fields }).map((_, i) => (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-4 w-1/4" }), _jsx(Skeleton, { className: "h-10 w-full" })] }, i))), _jsx(Skeleton, { className: "h-12 w-full" })] }));
|
|
41
|
+
}
|
|
42
|
+
// Aliases for backward compatibility or different naming preferences
|
|
43
|
+
export { Skeleton, CardSkeleton, SkeletonTile, SkeletonList, DetailPageSkeleton, FormSkeleton, FeedSkeleton };
|
package/dist/misc/tile.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { toggleUserWishlist } from "@myrjfa/state";
|
|
4
|
-
import { userAtom, userLoadingAtom } from "@myrjfa/state";
|
|
5
|
-
import { cn, formatDate, truncateText } from "@myrjfa/state";
|
|
3
|
+
import { toggleUserWishlist } from "@myrjfa/state/dist/lib/actions/actions";
|
|
4
|
+
import { userAtom, userLoadingAtom } from "@myrjfa/state/dist/lib/userAtom";
|
|
5
|
+
import { cn, formatDate, truncateText } from "@myrjfa/state/dist/lib/utils";
|
|
6
6
|
import { useAtom, useAtomValue } from "jotai";
|
|
7
7
|
import { Clock, Heart, Loader2, MapPin, Star } from "lucide-react";
|
|
8
8
|
import Image from "next/image";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #21 — Floating WhatsApp Help Button
|
|
3
|
+
* Fixed bottom-right pill button that opens a WhatsApp chat with support.
|
|
4
|
+
* Matches the "Need help? Chat with us" pill + green icon design.
|
|
5
|
+
*/
|
|
6
|
+
export declare function WhatsAppHelpButton({ message }: {
|
|
7
|
+
message: string;
|
|
8
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
//# sourceMappingURL=whatsapp-help.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whatsapp-help.d.ts","sourceRoot":"","sources":["../../src/misc/whatsapp-help.tsx"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,2CAyClE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { WhatsappIcon } from 'react-share';
|
|
4
|
+
import Link from 'next/link';
|
|
5
|
+
/**
|
|
6
|
+
* #21 — Floating WhatsApp Help Button
|
|
7
|
+
* Fixed bottom-right pill button that opens a WhatsApp chat with support.
|
|
8
|
+
* Matches the "Need help? Chat with us" pill + green icon design.
|
|
9
|
+
*/
|
|
10
|
+
export function WhatsAppHelpButton({ message }) {
|
|
11
|
+
const whatsappUrl = `https://wa.me/918482944029?text=${encodeURIComponent(message)}`;
|
|
12
|
+
return (_jsxs(Link, { href: whatsappUrl, target: "_blank", rel: "noopener noreferrer", "aria-label": "Get help on WhatsApp", className: "\n fixed bottom-6 right-6 z-[9998]\n flex items-center gap-0\n rounded-full\n bg-white\n shadow-[0_2px_12px_rgba(0,0,0,0.15)]\n hover:shadow-[0_4px_16px_rgba(0,0,0,0.2)]\n border border-gray-200\n transition-all duration-200\n hover:scale-[1.03]\n overflow-hidden\n no-underline\n group\n ", children: [_jsx("span", { className: "\n pl-4 pr-3 py-2.5\n text-sm font-medium text-gray-700\n whitespace-nowrap\n group-hover:text-gray-900\n transition-colors\n ", children: "Need help? Chat with us" }), _jsx("span", { className: "flex-shrink-0 pr-0.5 py-0.5", children: _jsx(WhatsappIcon, { size: 42, round: true }) })] }));
|
|
13
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"socialLink.d.ts","sourceRoot":"","sources":["../../src/profile/socialLink.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"socialLink.d.ts","sourceRoot":"","sources":["../../src/profile/socialLink.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAsB,kBAAkB,EAAE,MAAM,6CAA6C,CAAC;AAGrG,UAAU,oBAAoB;IAC1B,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,OAAO,CAAC;IACvB,oBAAoB,CAAC,EAAE,CAAC,QAAQ,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvF;AAeD,wBAAgB,eAAe,CAAC,EAC5B,QAAQ,EACR,GAAG,EACH,aAAa,EACb,oBAAoB,GACvB,EAAE,oBAAoB,kDAgFtB"}
|
|
@@ -3,30 +3,60 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useState } from "react";
|
|
4
4
|
import { Input } from "../misc/input";
|
|
5
5
|
import { Button } from "../misc/button";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { GithubIcon, InstagramIcon, StoreIcon, YoutubeIcon } from "lucide-react";
|
|
7
|
+
import { normalizeSocialUrl } from "@myrjfa/state/dist/lib/utils/socialMediaUrl";
|
|
8
|
+
import { FacebookIcon, LinkedinIcon, TwitterIcon } from "react-share";
|
|
8
9
|
const platformConfig = {
|
|
9
|
-
instagram: { label: "Instagram", icon: InstagramIcon, color: "hover:text-pink-600" },
|
|
10
|
-
youtube: { label: "YouTube", icon: YoutubeIcon, color: "hover:text-red-600" },
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
instagram: { label: "Instagram", icon: InstagramIcon, color: "hover:text-pink-600", hint: "Enter username or profile URL" },
|
|
11
|
+
youtube: { label: "YouTube", icon: YoutubeIcon, color: "hover:text-red-600", hint: "Enter @handle or profile URL" },
|
|
12
|
+
twitter: { label: "Twitter", icon: TwitterIcon, color: "hover:text-blue-600", hint: "Enter @handle or profile URL" },
|
|
13
|
+
facebook: { label: "Facebook", icon: FacebookIcon, color: "hover:text-blue-600", hint: "Enter @handle or profile URL" },
|
|
14
|
+
github: { label: "GitHub", icon: GithubIcon, color: "hover:text-blue-600", hint: "Enter @handle or profile URL" },
|
|
15
|
+
linkedin: { label: "LinkedIn", icon: LinkedinIcon, color: "hover:text-blue-600", hint: "Enter username or profile URL" },
|
|
16
|
+
googleBusiness: { label: "Google Business", icon: StoreIcon, color: "hover:text-green-600", hint: "Enter full Google Business URL" },
|
|
13
17
|
};
|
|
14
18
|
export function SocialLinkField({ platform, url, isCurrentUser, updateUserSocialLink, }) {
|
|
15
|
-
const [input, setInput] = useState(url);
|
|
19
|
+
const [input, setInput] = useState(url !== null && url !== void 0 ? url : "");
|
|
20
|
+
const [urlError, setUrlError] = useState(null);
|
|
16
21
|
const [loading, setLoading] = useState(false);
|
|
17
|
-
const
|
|
18
|
-
|
|
22
|
+
const { label, icon: Icon, color, hint } = platformConfig[platform];
|
|
23
|
+
// #13: Validate and normalize the URL when focus leaves the input
|
|
24
|
+
const handleBlur = () => {
|
|
25
|
+
if (!input.trim() || platform === "googleBusiness")
|
|
26
|
+
return;
|
|
27
|
+
const { url: normalized, error } = normalizeSocialUrl(platform, input);
|
|
28
|
+
setUrlError(error);
|
|
29
|
+
if (!error)
|
|
30
|
+
setInput(normalized); // auto-correct the field to canonical URL
|
|
31
|
+
};
|
|
32
|
+
const handleSave = async () => {
|
|
33
|
+
if (!input.trim() || !updateUserSocialLink)
|
|
34
|
+
return;
|
|
35
|
+
// Final normalization before saving
|
|
36
|
+
let finalUrl = input;
|
|
37
|
+
if (platform !== "googleBusiness") {
|
|
38
|
+
const { url: normalized, error } = normalizeSocialUrl(platform, input);
|
|
39
|
+
if (error) {
|
|
40
|
+
setUrlError(error);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
finalUrl = normalized;
|
|
44
|
+
setInput(normalized);
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
setLoading(true);
|
|
48
|
+
await updateUserSocialLink(platform, finalUrl);
|
|
49
|
+
setUrlError(null);
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
setLoading(false);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
19
55
|
if (isCurrentUser) {
|
|
20
|
-
return (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx(Input, { type: "
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
await updateUserSocialLink(platform, input);
|
|
25
|
-
}
|
|
26
|
-
finally {
|
|
27
|
-
setLoading(false);
|
|
28
|
-
}
|
|
29
|
-
}, children: "Add" })] }));
|
|
56
|
+
return (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsxs("div", { className: "flex items-center gap-1", children: [_jsx(Icon, { className: `h-5 w-5 shrink-0 text-gray-400 ${color}` }), _jsx(Input, { type: "text", placeholder: hint, value: input, onChange: (e) => {
|
|
57
|
+
setInput(e.target.value);
|
|
58
|
+
setUrlError(null);
|
|
59
|
+
}, onBlur: handleBlur, className: urlError ? "border-red-400 focus:ring-red-400" : "" }), _jsx(Button, { disabled: loading || !input.trim(), onClick: handleSave, children: loading ? "Adding..." : "Add" })] }), urlError && (_jsx("p", { className: "text-xs text-red-500 ml-6", children: urlError }))] }));
|
|
30
60
|
}
|
|
31
61
|
else if (url) {
|
|
32
62
|
return (_jsx("a", { href: url, target: "_blank", rel: "noopener noreferrer", className: `text-gray-500 ${color} flex flex-row gap-1`, children: _jsx(Icon, { className: "h-5 w-5" }) }));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@myrjfa/ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/index.js",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"description": "Shared UI components for my apps",
|
|
10
10
|
"main": "dist/index.js",
|
|
11
11
|
"types": "dist/index.d.ts",
|
|
12
|
+
"sideEffects": false,
|
|
12
13
|
"files": [
|
|
13
14
|
"dist"
|
|
14
15
|
],
|
|
@@ -42,7 +43,7 @@
|
|
|
42
43
|
"embla-carousel-react": "^8.5.2",
|
|
43
44
|
"emoji-picker-react": "^4.18.0",
|
|
44
45
|
"leaflet": "1.9.4",
|
|
45
|
-
"
|
|
46
|
+
"react-easy-crop": "^5.5.6",
|
|
46
47
|
"react-hook-form": "^7.54.2",
|
|
47
48
|
"react-icons": "^5.5.0",
|
|
48
49
|
"react-leaflet": "^5.0.0",
|
|
@@ -55,11 +56,11 @@
|
|
|
55
56
|
"lucide-react": "*",
|
|
56
57
|
"next": "*",
|
|
57
58
|
"react": "*",
|
|
58
|
-
"react-dom": "",
|
|
59
|
+
"react-dom": "*",
|
|
59
60
|
"zod": "*"
|
|
60
61
|
},
|
|
61
62
|
"devDependencies": {
|
|
62
|
-
"@myrjfa/state": "2.
|
|
63
|
+
"@myrjfa/state": "2.1.1",
|
|
63
64
|
"@types/leaflet": "1.9.21",
|
|
64
65
|
"@types/react": "19.0.10",
|
|
65
66
|
"@types/react-dom": "^19.0.4",
|