@voyage-sdk/core 0.1.3 → 0.1.4
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 +48 -11
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -12,30 +12,67 @@ Or via CDN:
|
|
|
12
12
|
|
|
13
13
|
```html
|
|
14
14
|
<script src="https://unpkg.com/@voyage-sdk/core"></script>
|
|
15
|
-
<link rel="stylesheet" href="https://unpkg.com/@voyage-sdk/core/dist/style.css" />
|
|
16
15
|
```
|
|
17
16
|
|
|
17
|
+
> **Note:** Styles are automatically injected. No CSS import required.
|
|
18
|
+
|
|
18
19
|
## Quick Start
|
|
19
20
|
|
|
20
|
-
###
|
|
21
|
+
### HTML / Vanilla JS
|
|
21
22
|
|
|
22
|
-
```
|
|
23
|
+
```html
|
|
24
|
+
<script src="https://unpkg.com/@voyage-sdk/core"></script>
|
|
25
|
+
<script>
|
|
26
|
+
Voyage.init({
|
|
27
|
+
sdkKey: 'your-sdk-key-here'
|
|
28
|
+
})
|
|
29
|
+
</script>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### React / Next.js
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { useEffect } from 'react'
|
|
23
36
|
import Voyage from '@voyage-sdk/core'
|
|
24
37
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
38
|
+
function App() {
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
Voyage.init({
|
|
41
|
+
sdkKey: 'your-sdk-key-here'
|
|
42
|
+
})
|
|
43
|
+
}, [])
|
|
44
|
+
|
|
45
|
+
return <div>...</div>
|
|
46
|
+
}
|
|
28
47
|
```
|
|
29
48
|
|
|
30
|
-
###
|
|
49
|
+
### Vue.js
|
|
31
50
|
|
|
32
|
-
```
|
|
33
|
-
<script
|
|
34
|
-
|
|
35
|
-
|
|
51
|
+
```vue
|
|
52
|
+
<script setup>
|
|
53
|
+
import { onMounted } from 'vue'
|
|
54
|
+
import Voyage from '@voyage-sdk/core'
|
|
55
|
+
|
|
56
|
+
onMounted(() => {
|
|
36
57
|
Voyage.init({
|
|
37
58
|
sdkKey: 'your-sdk-key-here'
|
|
38
59
|
})
|
|
60
|
+
})
|
|
61
|
+
</script>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Svelte
|
|
65
|
+
|
|
66
|
+
```svelte
|
|
67
|
+
<script>
|
|
68
|
+
import { onMount } from 'svelte'
|
|
69
|
+
import Voyage from '@voyage-sdk/core'
|
|
70
|
+
|
|
71
|
+
onMount(() => {
|
|
72
|
+
Voyage.init({
|
|
73
|
+
sdkKey: 'your-sdk-key-here'
|
|
74
|
+
})
|
|
75
|
+
})
|
|
39
76
|
</script>
|
|
40
77
|
```
|
|
41
78
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
'use strict';Object.defineProperty(exports,'__esModule',{value:true});var preact=require('preact'),hooks=require('preact/hooks'),jsxRuntime=require('preact/jsx-runtime');function ge(){return jsxRuntime.jsx("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsxRuntime.jsx("path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"})})}function D({onClick:r,label:o,position:e,primaryColor:i,hasError:p=false}){let[a,u]=hooks.useState(false),[c,l]=hooks.useState(false),d=e==="bottom-right"?{right:"24px"}:{left:"24px"},g=()=>c?"scale(0.95)":a?"scale(1.02) translateY(-2px)":"scale(1)";return jsxRuntime.jsxs("div",{style:{position:"fixed",bottom:"24px",...d,zIndex:9998},children:[jsxRuntime.jsxs("button",{onClick:r,onMouseEnter:()=>u(true),onMouseLeave:()=>{u(false),l(false);},onMouseDown:()=>l(true),onMouseUp:()=>l(false),style:{position:"relative",display:"flex",alignItems:"center",gap:"10px",padding:"14px 24px",border:"none",borderRadius:"50px",cursor:"pointer",fontFamily:"'Quicksand', 'Nunito', system-ui, sans-serif",fontSize:"15px",fontWeight:600,color:"#fff",backgroundColor:i,boxShadow:a?`0 8px 32px ${i}60, 0 0 20px ${i}40`:`0 4px 20px ${i}50, 0 0 10px ${i}30`,transform:g(),transition:"all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1)"},children:[jsxRuntime.jsx(ge,{}),jsxRuntime.jsx("span",{children:o})]}),p&&jsxRuntime.jsx("div",{style:{position:"absolute",top:"-4px",right:"-4px",width:"18px",height:"18px",borderRadius:"50%",backgroundColor:"#EF4444",display:"flex",alignItems:"center",justifyContent:"center",color:"#fff",fontSize:"12px",fontWeight:"bold",boxShadow:"0 2px 6px rgba(239, 68, 68, 0.5)"},children:"!"})]})}function he({size:r=24}){return jsxRuntime.jsx("svg",{width:r,height:r,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsxRuntime.jsx("path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"})})}function me(){return jsxRuntime.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsxRuntime.jsx("path",{d:"M8 2l1.88 1.88M14.12 3.88L16 2M9 7.13v-1a3.003 3.003 0 116 0v1"}),jsxRuntime.jsx("path",{d:"M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 014-4h4a4 4 0 014 4v3c0 3.3-2.7 6-6 6"}),jsxRuntime.jsx("path",{d:"M12 20v-9M6.53 9C4.6 8.8 3 7.1 3 5M6 13H2M6 17l-4 1M17.47 9c1.93-.2 3.53-1.9 3.53-4M18 13h4M18 17l4 1"})]})}function be(){return jsxRuntime.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsxRuntime.jsx("path",{d:"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 006 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"}),jsxRuntime.jsx("path",{d:"M9 18h6M10 22h4"})]})}function ye(){return jsxRuntime.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsxRuntime.jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),jsxRuntime.jsx("circle",{cx:"8.5",cy:"8.5",r:"1.5"}),jsxRuntime.jsx("polyline",{points:"21 15 16 10 5 21"})]})}function _(){return jsxRuntime.jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsxRuntime.jsx("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),jsxRuntime.jsx("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})}function xe(){return jsxRuntime.jsx("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsxRuntime.jsx("polyline",{points:"20 6 9 17 4 12"})})}var n={bgLight:"#F8FAFC",bgCard:"rgba(255, 255, 255, 0.98)",border:"rgba(0, 0, 0, 0.08)",text:"#1F2937",textMuted:"#6B7280",error:"#EF4444",success:"#22C55E"};function X({config:r,metadata:o,onClose:e,onSubmit:i,onUpload:p}){let[a,u]=hooks.useState(null),[c,l]=hooks.useState(""),[d,g]=hooks.useState(""),[v,x]=hooks.useState(null),[P,k]=hooks.useState(null),[L,H]=hooks.useState(false),[j,B]=hooks.useState(false),[U,b]=hooks.useState(null),[se,ae]=hooks.useState(false),F=hooks.useRef(null),{i18n:C,formFields:E,theme:le}=r,S=le.primaryColor||"#0ea5e9",A=400,de=a==="bug"?C.bugPlaceholder||C.placeholder:C.featurePlaceholder||C.placeholder,ce=async h=>{let I=h.target.files?.[0];if(I){if(!I.type.startsWith("image/")){b("Only image files are allowed");return}if(I.size>10*1024*1024){b("Image must be under 10MB");return}B(true),b(null);try{let M=await Se(I,{maxWidth:1920,maxHeight:1080,quality:.8}),J=new FileReader;J.onload=()=>k(J.result),J.readAsDataURL(M);let N=await p(M);B(!1),N?x(N):(b("Failed to upload image"),k(null));}catch(M){console.error("[Voyage] Image processing error:",M),B(false),b("Failed to process image");}}},pe=()=>{x(null),k(null),F.current&&(F.current.value="");},ue=async()=>{if(!a){b("Please select a type");return}if(!c.trim()){b("Please enter your feedback");return}if(E.email.required&&!d.trim()){b("Please enter your email");return}H(true),b(null);let h={label:a,text:c.trim(),email:d.trim()||void 0,imageUrl:v||void 0,metadata:o},m=await i(h);H(false),m?ae(true):b("Failed to submit. Please try again.");},f=(()=>{let h=`${S}15`;return {overlay:{position:"fixed",top:0,left:0,right:0,bottom:0,backgroundColor:"rgba(0, 0, 0, 0.4)",backdropFilter:"blur(4px)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999,padding:"20px"},modal:{backgroundColor:n.bgCard,backdropFilter:"blur(20px)",borderRadius:"20px",width:"100%",maxWidth:"580px",maxHeight:"90vh",overflowY:"auto",position:"relative",fontFamily:"'Quicksand', 'Nunito', system-ui, sans-serif",border:`1px solid ${n.border}`,boxShadow:"0 25px 50px -12px rgba(0, 0, 0, 0.15)"},colorBar:{height:"4px",backgroundColor:S},header:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"14px 20px",borderBottom:`1px solid ${n.border}`,backgroundColor:n.bgLight},headerIcon:{width:"32px",height:"32px",borderRadius:"10px",backgroundColor:S,display:"flex",alignItems:"center",justifyContent:"center",color:"#fff"},typeButton:m=>({display:"flex",alignItems:"center",justifyContent:"center",gap:"6px",padding:"10px 12px",border:m?`2px solid ${S}`:`1px solid ${n.border}`,borderRadius:"10px",backgroundColor:m?h:n.bgLight,cursor:"pointer",fontWeight:600,fontSize:"13px",color:m?n.text:n.textMuted,transition:"all 0.2s"}),submitButton:m=>({width:"100%",padding:"12px",backgroundColor:m?n.bgLight:S,color:m?n.textMuted:"#fff",border:"none",borderRadius:"12px",fontSize:"15px",fontWeight:700,cursor:m?"not-allowed":"pointer",fontFamily:"inherit",transition:"all 0.2s",boxShadow:m?"none":`0 4px 15px ${S}40`}),primaryButton:{width:"100%",padding:"16px",backgroundColor:S,color:"#fff",border:"none",borderRadius:"12px",fontSize:"15px",fontWeight:700,cursor:"pointer",fontFamily:"inherit",marginTop:"8px"}}})();return se?jsxRuntime.jsx("div",{style:f.overlay,children:jsxRuntime.jsx("div",{style:f.modal,children:jsxRuntime.jsxs("div",{style:Te,children:[jsxRuntime.jsx("div",{style:Re,children:jsxRuntime.jsx(xe,{})}),jsxRuntime.jsx("h3",{style:Oe,children:C.successMessage}),jsxRuntime.jsx("p",{style:$e,children:"Your voice shapes what we build next."}),jsxRuntime.jsx("button",{onClick:e,style:f.primaryButton,children:"Done"})]})})}):jsxRuntime.jsx("div",{style:f.overlay,onClick:e,children:jsxRuntime.jsxs("div",{style:f.modal,onClick:h=>h.stopPropagation(),children:[jsxRuntime.jsxs("div",{style:f.header,children:[jsxRuntime.jsxs("div",{style:ve,children:[jsxRuntime.jsx("div",{style:f.headerIcon,children:jsxRuntime.jsx(he,{size:20})}),jsxRuntime.jsx("span",{style:Ce,children:"Help Us Improve"})]}),jsxRuntime.jsx("button",{onClick:e,style:ke,children:jsxRuntime.jsx(_,{})})]}),jsxRuntime.jsx("div",{style:f.colorBar}),jsxRuntime.jsxs("div",{style:we,children:[jsxRuntime.jsxs("div",{style:Q,children:[jsxRuntime.jsx("label",{style:W,children:"Feedback Type"}),jsxRuntime.jsxs("div",{style:Pe,children:[jsxRuntime.jsxs("button",{onClick:()=>u("bug"),style:f.typeButton(a==="bug"),children:[jsxRuntime.jsx("span",{style:Y(a==="bug","bug"),children:jsxRuntime.jsx(me,{})}),jsxRuntime.jsx("span",{children:"Bug"})]}),jsxRuntime.jsxs("button",{onClick:()=>u("feature"),style:f.typeButton(a==="feature"),children:[jsxRuntime.jsx("span",{style:Y(a==="feature","feature"),children:jsxRuntime.jsx(be,{})}),jsxRuntime.jsx("span",{children:"Feature"})]})]})]}),jsxRuntime.jsxs("div",{style:Fe,children:[jsxRuntime.jsxs("div",{style:Ie,children:[jsxRuntime.jsx("label",{style:W,children:"Description"}),jsxRuntime.jsxs("div",{style:je,children:[jsxRuntime.jsx("textarea",{placeholder:de,value:c,maxLength:A,onInput:h=>l(h.target.value),style:Be}),jsxRuntime.jsxs("span",{style:Ee,children:[c.length,"/",A]})]})]}),jsxRuntime.jsxs("div",{style:Me,children:[jsxRuntime.jsx("label",{style:W,children:"Screenshot"}),P?jsxRuntime.jsxs("div",{style:De,children:[jsxRuntime.jsx("img",{src:P,alt:"Preview",style:Le}),jsxRuntime.jsx("button",{onClick:pe,style:Xe,children:jsxRuntime.jsx(_,{})}),j&&jsxRuntime.jsx("div",{style:ze,children:"..."})]}):jsxRuntime.jsxs("button",{onClick:()=>F.current?.click(),style:We,children:[jsxRuntime.jsx(ye,{}),jsxRuntime.jsx("span",{style:{fontSize:"11px"},children:"Upload"})]}),jsxRuntime.jsx("input",{ref:F,type:"file",accept:"image/*",onChange:ce,style:{display:"none"}})]})]}),E.email.enabled&&jsxRuntime.jsxs("div",{style:Q,children:[jsxRuntime.jsxs("label",{style:W,children:["Email ",E.email.required?"":"(optional)"]}),jsxRuntime.jsx("input",{type:"email",placeholder:"your@email.com",value:d,onInput:h=>g(h.target.value),style:Je})]}),U&&jsxRuntime.jsx("p",{style:Ve,children:U}),jsxRuntime.jsx("button",{onClick:ue,disabled:L||j,style:f.submitButton(L||j),children:L?jsxRuntime.jsxs("span",{style:He,children:[jsxRuntime.jsx("span",{className:"voyage-spinner"}),"Sending..."]}):C.submitLabel})]})]})})}async function Se(r,o){let{maxWidth:e,maxHeight:i,quality:p}=o;return new Promise((a,u)=>{let c=new Image;c.onload=()=>{let{width:l,height:d}=c;if(l>e||d>i){let x=Math.min(e/l,i/d);l=Math.round(l*x),d=Math.round(d*x);}let g=document.createElement("canvas");g.width=l,g.height=d;let v=g.getContext("2d");if(!v){u(new Error("Failed to get canvas context"));return}v.drawImage(c,0,0,l,d),g.toBlob(x=>{if(!x){u(new Error("Failed to convert image"));return}let P=Date.now(),k=new File([x],`image_${P}.webp`,{type:"image/webp"});a(k);},"image/webp",p);},c.onerror=()=>u(new Error("Failed to load image")),c.src=URL.createObjectURL(r);})}var ve={display:"flex",alignItems:"center",gap:"12px"},Ce={fontSize:"16px",fontWeight:700,color:n.text},ke={background:"transparent",border:"none",color:n.textMuted,cursor:"pointer",padding:"8px",borderRadius:"8px",display:"flex",alignItems:"center",justifyContent:"center",transition:"all 0.2s"},we={padding:"16px 20px"},Q={marginBottom:"14px"},W={display:"block",fontSize:"13px",fontWeight:600,color:n.text,marginBottom:"8px"},Pe={display:"grid",gridTemplateColumns:"1fr 1fr",gap:"12px"},Fe={display:"flex",gap:"14px",marginBottom:"14px"},Ie={flex:1,display:"flex",flexDirection:"column"},Me={width:"120px",flexShrink:0,display:"flex",flexDirection:"column"},We={width:"100%",aspectRatio:"1",border:`2px dashed ${n.border}`,borderRadius:"10px",backgroundColor:"transparent",cursor:"pointer",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:"4px",color:n.textMuted,fontSize:"12px",transition:"all 0.2s"},Le={width:"100%",aspectRatio:"1",objectFit:"cover",borderRadius:"10px"},Y=(r,o)=>({display:"flex",alignItems:"center",justifyContent:"center",color:r?o==="bug"?n.error:"#F59E0B":n.textMuted}),je={position:"relative"},Be={width:"100%",minHeight:"120px",padding:"14px",border:`1px solid ${n.border}`,borderRadius:"12px",fontSize:"14px",resize:"vertical",boxSizing:"border-box",backgroundColor:n.bgLight,color:n.text,fontFamily:"inherit",outline:"none"},Ee={position:"absolute",bottom:"12px",right:"14px",fontSize:"12px",color:n.textMuted},Je={width:"100%",padding:"10px 12px",border:`1px solid ${n.border}`,borderRadius:"10px",fontSize:"13px",boxSizing:"border-box",backgroundColor:n.bgLight,color:n.text,fontFamily:"inherit",outline:"none"},De={position:"relative",display:"inline-block",borderRadius:"12px",overflow:"hidden"},Xe={position:"absolute",top:"8px",right:"8px",width:"28px",height:"28px",borderRadius:"50%",backgroundColor:"rgba(0, 0, 0, 0.7)",color:"#fff",border:"none",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center"},ze={position:"absolute",inset:0,backgroundColor:"rgba(0, 0, 0, 0.7)",display:"flex",alignItems:"center",justifyContent:"center",color:"#fff",fontSize:"14px",borderRadius:"12px"},Ve={color:n.error,fontSize:"14px",marginBottom:"16px",padding:"12px",backgroundColor:"rgba(239, 68, 68, 0.1)",borderRadius:"8px",border:"1px solid rgba(239, 68, 68, 0.3)"},Te={padding:"48px 24px",textAlign:"center"},Re={width:"64px",height:"64px",borderRadius:"50%",backgroundColor:"rgba(34, 197, 94, 0.15)",color:n.success,display:"flex",alignItems:"center",justifyContent:"center",margin:"0 auto 20px"},Oe={fontSize:"20px",fontWeight:700,color:n.text,marginBottom:"8px"},$e={fontSize:"14px",color:n.textMuted,marginBottom:"24px"},He={display:"flex",alignItems:"center",justifyContent:"center",gap:"8px"};function z({config:r,onSubmit:o,onUpload:e,getMetadata:i,visible:p,defaultOpen:a=false,hasError:u=false,onOpenChange:c}){let[l,d]=hooks.useState(a);if(hooks.useEffect(()=>{d(a);},[a]),hooks.useEffect(()=>{c?.(l);},[l,c]),!p)return null;let{theme:g,i18n:v}=r;return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[!l&&jsxRuntime.jsx(D,{onClick:()=>d(true),label:v.buttonLabel,position:g.position,primaryColor:g.primaryColor,hasError:u}),l&&jsxRuntime.jsx(X,{config:r,metadata:i(),onClose:()=>d(false),onSubmit:o,onUpload:e})]})}var V=()=>{if(typeof document>"u"||document.getElementById("voyage-sdk-styles"))return;let r=document.createElement("style");r.id="voyage-sdk-styles",r.textContent=`
|
|
1
|
+
'use strict';Object.defineProperty(exports,'__esModule',{value:true});var preact=require('preact'),hooks=require('preact/hooks'),jsxRuntime=require('preact/jsx-runtime');function he(){return jsxRuntime.jsx("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsxRuntime.jsx("path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"})})}function D({onClick:i,label:t,position:e,primaryColor:r,hasError:a=false}){let[l,p]=hooks.useState(false),[u,c]=hooks.useState(false),d=e==="bottom-right"?{right:"24px"}:{left:"24px"},g=()=>u?"scale(0.95)":l?"scale(1.02) translateY(-2px)":"scale(1)";return jsxRuntime.jsxs("div",{style:{position:"fixed",bottom:"24px",...d,zIndex:9998},children:[jsxRuntime.jsxs("button",{onClick:i,onMouseEnter:()=>p(true),onMouseLeave:()=>{p(false),c(false);},onMouseDown:()=>c(true),onMouseUp:()=>c(false),style:{position:"relative",display:"flex",alignItems:"center",gap:"10px",padding:"14px 24px",border:"none",borderRadius:"50px",cursor:"pointer",fontFamily:"'Quicksand', 'Nunito', system-ui, sans-serif",fontSize:"15px",fontWeight:600,color:"#fff",backgroundColor:r,boxShadow:l?`0 8px 32px ${r}60, 0 0 20px ${r}40`:`0 4px 20px ${r}50, 0 0 10px ${r}30`,transform:g(),transition:"all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1)"},children:[jsxRuntime.jsx(he,{}),jsxRuntime.jsx("span",{children:t})]}),a&&jsxRuntime.jsx("div",{style:{position:"absolute",top:"-4px",right:"-4px",width:"18px",height:"18px",borderRadius:"50%",backgroundColor:"#EF4444",display:"flex",alignItems:"center",justifyContent:"center",color:"#fff",fontSize:"12px",fontWeight:"bold",boxShadow:"0 2px 6px rgba(239, 68, 68, 0.5)"},children:"!"})]})}function be({size:i=24}){return jsxRuntime.jsx("svg",{width:i,height:i,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsxRuntime.jsx("path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"})})}function ye(){return jsxRuntime.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsxRuntime.jsx("path",{d:"M8 2l1.88 1.88M14.12 3.88L16 2M9 7.13v-1a3.003 3.003 0 116 0v1"}),jsxRuntime.jsx("path",{d:"M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 014-4h4a4 4 0 014 4v3c0 3.3-2.7 6-6 6"}),jsxRuntime.jsx("path",{d:"M12 20v-9M6.53 9C4.6 8.8 3 7.1 3 5M6 13H2M6 17l-4 1M17.47 9c1.93-.2 3.53-1.9 3.53-4M18 13h4M18 17l4 1"})]})}function xe(){return jsxRuntime.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsxRuntime.jsx("path",{d:"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 006 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"}),jsxRuntime.jsx("path",{d:"M9 18h6M10 22h4"})]})}function Se(){return jsxRuntime.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsxRuntime.jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),jsxRuntime.jsx("circle",{cx:"8.5",cy:"8.5",r:"1.5"}),jsxRuntime.jsx("polyline",{points:"21 15 16 10 5 21"})]})}function Q(){return jsxRuntime.jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsxRuntime.jsx("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),jsxRuntime.jsx("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})}function Ce(){return jsxRuntime.jsx("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsxRuntime.jsx("polyline",{points:"20 6 9 17 4 12"})})}var n={bgLight:"#F8FAFC",bgCard:"rgba(255, 255, 255, 0.98)",border:"rgba(0, 0, 0, 0.08)",text:"#1F2937",textMuted:"#6B7280",error:"#EF4444",success:"#22C55E"};function O({config:i,metadata:t,onClose:e,onSubmit:r,onUpload:a}){let[l,p]=hooks.useState(null),[u,c]=hooks.useState(""),[d,g]=hooks.useState(""),[C,x]=hooks.useState(null),[P,k]=hooks.useState(null),[B,H]=hooks.useState(false),[j,T]=hooks.useState(false),[_,b]=hooks.useState(null),[le,ce]=hooks.useState(false),I=hooks.useRef(null),{i18n:v,formFields:J,theme:de}=i,S=de.primaryColor||"#0ea5e9",N=400,ue=l==="bug"?v.bugPlaceholder||v.placeholder:v.featurePlaceholder||v.placeholder,pe=async h=>{let M=h.target.files?.[0];if(M){if(!M.type.startsWith("image/")){b("Only image files are allowed");return}if(M.size>10*1024*1024){b("Image must be under 10MB");return}T(true),b(null);try{let F=await ve(M,{maxWidth:1920,maxHeight:1080,quality:.8}),V=new FileReader;V.onload=()=>k(V.result),V.readAsDataURL(F);let q=await a(F);T(!1),q?x(q):(b("Failed to upload image"),k(null));}catch(F){console.error("[Voyage] Image processing error:",F),T(false),b("Failed to process image");}}},ge=()=>{x(null),k(null),I.current&&(I.current.value="");},fe=async()=>{if(!l){b("Please select a type");return}if(!u.trim()){b("Please enter your feedback");return}if(J.email.required&&!d.trim()){b("Please enter your email");return}H(true),b(null);let h={label:l,text:u.trim(),email:d.trim()||void 0,imageUrl:C||void 0,metadata:t},m=await r(h);H(false),m?ce(true):b("Failed to submit. Please try again.");},f=(()=>{let h=`${S}15`;return {overlay:{position:"fixed",top:0,left:0,right:0,bottom:0,backgroundColor:"rgba(0, 0, 0, 0.4)",backdropFilter:"blur(4px)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999,padding:"20px"},modal:{backgroundColor:n.bgCard,backdropFilter:"blur(20px)",borderRadius:"20px",width:"100%",maxWidth:"580px",maxHeight:"90vh",overflowY:"auto",position:"relative",fontFamily:"'Quicksand', 'Nunito', system-ui, sans-serif",border:`1px solid ${n.border}`,boxShadow:"0 25px 50px -12px rgba(0, 0, 0, 0.15)"},colorBar:{height:"4px",backgroundColor:S},header:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"14px 20px",borderBottom:`1px solid ${n.border}`,backgroundColor:n.bgLight},headerIcon:{width:"32px",height:"32px",borderRadius:"10px",backgroundColor:S,display:"flex",alignItems:"center",justifyContent:"center",color:"#fff"},typeButton:m=>({display:"flex",alignItems:"center",justifyContent:"center",gap:"6px",padding:"10px 12px",border:m?`2px solid ${S}`:`1px solid ${n.border}`,borderRadius:"10px",backgroundColor:m?h:n.bgLight,cursor:"pointer",fontWeight:600,fontSize:"13px",color:m?n.text:n.textMuted,transition:"all 0.2s"}),submitButton:m=>({width:"100%",padding:"12px",backgroundColor:m?n.bgLight:S,color:m?n.textMuted:"#fff",border:"none",borderRadius:"12px",fontSize:"15px",fontWeight:700,cursor:m?"not-allowed":"pointer",fontFamily:"inherit",transition:"all 0.2s",boxShadow:m?"none":`0 4px 15px ${S}40`}),primaryButton:{width:"100%",padding:"16px",backgroundColor:S,color:"#fff",border:"none",borderRadius:"12px",fontSize:"15px",fontWeight:700,cursor:"pointer",fontFamily:"inherit",marginTop:"8px"}}})();return le?jsxRuntime.jsx("div",{style:f.overlay,children:jsxRuntime.jsx("div",{style:f.modal,children:jsxRuntime.jsxs("div",{style:Re,children:[jsxRuntime.jsx("div",{style:Ue,children:jsxRuntime.jsx(Ce,{})}),jsxRuntime.jsx("h3",{style:$e,children:v.successMessage}),jsxRuntime.jsx("p",{style:Ae,children:"Your voice shapes what we build next."}),jsxRuntime.jsx("button",{onClick:e,style:f.primaryButton,children:"Done"})]})})}):jsxRuntime.jsx("div",{style:f.overlay,onClick:e,children:jsxRuntime.jsxs("div",{style:f.modal,onClick:h=>h.stopPropagation(),children:[jsxRuntime.jsxs("div",{style:f.header,children:[jsxRuntime.jsxs("div",{style:ke,children:[jsxRuntime.jsx("div",{style:f.headerIcon,children:jsxRuntime.jsx(be,{size:20})}),jsxRuntime.jsx("span",{style:we,children:"Help Us Improve"})]}),jsxRuntime.jsx("button",{onClick:e,style:Pe,children:jsxRuntime.jsx(Q,{})})]}),jsxRuntime.jsx("div",{style:f.colorBar}),jsxRuntime.jsxs("div",{style:Ie,children:[jsxRuntime.jsxs("div",{style:Y,children:[jsxRuntime.jsx("label",{style:E,children:"Feedback Type"}),jsxRuntime.jsxs("div",{style:Me,children:[jsxRuntime.jsxs("button",{onClick:()=>p("bug"),style:f.typeButton(l==="bug"),children:[jsxRuntime.jsx("span",{style:Z(l==="bug","bug"),children:jsxRuntime.jsx(ye,{})}),jsxRuntime.jsx("span",{children:"Bug"})]}),jsxRuntime.jsxs("button",{onClick:()=>p("feature"),style:f.typeButton(l==="feature"),children:[jsxRuntime.jsx("span",{style:Z(l==="feature","feature"),children:jsxRuntime.jsx(xe,{})}),jsxRuntime.jsx("span",{children:"Feature"})]})]})]}),jsxRuntime.jsxs("div",{style:Fe,children:[jsxRuntime.jsxs("div",{style:Ee,children:[jsxRuntime.jsx("label",{style:E,children:"Description"}),jsxRuntime.jsxs("div",{style:je,children:[jsxRuntime.jsx("textarea",{placeholder:ue,value:u,maxLength:N,onInput:h=>c(h.target.value),style:Te}),jsxRuntime.jsxs("span",{style:Je,children:[u.length,"/",N]})]})]}),jsxRuntime.jsxs("div",{style:We,children:[jsxRuntime.jsx("label",{style:E,children:"Screenshot"}),P?jsxRuntime.jsxs("div",{style:De,children:[jsxRuntime.jsx("img",{src:P,alt:"Preview",style:Be}),jsxRuntime.jsx("button",{onClick:ge,style:Oe,children:jsxRuntime.jsx(Q,{})}),j&&jsxRuntime.jsx("div",{style:ze,children:"..."})]}):jsxRuntime.jsxs("button",{onClick:()=>I.current?.click(),style:Le,children:[jsxRuntime.jsx(Se,{}),jsxRuntime.jsx("span",{style:{fontSize:"11px"},children:"Upload"})]}),jsxRuntime.jsx("input",{ref:I,type:"file",accept:"image/*",onChange:pe,style:{display:"none"}})]})]}),J.email.enabled&&jsxRuntime.jsxs("div",{style:Y,children:[jsxRuntime.jsxs("label",{style:E,children:["Email ",J.email.required?"":"(optional)"]}),jsxRuntime.jsx("input",{type:"email",placeholder:"your@email.com",value:d,onInput:h=>g(h.target.value),style:Ve})]}),_&&jsxRuntime.jsx("p",{style:Xe,children:_}),jsxRuntime.jsx("button",{onClick:fe,disabled:B||j,style:f.submitButton(B||j),children:B?jsxRuntime.jsxs("span",{style:He,children:[jsxRuntime.jsx("span",{className:"voyage-spinner"}),"Sending..."]}):v.submitLabel})]})]})})}async function ve(i,t){let{maxWidth:e,maxHeight:r,quality:a}=t;return new Promise((l,p)=>{let u=new Image;u.onload=()=>{let{width:c,height:d}=u;if(c>e||d>r){let x=Math.min(e/c,r/d);c=Math.round(c*x),d=Math.round(d*x);}let g=document.createElement("canvas");g.width=c,g.height=d;let C=g.getContext("2d");if(!C){p(new Error("Failed to get canvas context"));return}C.drawImage(u,0,0,c,d),g.toBlob(x=>{if(!x){p(new Error("Failed to convert image"));return}let P=Date.now(),k=new File([x],`image_${P}.webp`,{type:"image/webp"});l(k);},"image/webp",a);},u.onerror=()=>p(new Error("Failed to load image")),u.src=URL.createObjectURL(i);})}var ke={display:"flex",alignItems:"center",gap:"12px"},we={fontSize:"16px",fontWeight:700,color:n.text},Pe={background:"transparent",border:"none",color:n.textMuted,cursor:"pointer",padding:"8px",borderRadius:"8px",display:"flex",alignItems:"center",justifyContent:"center",transition:"all 0.2s"},Ie={padding:"16px 20px"},Y={marginBottom:"14px"},E={display:"block",fontSize:"13px",fontWeight:600,color:n.text,marginBottom:"8px"},Me={display:"grid",gridTemplateColumns:"1fr 1fr",gap:"12px"},Fe={display:"flex",gap:"14px",marginBottom:"14px"},Ee={flex:1,display:"flex",flexDirection:"column"},We={width:"120px",flexShrink:0,display:"flex",flexDirection:"column"},Le={width:"100%",aspectRatio:"1",border:`2px dashed ${n.border}`,borderRadius:"10px",backgroundColor:"transparent",cursor:"pointer",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:"4px",color:n.textMuted,fontSize:"12px",transition:"all 0.2s"},Be={width:"100%",aspectRatio:"1",objectFit:"cover",borderRadius:"10px"},Z=(i,t)=>({display:"flex",alignItems:"center",justifyContent:"center",color:i?t==="bug"?n.error:"#F59E0B":n.textMuted}),je={position:"relative"},Te={width:"100%",minHeight:"120px",padding:"14px",border:`1px solid ${n.border}`,borderRadius:"12px",fontSize:"14px",resize:"vertical",boxSizing:"border-box",backgroundColor:n.bgLight,color:n.text,fontFamily:"inherit",outline:"none"},Je={position:"absolute",bottom:"12px",right:"14px",fontSize:"12px",color:n.textMuted},Ve={width:"100%",padding:"10px 12px",border:`1px solid ${n.border}`,borderRadius:"10px",fontSize:"13px",boxSizing:"border-box",backgroundColor:n.bgLight,color:n.text,fontFamily:"inherit",outline:"none"},De={position:"relative",display:"inline-block",borderRadius:"12px",overflow:"hidden"},Oe={position:"absolute",top:"8px",right:"8px",width:"28px",height:"28px",borderRadius:"50%",backgroundColor:"rgba(0, 0, 0, 0.7)",color:"#fff",border:"none",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center"},ze={position:"absolute",inset:0,backgroundColor:"rgba(0, 0, 0, 0.7)",display:"flex",alignItems:"center",justifyContent:"center",color:"#fff",fontSize:"14px",borderRadius:"12px"},Xe={color:n.error,fontSize:"14px",marginBottom:"16px",padding:"12px",backgroundColor:"rgba(239, 68, 68, 0.1)",borderRadius:"8px",border:"1px solid rgba(239, 68, 68, 0.3)"},Re={padding:"48px 24px",textAlign:"center"},Ue={width:"64px",height:"64px",borderRadius:"50%",backgroundColor:"rgba(34, 197, 94, 0.15)",color:n.success,display:"flex",alignItems:"center",justifyContent:"center",margin:"0 auto 20px"},$e={fontSize:"20px",fontWeight:700,color:n.text,marginBottom:"8px"},Ae={fontSize:"14px",color:n.textMuted,marginBottom:"24px"},He={display:"flex",alignItems:"center",justifyContent:"center",gap:"8px"};function z({config:i,onSubmit:t,onUpload:e,getMetadata:r,visible:a,defaultOpen:l=false,hasError:p=false,onOpenChange:u}){let[c,d]=hooks.useState(l);if(hooks.useEffect(()=>{d(l);},[l]),hooks.useEffect(()=>{u?.(c);},[c,u]),!a)return null;let{theme:g,i18n:C}=i;return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[!c&&jsxRuntime.jsx(D,{onClick:()=>d(true),label:C.buttonLabel,position:g.position,primaryColor:g.primaryColor,hasError:p}),c&&jsxRuntime.jsx(O,{config:i,metadata:r(),onClose:()=>d(false),onSubmit:t,onUpload:e})]})}var X=()=>{if(typeof document>"u"||document.getElementById("voyage-sdk-styles"))return;let i=document.createElement("style");i.id="voyage-sdk-styles",i.textContent=`
|
|
2
2
|
/* Voyage SDK Styles */
|
|
3
3
|
|
|
4
4
|
/* Spinner Animation */
|
|
@@ -37,6 +37,6 @@
|
|
|
37
37
|
|
|
38
38
|
/* Load Quicksand font if not present */
|
|
39
39
|
@import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@400;500;600;700&display=swap');
|
|
40
|
-
`,document.head.appendChild(
|
|
41
|
-
exports.Voyage=
|
|
40
|
+
`,document.head.appendChild(i);};var R="https://rxflzurkkuqgopjkshjh.supabase.co/functions/v1",oe="voyage_config";function U(i,t,e){let r=new AbortController,a=setTimeout(()=>r.abort(),e);return fetch(i,{...t,signal:r.signal}).finally(()=>clearTimeout(a))}async function L(i,t={}){let{forceRefresh:e=false}=t;if(!e){let r=W(i);if(r)return r}try{let r=await U(`${R}/get-widget-config`,{method:"GET",headers:{"Content-Type":"application/json","x-sdk-key":i}},5e3);if(!r.ok)return console.error("[Voyage] Failed to fetch config:",r.status),W(i,!0);let a=await r.json();return Ke(i,a),a}catch(r){return r instanceof Error&&r.name==="AbortError"?console.warn("[Voyage] Config fetch timeout, using cached config"):console.error("[Voyage] Network error:",r),W(i,true)}}async function re(i,t){try{let e=await U(`${R}/submit-feedback`,{method:"POST",headers:{"Content-Type":"application/json","x-sdk-key":i},body:JSON.stringify({label:t.label,content:t.text,email:t.email,imageUrl:t.imageUrl,metadata:t.metadata})},1e4);if(!e.ok){let r=await e.json().catch(()=>({}));return console.error("[Voyage] Failed to submit feedback:",e.status,r),!1}return !0}catch(e){return e instanceof Error&&e.name==="AbortError"?console.error("[Voyage] Feedback submission timeout"):console.error("[Voyage] Network error:",e),false}}async function ie(i,t){if(!t.type.startsWith("image/"))return console.error("[Voyage] Only image files are allowed"),null;if(t.size>5*1024*1024)return console.error("[Voyage] Image must be under 5MB"),null;try{let e=new FormData;e.append("file",t);let r=await U(`${R}/upload-feedback-image`,{method:"POST",headers:{"x-sdk-key":i},body:e},3e4);if(!r.ok){let l=await r.json().catch(()=>({}));return console.error("[Voyage] Failed to upload image:",r.status,l),null}return (await r.json()).url}catch(e){return e instanceof Error&&e.name==="AbortError"?console.error("[Voyage] Image upload timeout"):console.error("[Voyage] Network error:",e),null}}function ne(i){return W(i,true)}function W(i,t=false){try{let e=localStorage.getItem(`${oe}_${i}`);if(!e)return null;let r=JSON.parse(e);return Date.now()-r.timestamp>36e5&&!t?null:r.config}catch{return null}}function Ke(i,t){try{let e={config:t,timestamp:Date.now()};localStorage.setItem(`${oe}_${i}`,JSON.stringify(e));}catch{}}function se(){return {url:window.location.href,pathname:window.location.pathname,browser:navigator.userAgent,viewport:`${window.innerWidth}x${window.innerHeight}`,title:document.title,timestamp:new Date().toISOString(),locale:navigator.language,referrer:document.referrer}}var $={projectId:"",formFields:{email:{enabled:true,required:false},category:{enabled:true,options:["bug","feature"]}},theme:{primaryColor:"#0ea5e9",position:"bottom-right"},i18n:{buttonLabel:"To : the Maker",placeholder:"Describe your ideas to improve our product",bugPlaceholder:"Please describe the bug in detail (e.g., clicked a button and it didn't work)",featurePlaceholder:"Describe your ideas to improve our product (e.g., I want to export TASK.md to Linear tickets)",submitLabel:"Send to the Maker",successMessage:"Thank you for your feedback!"}},A=class{constructor(){this.config=null;this.serverConfig=null;this.container=null;this.isWidgetVisible=false;this.isModalOpen=false;this.hasInitError=false;}async init(t){if(this.config=t,this.hasInitError=false,!t.sdkKey){console.error("[Voyage] SDK Key is required. Get your key from the dashboard."),this.hasInitError=true,X(),this.isWidgetVisible=true,this.serverConfig={...$},this.renderWidget();return}if(X(),!this.shouldDisplay()){console.log("[Voyage] Widget hidden by display rules");return}let e=ne(t.sdkKey);if(e){this.serverConfig=this.mergeConfig(e,t),this.isWidgetVisible=true,this.renderWidget(),console.log("[Voyage] Initialized (cached)"),this.refreshConfigInBackground();return}let r=await L(t.sdkKey);if(!r){console.error("[Voyage] Failed to fetch config. Check your SDK Key or network connection."),this.hasInitError=true,this.serverConfig={...$},this.isWidgetVisible=true,this.renderWidget();return}this.serverConfig=this.mergeConfig(r,t),this.isWidgetVisible=true,this.renderWidget(),console.log("[Voyage] Initialized");}async refreshConfigInBackground(){if(this.config)try{let t=await L(this.config.sdkKey,{forceRefresh:!0});if(t&&this.serverConfig){let e=this.mergeConfig(t,this.config);JSON.stringify(e)!==JSON.stringify(this.serverConfig)&&(this.serverConfig=e,this.renderWidget(),console.log("[Voyage] Config updated"));}}catch{}}show(){if(!this.config){console.warn("[Voyage] SDK not initialized");return}this.isWidgetVisible=true,this.renderWidget();}hide(){this.isWidgetVisible=false,this.renderWidget();}open(){if(!this.config){console.warn("[Voyage] SDK not initialized");return}this.isModalOpen=true,this.renderWidget();}close(){this.isModalOpen=false,this.renderWidget();}isOpen(){return this.isModalOpen}isVisible(){return this.isWidgetVisible}async refreshConfig(){if(!this.config)return;let t=await L(this.config.sdkKey,{forceRefresh:true});this.serverConfig=this.mergeConfig(t,this.config),this.renderWidget();}destroy(){this.container&&(preact.render(null,this.container),this.container.remove(),this.container=null),this.config=null,this.serverConfig=null,this.isWidgetVisible=false,this.isModalOpen=false;}renderWidget(){if(!this.serverConfig||!this.config)return;this.container||(this.container=document.createElement("div"),this.container.id="voyage-widget-container",document.body.appendChild(this.container));let t=this.config.sdkKey;preact.render(preact.h(z,{config:this.serverConfig,visible:this.isWidgetVisible,defaultOpen:this.isModalOpen,hasError:this.hasInitError,onOpenChange:e=>{this.isModalOpen=e;},getMetadata:se,onSubmit:async e=>re(t,e),onUpload:async e=>ie(t,e)}),this.container);}mergeConfig(t,e){return t||{...$}}shouldDisplay(){if(!this.config)return false;let t=window.location.pathname,{include:e,exclude:r}=this.config;return e&&e.length>0?e.some(a=>this.matchPath(t,a)):r&&r.length>0?!r.some(a=>this.matchPath(t,a)):true}matchPath(t,e){if(e.endsWith("/*")){let r=e.slice(0,-2);return t.startsWith(r)}return t===e}},Qe=new A;var vt=Qe;
|
|
41
|
+
exports.Voyage=Qe;exports.default=vt;//# sourceMappingURL=index.cjs.map
|
|
42
42
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Button.tsx","../src/components/Modal.tsx","../src/components/Widget.tsx","../src/styles.ts","../src/utils/api.ts","../src/utils/metadata.ts","../src/index.ts"],"names":["MessageIcon","jsx","Button","onClick","label","position","primaryColor","hasError","isHovered","setIsHovered","useState","isPressed","setIsPressed","positionStyle","getTransform","jsxs","size","BugIcon","LightbulbIcon","ImageIcon","CloseIcon","CheckIcon","colors","Modal","config","metadata","onClose","onSubmit","onUpload","setLabel","text","setText","email","setEmail","imageUrl","setImageUrl","imagePreview","setImagePreview","isSubmitting","setIsSubmitting","isUploading","setIsUploading","error","setError","success","setSuccess","fileInputRef","useRef","i18n","formFields","theme","maxLength","currentPlaceholder","handleFileSelect","e","file","processedFile","processImage","reader","url","err","handleRemoveImage","handleSubmit","feedbackData","result","styles","primaryBgLight","active","disabled","successContainerStyle","successIconStyle","successTitleStyle","successTextStyle","headerLeftStyle","headerTitleStyle","closeButtonStyle","contentStyle","sectionStyle","labelStyle","typeButtonsStyle","typeIconStyle","descriptionRowStyle","descriptionColStyle","textareaWrapperStyle","textareaStyle","charCountStyle","uploadColStyle","imagePreviewContainerStyle","imagePreviewSquareStyle","removeImageButtonStyle","uploadingOverlayStyle","uploadButtonSquareStyle","inputStyle","errorStyle","spinnerContainerStyle","options","maxWidth","maxHeight","quality","resolve","reject","img","width","height","ratio","canvas","ctx","blob","timestamp","newFile","type","Widget","getMetadata","visible","defaultOpen","onOpenChange","isOpen","setIsOpen","useEffect","Fragment","injectStyles","style","API_BASE","CACHE_KEY","fetchProjectConfig","sdkKey","cached","getFromCache","response","saveToCache","submitFeedback","data","errorData","uploadImage","formData","ignoreExpiry","raw","captureMetadata","DEFAULT_CONFIG","VoyageSDK","fetchedConfig","render","h","open","server","_client","pathname","include","exclude","pattern","prefix","Voyage","index_default"],"mappings":"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","file":"index.cjs","sourcesContent":["import { h } from 'preact';\nimport { useState } from 'preact/hooks';\n\ninterface ButtonProps {\n onClick: () => void;\n label: string;\n position: 'bottom-right' | 'bottom-left';\n primaryColor: string;\n hasError?: boolean;\n}\n\n// 말풍선 아이콘 SVG\nfunction MessageIcon() {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n );\n}\n\n// 에러 아이콘 (느낌표)\nfunction ErrorIcon() {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"#fff\"\n stroke=\"none\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"12\" fill=\"#EF4444\" />\n <text x=\"12\" y=\"17\" textAnchor=\"middle\" fill=\"#fff\" fontSize=\"14\" fontWeight=\"bold\">!</text>\n </svg>\n );\n}\n\nexport function Button({ onClick, label, position, primaryColor, hasError = false }: ButtonProps) {\n const [isHovered, setIsHovered] = useState(false);\n const [isPressed, setIsPressed] = useState(false);\n\n const positionStyle = position === 'bottom-right'\n ? { right: '24px' }\n : { left: '24px' };\n\n // Jelly 효과 transform\n const getTransform = () => {\n if (isPressed) return 'scale(0.95)';\n if (isHovered) return 'scale(1.02) translateY(-2px)';\n return 'scale(1)';\n };\n\n return (\n <div style={{ position: 'fixed', bottom: '24px', ...positionStyle, zIndex: 9998 }}>\n <button\n onClick={onClick}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => { setIsHovered(false); setIsPressed(false); }}\n onMouseDown={() => setIsPressed(true)}\n onMouseUp={() => setIsPressed(false)}\n style={{\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n padding: '14px 24px',\n border: 'none',\n borderRadius: '50px',\n cursor: 'pointer',\n fontFamily: \"'Quicksand', 'Nunito', system-ui, sans-serif\",\n fontSize: '15px',\n fontWeight: 600,\n color: '#fff',\n // primaryColor 적용\n backgroundColor: primaryColor,\n // 그림자 + glow 효과\n boxShadow: isHovered\n ? `0 8px 32px ${primaryColor}60, 0 0 20px ${primaryColor}40`\n : `0 4px 20px ${primaryColor}50, 0 0 10px ${primaryColor}30`,\n // Jelly 애니메이션\n transform: getTransform(),\n transition: 'all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1)',\n }}\n >\n <MessageIcon />\n <span>{label}</span>\n </button>\n {/* 에러 아이콘 - 우측 상단 */}\n {hasError && (\n <div\n style={{\n position: 'absolute',\n top: '-4px',\n right: '-4px',\n width: '18px',\n height: '18px',\n borderRadius: '50%',\n backgroundColor: '#EF4444',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#fff',\n fontSize: '12px',\n fontWeight: 'bold',\n boxShadow: '0 2px 6px rgba(239, 68, 68, 0.5)',\n }}\n >\n !\n </div>\n )}\n </div>\n );\n}\n","import { h } from 'preact';\nimport { useRef, useState } from 'preact/hooks';\n\nimport type { ProjectConfig, FeedbackData, FeedbackMetadata } from '../types';\n\ninterface ModalProps {\n config: ProjectConfig;\n metadata: FeedbackMetadata;\n onClose: () => void;\n onSubmit: (data: FeedbackData) => Promise<boolean>;\n onUpload: (file: File) => Promise<string | null>;\n}\n\n// 아이콘들\nfunction MessageIcon({ size = 24 }: { size?: number }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n );\n}\n\nfunction BugIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M8 2l1.88 1.88M14.12 3.88L16 2M9 7.13v-1a3.003 3.003 0 116 0v1\" />\n <path d=\"M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 014-4h4a4 4 0 014 4v3c0 3.3-2.7 6-6 6\" />\n <path d=\"M12 20v-9M6.53 9C4.6 8.8 3 7.1 3 5M6 13H2M6 17l-4 1M17.47 9c1.93-.2 3.53-1.9 3.53-4M18 13h4M18 17l4 1\" />\n </svg>\n );\n}\n\nfunction LightbulbIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 006 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\" />\n <path d=\"M9 18h6M10 22h4\" />\n </svg>\n );\n}\n\nfunction ImageIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\" />\n <polyline points=\"21 15 16 10 5 21\" />\n </svg>\n );\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\nfunction CheckIcon() {\n return (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n );\n}\n\n// 라이트 테마 색상\nconst colors = {\n bg: '#FFFFFF',\n bgLight: '#F8FAFC',\n bgCard: 'rgba(255, 255, 255, 0.98)',\n border: 'rgba(0, 0, 0, 0.08)',\n borderLight: 'rgba(0, 0, 0, 0.12)',\n text: '#1F2937',\n textMuted: '#6B7280',\n error: '#EF4444',\n success: '#22C55E',\n};\n\nexport function Modal({ config, metadata, onClose, onSubmit, onUpload }: ModalProps) {\n const [label, setLabel] = useState<'bug' | 'feature' | null>(null);\n const [text, setText] = useState('');\n const [email, setEmail] = useState('');\n const [imageUrl, setImageUrl] = useState<string | null>(null);\n const [imagePreview, setImagePreview] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [isUploading, setIsUploading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [success, setSuccess] = useState(false);\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const { i18n, formFields, theme } = config;\n const primaryColor = theme.primaryColor || '#0ea5e9';\n const maxLength = 400;\n\n // 동적 placeholder\n const currentPlaceholder = label === 'bug'\n ? (i18n.bugPlaceholder || i18n.placeholder)\n : (i18n.featurePlaceholder || i18n.placeholder);\n\n const handleFileSelect = async (e: Event) => {\n const target = e.target as HTMLInputElement;\n const file = target.files?.[0];\n if (!file) return;\n\n if (!file.type.startsWith('image/')) {\n setError('Only image files are allowed');\n return;\n }\n if (file.size > 10 * 1024 * 1024) {\n setError('Image must be under 10MB');\n return;\n }\n\n setIsUploading(true);\n setError(null);\n\n try {\n // 이미지를 WebP로 변환 및 resize\n const processedFile = await processImage(file, {\n maxWidth: 1920,\n maxHeight: 1080,\n quality: 0.8,\n });\n\n // 프리뷰 생성\n const reader = new FileReader();\n reader.onload = () => setImagePreview(reader.result as string);\n reader.readAsDataURL(processedFile);\n\n const url = await onUpload(processedFile);\n setIsUploading(false);\n\n if (url) {\n setImageUrl(url);\n } else {\n setError('Failed to upload image');\n setImagePreview(null);\n }\n } catch (err) {\n console.error('[Voyage] Image processing error:', err);\n setIsUploading(false);\n setError('Failed to process image');\n }\n };\n\n const handleRemoveImage = () => {\n setImageUrl(null);\n setImagePreview(null);\n if (fileInputRef.current) {\n fileInputRef.current.value = '';\n }\n };\n\n const handleSubmit = async () => {\n if (!label) {\n setError('Please select a type');\n return;\n }\n if (!text.trim()) {\n setError('Please enter your feedback');\n return;\n }\n if (formFields.email.required && !email.trim()) {\n setError('Please enter your email');\n return;\n }\n\n setIsSubmitting(true);\n setError(null);\n\n const feedbackData: FeedbackData = {\n label,\n text: text.trim(),\n email: email.trim() || undefined,\n imageUrl: imageUrl || undefined,\n metadata,\n };\n\n const result = await onSubmit(feedbackData);\n setIsSubmitting(false);\n\n if (result) {\n setSuccess(true);\n } else {\n setError('Failed to submit. Please try again.');\n }\n };\n\n // 스타일 함수 (primaryColor 적용)\n const getStyles = () => {\n const primaryBgLight = `${primaryColor}15`;\n\n return {\n overlay: {\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.4)',\n backdropFilter: 'blur(4px)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 9999,\n padding: '20px',\n } as h.JSX.CSSProperties,\n\n modal: {\n backgroundColor: colors.bgCard,\n backdropFilter: 'blur(20px)',\n borderRadius: '20px',\n width: '100%',\n maxWidth: '580px',\n maxHeight: '90vh',\n overflowY: 'auto',\n position: 'relative',\n fontFamily: \"'Quicksand', 'Nunito', system-ui, sans-serif\",\n border: `1px solid ${colors.border}`,\n boxShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.15)',\n } as h.JSX.CSSProperties,\n\n colorBar: {\n height: '4px',\n backgroundColor: primaryColor,\n } as h.JSX.CSSProperties,\n\n header: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '14px 20px',\n borderBottom: `1px solid ${colors.border}`,\n backgroundColor: colors.bgLight,\n } as h.JSX.CSSProperties,\n\n headerIcon: {\n width: '32px',\n height: '32px',\n borderRadius: '10px',\n backgroundColor: primaryColor,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#fff',\n } as h.JSX.CSSProperties,\n\n typeButton: (active: boolean) => ({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '6px',\n padding: '10px 12px',\n border: active ? `2px solid ${primaryColor}` : `1px solid ${colors.border}`,\n borderRadius: '10px',\n backgroundColor: active ? primaryBgLight : colors.bgLight,\n cursor: 'pointer',\n fontWeight: 600,\n fontSize: '13px',\n color: active ? colors.text : colors.textMuted,\n transition: 'all 0.2s',\n } as h.JSX.CSSProperties),\n\n submitButton: (disabled: boolean) => ({\n width: '100%',\n padding: '12px',\n backgroundColor: disabled ? colors.bgLight : primaryColor,\n color: disabled ? colors.textMuted : '#fff',\n border: 'none',\n borderRadius: '12px',\n fontSize: '15px',\n fontWeight: 700,\n cursor: disabled ? 'not-allowed' : 'pointer',\n fontFamily: 'inherit',\n transition: 'all 0.2s',\n boxShadow: disabled ? 'none' : `0 4px 15px ${primaryColor}40`,\n } as h.JSX.CSSProperties),\n\n primaryButton: {\n width: '100%',\n padding: '16px',\n backgroundColor: primaryColor,\n color: '#fff',\n border: 'none',\n borderRadius: '12px',\n fontSize: '15px',\n fontWeight: 700,\n cursor: 'pointer',\n fontFamily: 'inherit',\n marginTop: '8px',\n } as h.JSX.CSSProperties,\n };\n };\n\n const styles = getStyles();\n\n // 성공 화면\n if (success) {\n return (\n <div style={styles.overlay}>\n <div style={styles.modal}>\n <div style={successContainerStyle}>\n <div style={successIconStyle}>\n <CheckIcon />\n </div>\n <h3 style={successTitleStyle}>{i18n.successMessage}</h3>\n <p style={successTextStyle}>Your voice shapes what we build next.</p>\n <button onClick={onClose} style={styles.primaryButton}>\n Done\n </button>\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div style={styles.overlay} onClick={onClose}>\n <div style={styles.modal} onClick={(e) => e.stopPropagation()}>\n {/* 헤더 */}\n <div style={styles.header}>\n <div style={headerLeftStyle}>\n <div style={styles.headerIcon}>\n <MessageIcon size={20} />\n </div>\n <span style={headerTitleStyle}>Help Us Improve</span>\n </div>\n <button onClick={onClose} style={closeButtonStyle}>\n <CloseIcon />\n </button>\n </div>\n\n {/* 컬러 바 */}\n <div style={styles.colorBar} />\n\n {/* 컨텐츠 */}\n <div style={contentStyle}>\n {/* 이슈 타입 */}\n <div style={sectionStyle}>\n <label style={labelStyle}>Feedback Type</label>\n <div style={typeButtonsStyle}>\n <button\n onClick={() => setLabel('bug')}\n style={styles.typeButton(label === 'bug')}\n >\n <span style={typeIconStyle(label === 'bug', 'bug')}>\n <BugIcon />\n </span>\n <span>Bug</span>\n </button>\n <button\n onClick={() => setLabel('feature')}\n style={styles.typeButton(label === 'feature')}\n >\n <span style={typeIconStyle(label === 'feature', 'feature')}>\n <LightbulbIcon />\n </span>\n <span>Feature</span>\n </button>\n </div>\n </div>\n\n {/* 설명 + 이미지 (flex row) */}\n <div style={descriptionRowStyle}>\n {/* 텍스트 영역 */}\n <div style={descriptionColStyle}>\n <label style={labelStyle}>Description</label>\n <div style={textareaWrapperStyle}>\n <textarea\n placeholder={currentPlaceholder}\n value={text}\n maxLength={maxLength}\n onInput={(e) => setText((e.target as HTMLTextAreaElement).value)}\n style={textareaStyle}\n />\n <span style={charCountStyle}>{text.length}/{maxLength}</span>\n </div>\n </div>\n\n {/* 이미지 업로드 (정사각형) */}\n <div style={uploadColStyle}>\n <label style={labelStyle}>Screenshot</label>\n {imagePreview ? (\n <div style={imagePreviewContainerStyle}>\n <img src={imagePreview} alt=\"Preview\" style={imagePreviewSquareStyle} />\n <button onClick={handleRemoveImage} style={removeImageButtonStyle}>\n <CloseIcon />\n </button>\n {isUploading && <div style={uploadingOverlayStyle}>...</div>}\n </div>\n ) : (\n <button\n onClick={() => fileInputRef.current?.click()}\n style={uploadButtonSquareStyle}\n >\n <ImageIcon />\n <span style={{ fontSize: '11px' }}>Upload</span>\n </button>\n )}\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n onChange={handleFileSelect}\n style={{ display: 'none' }}\n />\n </div>\n </div>\n\n {/* 이메일 */}\n {formFields.email.enabled && (\n <div style={sectionStyle}>\n <label style={labelStyle}>\n Email {formFields.email.required ? '' : '(optional)'}\n </label>\n <input\n type=\"email\"\n placeholder=\"your@email.com\"\n value={email}\n onInput={(e) => setEmail((e.target as HTMLInputElement).value)}\n style={inputStyle}\n />\n </div>\n )}\n\n {/* 에러 */}\n {error && <p style={errorStyle}>{error}</p>}\n\n {/* 제출 버튼 */}\n <button\n onClick={handleSubmit}\n disabled={isSubmitting || isUploading}\n style={styles.submitButton(isSubmitting || isUploading)}\n >\n {isSubmitting ? (\n <span style={spinnerContainerStyle}>\n <span className=\"voyage-spinner\" />\n Sending...\n </span>\n ) : (\n i18n.submitLabel\n )}\n </button>\n </div>\n </div>\n </div>\n );\n}\n\n// 이미지 처리 유틸: resize + WebP 변환\ninterface ProcessImageOptions {\n maxWidth: number;\n maxHeight: number;\n quality: number;\n}\n\nasync function processImage(file: File, options: ProcessImageOptions): Promise<File> {\n const { maxWidth, maxHeight, quality } = options;\n\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n // 비율 유지하면서 resize 계산\n let { width, height } = img;\n\n if (width > maxWidth || height > maxHeight) {\n const ratio = Math.min(maxWidth / width, maxHeight / height);\n width = Math.round(width * ratio);\n height = Math.round(height * ratio);\n }\n\n // Canvas에 그리기\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n reject(new Error('Failed to get canvas context'));\n return;\n }\n\n ctx.drawImage(img, 0, 0, width, height);\n\n // WebP로 변환\n canvas.toBlob(\n (blob) => {\n if (!blob) {\n reject(new Error('Failed to convert image'));\n return;\n }\n\n // Blob을 File로 변환\n const timestamp = Date.now();\n const newFile = new File([blob], `image_${timestamp}.webp`, {\n type: 'image/webp',\n });\n\n resolve(newFile);\n },\n 'image/webp',\n quality\n );\n };\n\n img.onerror = () => reject(new Error('Failed to load image'));\n img.src = URL.createObjectURL(file);\n });\n}\n\n// 정적 스타일 정의 (라이트 테마)\nconst headerLeftStyle: h.JSX.CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n};\n\nconst headerTitleStyle: h.JSX.CSSProperties = {\n fontSize: '16px',\n fontWeight: 700,\n color: colors.text,\n};\n\nconst closeButtonStyle: h.JSX.CSSProperties = {\n background: 'transparent',\n border: 'none',\n color: colors.textMuted,\n cursor: 'pointer',\n padding: '8px',\n borderRadius: '8px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n transition: 'all 0.2s',\n};\n\nconst contentStyle: h.JSX.CSSProperties = {\n padding: '16px 20px',\n};\n\nconst sectionStyle: h.JSX.CSSProperties = {\n marginBottom: '14px',\n};\n\nconst labelStyle: h.JSX.CSSProperties = {\n display: 'block',\n fontSize: '13px',\n fontWeight: 600,\n color: colors.text,\n marginBottom: '8px',\n};\n\nconst typeButtonsStyle: h.JSX.CSSProperties = {\n display: 'grid',\n gridTemplateColumns: '1fr 1fr',\n gap: '12px',\n};\n\nconst descriptionRowStyle: h.JSX.CSSProperties = {\n display: 'flex',\n gap: '14px',\n marginBottom: '14px',\n};\n\nconst descriptionColStyle: h.JSX.CSSProperties = {\n flex: 1,\n display: 'flex',\n flexDirection: 'column',\n};\n\nconst uploadColStyle: h.JSX.CSSProperties = {\n width: '120px',\n flexShrink: 0,\n display: 'flex',\n flexDirection: 'column',\n};\n\nconst uploadButtonSquareStyle: h.JSX.CSSProperties = {\n width: '100%',\n aspectRatio: '1',\n border: `2px dashed ${colors.border}`,\n borderRadius: '10px',\n backgroundColor: 'transparent',\n cursor: 'pointer',\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '4px',\n color: colors.textMuted,\n fontSize: '12px',\n transition: 'all 0.2s',\n};\n\nconst imagePreviewSquareStyle: h.JSX.CSSProperties = {\n width: '100%',\n aspectRatio: '1',\n objectFit: 'cover',\n borderRadius: '10px',\n};\n\nconst typeIconStyle = (active: boolean, type: 'bug' | 'feature'): h.JSX.CSSProperties => ({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: active\n ? (type === 'bug' ? colors.error : '#F59E0B')\n : colors.textMuted,\n});\n\nconst textareaWrapperStyle: h.JSX.CSSProperties = {\n position: 'relative',\n};\n\nconst textareaStyle: h.JSX.CSSProperties = {\n width: '100%',\n minHeight: '120px',\n padding: '14px',\n border: `1px solid ${colors.border}`,\n borderRadius: '12px',\n fontSize: '14px',\n resize: 'vertical',\n boxSizing: 'border-box',\n backgroundColor: colors.bgLight,\n color: colors.text,\n fontFamily: 'inherit',\n outline: 'none',\n};\n\nconst charCountStyle: h.JSX.CSSProperties = {\n position: 'absolute',\n bottom: '12px',\n right: '14px',\n fontSize: '12px',\n color: colors.textMuted,\n};\n\nconst inputStyle: h.JSX.CSSProperties = {\n width: '100%',\n padding: '10px 12px',\n border: `1px solid ${colors.border}`,\n borderRadius: '10px',\n fontSize: '13px',\n boxSizing: 'border-box',\n backgroundColor: colors.bgLight,\n color: colors.text,\n fontFamily: 'inherit',\n outline: 'none',\n};\n\nconst imagePreviewContainerStyle: h.JSX.CSSProperties = {\n position: 'relative',\n display: 'inline-block',\n borderRadius: '12px',\n overflow: 'hidden',\n};\n\nconst removeImageButtonStyle: h.JSX.CSSProperties = {\n position: 'absolute',\n top: '8px',\n right: '8px',\n width: '28px',\n height: '28px',\n borderRadius: '50%',\n backgroundColor: 'rgba(0, 0, 0, 0.7)',\n color: '#fff',\n border: 'none',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n};\n\nconst uploadingOverlayStyle: h.JSX.CSSProperties = {\n position: 'absolute',\n inset: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.7)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#fff',\n fontSize: '14px',\n borderRadius: '12px',\n};\n\nconst errorStyle: h.JSX.CSSProperties = {\n color: colors.error,\n fontSize: '14px',\n marginBottom: '16px',\n padding: '12px',\n backgroundColor: 'rgba(239, 68, 68, 0.1)',\n borderRadius: '8px',\n border: `1px solid rgba(239, 68, 68, 0.3)`,\n};\n\nconst successContainerStyle: h.JSX.CSSProperties = {\n padding: '48px 24px',\n textAlign: 'center',\n};\n\nconst successIconStyle: h.JSX.CSSProperties = {\n width: '64px',\n height: '64px',\n borderRadius: '50%',\n backgroundColor: 'rgba(34, 197, 94, 0.15)',\n color: colors.success,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n margin: '0 auto 20px',\n};\n\nconst successTitleStyle: h.JSX.CSSProperties = {\n fontSize: '20px',\n fontWeight: 700,\n color: colors.text,\n marginBottom: '8px',\n};\n\nconst successTextStyle: h.JSX.CSSProperties = {\n fontSize: '14px',\n color: colors.textMuted,\n marginBottom: '24px',\n};\n\nconst spinnerContainerStyle: h.JSX.CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '8px',\n};\n","import { h } from 'preact';\nimport { useState, useEffect } from 'preact/hooks';\nimport { Button } from './Button';\nimport { Modal } from './Modal';\nimport type { ProjectConfig, FeedbackData, FeedbackMetadata } from '../types';\n\ninterface WidgetProps {\n config: ProjectConfig;\n onSubmit: (data: FeedbackData) => Promise<boolean>;\n onUpload: (file: File) => Promise<string | null>;\n getMetadata: () => FeedbackMetadata;\n visible: boolean;\n defaultOpen?: boolean;\n hasError?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\nexport function Widget({\n config,\n onSubmit,\n onUpload,\n getMetadata,\n visible,\n defaultOpen = false,\n hasError = false,\n onOpenChange,\n}: WidgetProps) {\n const [isOpen, setIsOpen] = useState(defaultOpen);\n\n // SDK에서 open()/close() 호출 시 동기화\n useEffect(() => {\n setIsOpen(defaultOpen);\n }, [defaultOpen]);\n\n useEffect(() => {\n onOpenChange?.(isOpen);\n }, [isOpen, onOpenChange]);\n\n if (!visible) {\n return null;\n }\n\n const { theme, i18n } = config;\n\n return (\n <>\n {!isOpen && (\n <Button\n onClick={() => setIsOpen(true)}\n label={i18n.buttonLabel}\n position={theme.position}\n primaryColor={theme.primaryColor}\n hasError={hasError}\n />\n )}\n\n {isOpen && (\n <Modal\n config={config}\n metadata={getMetadata()}\n onClose={() => setIsOpen(false)}\n onSubmit={onSubmit}\n onUpload={onUpload}\n />\n )}\n </>\n );\n}\n","// SDK 전용 CSS 스타일 (동적 주입)\nexport const injectStyles = () => {\n if (typeof document === 'undefined') return;\n if (document.getElementById('voyage-sdk-styles')) return;\n\n const style = document.createElement('style');\n style.id = 'voyage-sdk-styles';\n style.textContent = `\n /* Voyage SDK Styles */\n\n /* Spinner Animation */\n @keyframes voyage-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n\n #voyage-widget-container * {\n box-sizing: border-box;\n }\n\n #voyage-widget-container button {\n font-family: 'Quicksand', 'Nunito', system-ui, sans-serif;\n }\n\n #voyage-widget-container textarea:focus,\n #voyage-widget-container input:focus {\n border-color: rgba(124, 58, 237, 0.5);\n box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);\n }\n\n #voyage-widget-container button:focus {\n outline: none;\n }\n\n /* Spinner */\n .voyage-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid rgba(255,255,255,0.3);\n border-top-color: #fff;\n border-radius: 50%;\n animation: voyage-spin 0.8s linear infinite;\n }\n\n /* Load Quicksand font if not present */\n @import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@400;500;600;700&display=swap');\n `;\n\n document.head.appendChild(style);\n};\n","import type { ProjectConfig, FeedbackData } from '../types';\n\n// Supabase Edge Functions URL\nconst API_BASE = 'https://rxflzurkkuqgopjkshjh.supabase.co/functions/v1';\n\nconst CACHE_KEY = 'voyage_config';\nconst CACHE_TTL = 60 * 60 * 1000; // 1시간\n\ninterface CachedConfig {\n config: ProjectConfig;\n timestamp: number;\n}\n\nexport async function fetchProjectConfig(sdkKey: string): Promise<ProjectConfig | null> {\n // 캐시 확인\n const cached = getFromCache(sdkKey);\n if (cached) {\n return cached;\n }\n\n try {\n const response = await fetch(`${API_BASE}/get-widget-config`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'x-sdk-key': sdkKey,\n },\n });\n\n if (!response.ok) {\n console.error('[Voyage] Failed to fetch config:', response.status);\n return null;\n }\n\n const config = await response.json() as ProjectConfig;\n saveToCache(sdkKey, config);\n return config;\n } catch (error) {\n console.error('[Voyage] Network error:', error);\n // 네트워크 실패 시 캐시 사용 (만료되어도)\n return getFromCache(sdkKey, true);\n }\n}\n\nexport async function submitFeedback(sdkKey: string, data: FeedbackData): Promise<boolean> {\n try {\n const response = await fetch(`${API_BASE}/submit-feedback`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-sdk-key': sdkKey,\n },\n body: JSON.stringify({\n label: data.label,\n content: data.text,\n email: data.email,\n imageUrl: data.imageUrl,\n metadata: data.metadata,\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n console.error('[Voyage] Failed to submit feedback:', response.status, errorData);\n return false;\n }\n\n return true;\n } catch (error) {\n console.error('[Voyage] Network error:', error);\n return false;\n }\n}\n\nexport async function uploadImage(sdkKey: string, file: File): Promise<string | null> {\n // 검증\n if (!file.type.startsWith('image/')) {\n console.error('[Voyage] Only image files are allowed');\n return null;\n }\n\n if (file.size > 5 * 1024 * 1024) {\n console.error('[Voyage] Image must be under 5MB');\n return null;\n }\n\n try {\n const formData = new FormData();\n formData.append('file', file);\n\n const response = await fetch(`${API_BASE}/upload-feedback-image`, {\n method: 'POST',\n headers: {\n 'x-sdk-key': sdkKey,\n },\n body: formData,\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n console.error('[Voyage] Failed to upload image:', response.status, errorData);\n return null;\n }\n\n const result = await response.json();\n return result.url;\n } catch (error) {\n console.error('[Voyage] Network error:', error);\n return null;\n }\n}\n\nfunction getFromCache(sdkKey: string, ignoreExpiry = false): ProjectConfig | null {\n try {\n const raw = localStorage.getItem(`${CACHE_KEY}_${sdkKey}`);\n if (!raw) return null;\n\n const cached: CachedConfig = JSON.parse(raw);\n const isExpired = Date.now() - cached.timestamp > CACHE_TTL;\n\n if (isExpired && !ignoreExpiry) {\n return null;\n }\n\n return cached.config;\n } catch {\n return null;\n }\n}\n\nfunction saveToCache(sdkKey: string, config: ProjectConfig): void {\n try {\n const cached: CachedConfig = {\n config,\n timestamp: Date.now(),\n };\n localStorage.setItem(`${CACHE_KEY}_${sdkKey}`, JSON.stringify(cached));\n } catch {\n // localStorage 사용 불가 시 무시\n }\n}\n","import type { FeedbackMetadata } from '../types';\n\nexport function captureMetadata(): FeedbackMetadata {\n return {\n url: window.location.href,\n pathname: window.location.pathname,\n browser: navigator.userAgent,\n viewport: `${window.innerWidth}x${window.innerHeight}`,\n title: document.title,\n timestamp: new Date().toISOString(),\n locale: navigator.language,\n referrer: document.referrer,\n };\n}\n","// @voyage/sdk\n// Feedback Widget SDK for collecting user feedback\n\nimport { h, render } from 'preact';\n\nimport { Widget } from './components';\nimport { injectStyles } from './styles';\nimport { fetchProjectConfig, submitFeedback, uploadImage } from './utils/api';\nimport { captureMetadata } from './utils/metadata';\n\nimport type { VoyageConfig, ProjectConfig, FeedbackData } from './types';\n\nexport type { VoyageConfig, ProjectConfig, FeedbackData, FeedbackMetadata } from './types';\n\nconst DEFAULT_CONFIG: ProjectConfig = {\n projectId: '',\n formFields: {\n email: { enabled: true, required: false },\n category: { enabled: true, options: ['bug', 'feature'] },\n },\n theme: {\n primaryColor: '#0ea5e9',\n position: 'bottom-right',\n },\n i18n: {\n buttonLabel: 'To : the Maker',\n placeholder: 'Describe your ideas to improve our product',\n bugPlaceholder: 'Please describe the bug in detail (e.g., clicked a button and it didn\\'t work)',\n featurePlaceholder: 'Describe your ideas to improve our product (e.g., I want to export TASK.md to Linear tickets)',\n submitLabel: 'Send to the Maker',\n successMessage: 'Thank you for your feedback!',\n },\n};\n\nclass VoyageSDK {\n private config: VoyageConfig | null = null;\n private serverConfig: ProjectConfig | null = null;\n private container: HTMLElement | null = null;\n private isWidgetVisible = false;\n private isModalOpen = false;\n private hasInitError = false;\n\n async init(config: VoyageConfig): Promise<void> {\n this.config = config;\n this.hasInitError = false;\n\n if (!config.sdkKey) {\n console.error('[Voyage] SDK Key is required. Get your key from the dashboard.');\n this.hasInitError = true;\n injectStyles();\n this.isWidgetVisible = true;\n this.serverConfig = { ...DEFAULT_CONFIG };\n this.renderWidget();\n return;\n }\n\n // Inject SDK styles\n injectStyles();\n\n // Check display control\n if (!this.shouldDisplay()) {\n console.log('[Voyage] Widget hidden by display rules');\n return;\n }\n\n // Fetch server config\n const fetchedConfig = await fetchProjectConfig(config.sdkKey);\n\n if (!fetchedConfig) {\n console.error('[Voyage] Failed to fetch config. Check your SDK Key or network connection.');\n this.hasInitError = true;\n this.serverConfig = { ...DEFAULT_CONFIG };\n this.isWidgetVisible = true;\n this.renderWidget();\n return;\n }\n\n this.serverConfig = this.mergeConfig(fetchedConfig, config);\n\n // Render widget\n this.isWidgetVisible = true;\n this.renderWidget();\n console.log('[Voyage] Initialized');\n }\n\n show(): void {\n if (!this.config) {\n console.warn('[Voyage] SDK not initialized');\n return;\n }\n this.isWidgetVisible = true;\n this.renderWidget();\n }\n\n hide(): void {\n this.isWidgetVisible = false;\n this.renderWidget();\n }\n\n open(): void {\n if (!this.config) {\n console.warn('[Voyage] SDK not initialized');\n return;\n }\n this.isModalOpen = true;\n this.renderWidget();\n }\n\n close(): void {\n this.isModalOpen = false;\n this.renderWidget();\n }\n\n isOpen(): boolean {\n return this.isModalOpen;\n }\n\n isVisible(): boolean {\n return this.isWidgetVisible;\n }\n\n async refreshConfig(): Promise<void> {\n if (!this.config) return;\n const fetchedConfig = await fetchProjectConfig(this.config.sdkKey);\n this.serverConfig = this.mergeConfig(fetchedConfig, this.config);\n this.renderWidget();\n }\n\n destroy(): void {\n if (this.container) {\n render(null, this.container);\n this.container.remove();\n this.container = null;\n }\n this.config = null;\n this.serverConfig = null;\n this.isWidgetVisible = false;\n this.isModalOpen = false;\n }\n\n private renderWidget(): void {\n if (!this.serverConfig || !this.config) return;\n\n // Create container if not exists\n if (!this.container) {\n this.container = document.createElement('div');\n this.container.id = 'voyage-widget-container';\n document.body.appendChild(this.container);\n }\n\n const sdkKey = this.config.sdkKey;\n\n render(\n h(Widget, {\n config: this.serverConfig,\n visible: this.isWidgetVisible,\n defaultOpen: this.isModalOpen,\n hasError: this.hasInitError,\n onOpenChange: (open: boolean) => {\n this.isModalOpen = open;\n },\n getMetadata: captureMetadata,\n onSubmit: async (data: FeedbackData) => {\n return submitFeedback(sdkKey, data);\n },\n onUpload: async (file: File) => {\n return uploadImage(sdkKey, file);\n },\n }),\n this.container\n );\n }\n\n private mergeConfig(server: ProjectConfig | null, _client: VoyageConfig): ProjectConfig {\n // Server config takes priority: use values set from dashboard\n // Client-side theme override disabled (to prevent config conflicts)\n return server || { ...DEFAULT_CONFIG };\n }\n\n private shouldDisplay(): boolean {\n if (!this.config) return false;\n\n const pathname = window.location.pathname;\n const { include, exclude } = this.config;\n\n // include takes priority over exclude\n if (include && include.length > 0) {\n return include.some((pattern) => this.matchPath(pathname, pattern));\n }\n\n if (exclude && exclude.length > 0) {\n return !exclude.some((pattern) => this.matchPath(pathname, pattern));\n }\n\n return true;\n }\n\n private matchPath(pathname: string, pattern: string): boolean {\n // Simple glob matching: /admin/* matches /admin/anything\n if (pattern.endsWith('/*')) {\n const prefix = pattern.slice(0, -2);\n return pathname.startsWith(prefix);\n }\n return pathname === pattern;\n }\n}\n\n// Singleton instance\nconst Voyage = new VoyageSDK();\n\nexport { Voyage };\nexport default Voyage;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/Button.tsx","../src/components/Modal.tsx","../src/components/Widget.tsx","../src/styles.ts","../src/utils/api.ts","../src/utils/metadata.ts","../src/index.ts"],"names":["MessageIcon","jsx","Button","onClick","label","position","primaryColor","hasError","isHovered","setIsHovered","useState","isPressed","setIsPressed","positionStyle","getTransform","jsxs","size","BugIcon","LightbulbIcon","ImageIcon","CloseIcon","CheckIcon","colors","Modal","config","metadata","onClose","onSubmit","onUpload","setLabel","text","setText","email","setEmail","imageUrl","setImageUrl","imagePreview","setImagePreview","isSubmitting","setIsSubmitting","isUploading","setIsUploading","error","setError","success","setSuccess","fileInputRef","useRef","i18n","formFields","theme","maxLength","currentPlaceholder","handleFileSelect","e","file","processedFile","processImage","reader","url","err","handleRemoveImage","handleSubmit","feedbackData","result","styles","primaryBgLight","active","disabled","successContainerStyle","successIconStyle","successTitleStyle","successTextStyle","headerLeftStyle","headerTitleStyle","closeButtonStyle","contentStyle","sectionStyle","labelStyle","typeButtonsStyle","typeIconStyle","descriptionRowStyle","descriptionColStyle","textareaWrapperStyle","textareaStyle","charCountStyle","uploadColStyle","imagePreviewContainerStyle","imagePreviewSquareStyle","removeImageButtonStyle","uploadingOverlayStyle","uploadButtonSquareStyle","inputStyle","errorStyle","spinnerContainerStyle","options","maxWidth","maxHeight","quality","resolve","reject","img","width","height","ratio","canvas","ctx","blob","timestamp","newFile","type","Widget","getMetadata","visible","defaultOpen","onOpenChange","isOpen","setIsOpen","useEffect","Fragment","injectStyles","style","API_BASE","CACHE_KEY","fetchWithTimeout","timeoutMs","controller","timeoutId","fetchProjectConfig","sdkKey","forceRefresh","cached","getFromCache","response","saveToCache","submitFeedback","data","errorData","uploadImage","formData","getCachedConfig","ignoreExpiry","raw","captureMetadata","DEFAULT_CONFIG","VoyageSDK","cachedConfig","fetchedConfig","freshConfig","newConfig","render","h","open","server","_client","pathname","include","exclude","pattern","prefix","Voyage","index_default"],"mappings":"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","file":"index.cjs","sourcesContent":["import { h } from 'preact';\nimport { useState } from 'preact/hooks';\n\ninterface ButtonProps {\n onClick: () => void;\n label: string;\n position: 'bottom-right' | 'bottom-left';\n primaryColor: string;\n hasError?: boolean;\n}\n\n// 말풍선 아이콘 SVG\nfunction MessageIcon() {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n );\n}\n\n// 에러 아이콘 (느낌표)\nfunction ErrorIcon() {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"#fff\"\n stroke=\"none\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"12\" fill=\"#EF4444\" />\n <text x=\"12\" y=\"17\" textAnchor=\"middle\" fill=\"#fff\" fontSize=\"14\" fontWeight=\"bold\">!</text>\n </svg>\n );\n}\n\nexport function Button({ onClick, label, position, primaryColor, hasError = false }: ButtonProps) {\n const [isHovered, setIsHovered] = useState(false);\n const [isPressed, setIsPressed] = useState(false);\n\n const positionStyle = position === 'bottom-right'\n ? { right: '24px' }\n : { left: '24px' };\n\n // Jelly 효과 transform\n const getTransform = () => {\n if (isPressed) return 'scale(0.95)';\n if (isHovered) return 'scale(1.02) translateY(-2px)';\n return 'scale(1)';\n };\n\n return (\n <div style={{ position: 'fixed', bottom: '24px', ...positionStyle, zIndex: 9998 }}>\n <button\n onClick={onClick}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => { setIsHovered(false); setIsPressed(false); }}\n onMouseDown={() => setIsPressed(true)}\n onMouseUp={() => setIsPressed(false)}\n style={{\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n padding: '14px 24px',\n border: 'none',\n borderRadius: '50px',\n cursor: 'pointer',\n fontFamily: \"'Quicksand', 'Nunito', system-ui, sans-serif\",\n fontSize: '15px',\n fontWeight: 600,\n color: '#fff',\n // primaryColor 적용\n backgroundColor: primaryColor,\n // 그림자 + glow 효과\n boxShadow: isHovered\n ? `0 8px 32px ${primaryColor}60, 0 0 20px ${primaryColor}40`\n : `0 4px 20px ${primaryColor}50, 0 0 10px ${primaryColor}30`,\n // Jelly 애니메이션\n transform: getTransform(),\n transition: 'all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1)',\n }}\n >\n <MessageIcon />\n <span>{label}</span>\n </button>\n {/* 에러 아이콘 - 우측 상단 */}\n {hasError && (\n <div\n style={{\n position: 'absolute',\n top: '-4px',\n right: '-4px',\n width: '18px',\n height: '18px',\n borderRadius: '50%',\n backgroundColor: '#EF4444',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#fff',\n fontSize: '12px',\n fontWeight: 'bold',\n boxShadow: '0 2px 6px rgba(239, 68, 68, 0.5)',\n }}\n >\n !\n </div>\n )}\n </div>\n );\n}\n","import { h } from 'preact';\nimport { useRef, useState } from 'preact/hooks';\n\nimport type { ProjectConfig, FeedbackData, FeedbackMetadata } from '../types';\n\ninterface ModalProps {\n config: ProjectConfig;\n metadata: FeedbackMetadata;\n onClose: () => void;\n onSubmit: (data: FeedbackData) => Promise<boolean>;\n onUpload: (file: File) => Promise<string | null>;\n}\n\n// 아이콘들\nfunction MessageIcon({ size = 24 }: { size?: number }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n );\n}\n\nfunction BugIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M8 2l1.88 1.88M14.12 3.88L16 2M9 7.13v-1a3.003 3.003 0 116 0v1\" />\n <path d=\"M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 014-4h4a4 4 0 014 4v3c0 3.3-2.7 6-6 6\" />\n <path d=\"M12 20v-9M6.53 9C4.6 8.8 3 7.1 3 5M6 13H2M6 17l-4 1M17.47 9c1.93-.2 3.53-1.9 3.53-4M18 13h4M18 17l4 1\" />\n </svg>\n );\n}\n\nfunction LightbulbIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 006 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\" />\n <path d=\"M9 18h6M10 22h4\" />\n </svg>\n );\n}\n\nfunction ImageIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\" />\n <polyline points=\"21 15 16 10 5 21\" />\n </svg>\n );\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\nfunction CheckIcon() {\n return (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n );\n}\n\n// 라이트 테마 색상\nconst colors = {\n bg: '#FFFFFF',\n bgLight: '#F8FAFC',\n bgCard: 'rgba(255, 255, 255, 0.98)',\n border: 'rgba(0, 0, 0, 0.08)',\n borderLight: 'rgba(0, 0, 0, 0.12)',\n text: '#1F2937',\n textMuted: '#6B7280',\n error: '#EF4444',\n success: '#22C55E',\n};\n\nexport function Modal({ config, metadata, onClose, onSubmit, onUpload }: ModalProps) {\n const [label, setLabel] = useState<'bug' | 'feature' | null>(null);\n const [text, setText] = useState('');\n const [email, setEmail] = useState('');\n const [imageUrl, setImageUrl] = useState<string | null>(null);\n const [imagePreview, setImagePreview] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [isUploading, setIsUploading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [success, setSuccess] = useState(false);\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const { i18n, formFields, theme } = config;\n const primaryColor = theme.primaryColor || '#0ea5e9';\n const maxLength = 400;\n\n // 동적 placeholder\n const currentPlaceholder = label === 'bug'\n ? (i18n.bugPlaceholder || i18n.placeholder)\n : (i18n.featurePlaceholder || i18n.placeholder);\n\n const handleFileSelect = async (e: Event) => {\n const target = e.target as HTMLInputElement;\n const file = target.files?.[0];\n if (!file) return;\n\n if (!file.type.startsWith('image/')) {\n setError('Only image files are allowed');\n return;\n }\n if (file.size > 10 * 1024 * 1024) {\n setError('Image must be under 10MB');\n return;\n }\n\n setIsUploading(true);\n setError(null);\n\n try {\n // 이미지를 WebP로 변환 및 resize\n const processedFile = await processImage(file, {\n maxWidth: 1920,\n maxHeight: 1080,\n quality: 0.8,\n });\n\n // 프리뷰 생성\n const reader = new FileReader();\n reader.onload = () => setImagePreview(reader.result as string);\n reader.readAsDataURL(processedFile);\n\n const url = await onUpload(processedFile);\n setIsUploading(false);\n\n if (url) {\n setImageUrl(url);\n } else {\n setError('Failed to upload image');\n setImagePreview(null);\n }\n } catch (err) {\n console.error('[Voyage] Image processing error:', err);\n setIsUploading(false);\n setError('Failed to process image');\n }\n };\n\n const handleRemoveImage = () => {\n setImageUrl(null);\n setImagePreview(null);\n if (fileInputRef.current) {\n fileInputRef.current.value = '';\n }\n };\n\n const handleSubmit = async () => {\n if (!label) {\n setError('Please select a type');\n return;\n }\n if (!text.trim()) {\n setError('Please enter your feedback');\n return;\n }\n if (formFields.email.required && !email.trim()) {\n setError('Please enter your email');\n return;\n }\n\n setIsSubmitting(true);\n setError(null);\n\n const feedbackData: FeedbackData = {\n label,\n text: text.trim(),\n email: email.trim() || undefined,\n imageUrl: imageUrl || undefined,\n metadata,\n };\n\n const result = await onSubmit(feedbackData);\n setIsSubmitting(false);\n\n if (result) {\n setSuccess(true);\n } else {\n setError('Failed to submit. Please try again.');\n }\n };\n\n // 스타일 함수 (primaryColor 적용)\n const getStyles = () => {\n const primaryBgLight = `${primaryColor}15`;\n\n return {\n overlay: {\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.4)',\n backdropFilter: 'blur(4px)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 9999,\n padding: '20px',\n } as h.JSX.CSSProperties,\n\n modal: {\n backgroundColor: colors.bgCard,\n backdropFilter: 'blur(20px)',\n borderRadius: '20px',\n width: '100%',\n maxWidth: '580px',\n maxHeight: '90vh',\n overflowY: 'auto',\n position: 'relative',\n fontFamily: \"'Quicksand', 'Nunito', system-ui, sans-serif\",\n border: `1px solid ${colors.border}`,\n boxShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.15)',\n } as h.JSX.CSSProperties,\n\n colorBar: {\n height: '4px',\n backgroundColor: primaryColor,\n } as h.JSX.CSSProperties,\n\n header: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '14px 20px',\n borderBottom: `1px solid ${colors.border}`,\n backgroundColor: colors.bgLight,\n } as h.JSX.CSSProperties,\n\n headerIcon: {\n width: '32px',\n height: '32px',\n borderRadius: '10px',\n backgroundColor: primaryColor,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#fff',\n } as h.JSX.CSSProperties,\n\n typeButton: (active: boolean) => ({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '6px',\n padding: '10px 12px',\n border: active ? `2px solid ${primaryColor}` : `1px solid ${colors.border}`,\n borderRadius: '10px',\n backgroundColor: active ? primaryBgLight : colors.bgLight,\n cursor: 'pointer',\n fontWeight: 600,\n fontSize: '13px',\n color: active ? colors.text : colors.textMuted,\n transition: 'all 0.2s',\n } as h.JSX.CSSProperties),\n\n submitButton: (disabled: boolean) => ({\n width: '100%',\n padding: '12px',\n backgroundColor: disabled ? colors.bgLight : primaryColor,\n color: disabled ? colors.textMuted : '#fff',\n border: 'none',\n borderRadius: '12px',\n fontSize: '15px',\n fontWeight: 700,\n cursor: disabled ? 'not-allowed' : 'pointer',\n fontFamily: 'inherit',\n transition: 'all 0.2s',\n boxShadow: disabled ? 'none' : `0 4px 15px ${primaryColor}40`,\n } as h.JSX.CSSProperties),\n\n primaryButton: {\n width: '100%',\n padding: '16px',\n backgroundColor: primaryColor,\n color: '#fff',\n border: 'none',\n borderRadius: '12px',\n fontSize: '15px',\n fontWeight: 700,\n cursor: 'pointer',\n fontFamily: 'inherit',\n marginTop: '8px',\n } as h.JSX.CSSProperties,\n };\n };\n\n const styles = getStyles();\n\n // 성공 화면\n if (success) {\n return (\n <div style={styles.overlay}>\n <div style={styles.modal}>\n <div style={successContainerStyle}>\n <div style={successIconStyle}>\n <CheckIcon />\n </div>\n <h3 style={successTitleStyle}>{i18n.successMessage}</h3>\n <p style={successTextStyle}>Your voice shapes what we build next.</p>\n <button onClick={onClose} style={styles.primaryButton}>\n Done\n </button>\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div style={styles.overlay} onClick={onClose}>\n <div style={styles.modal} onClick={(e) => e.stopPropagation()}>\n {/* 헤더 */}\n <div style={styles.header}>\n <div style={headerLeftStyle}>\n <div style={styles.headerIcon}>\n <MessageIcon size={20} />\n </div>\n <span style={headerTitleStyle}>Help Us Improve</span>\n </div>\n <button onClick={onClose} style={closeButtonStyle}>\n <CloseIcon />\n </button>\n </div>\n\n {/* 컬러 바 */}\n <div style={styles.colorBar} />\n\n {/* 컨텐츠 */}\n <div style={contentStyle}>\n {/* 이슈 타입 */}\n <div style={sectionStyle}>\n <label style={labelStyle}>Feedback Type</label>\n <div style={typeButtonsStyle}>\n <button\n onClick={() => setLabel('bug')}\n style={styles.typeButton(label === 'bug')}\n >\n <span style={typeIconStyle(label === 'bug', 'bug')}>\n <BugIcon />\n </span>\n <span>Bug</span>\n </button>\n <button\n onClick={() => setLabel('feature')}\n style={styles.typeButton(label === 'feature')}\n >\n <span style={typeIconStyle(label === 'feature', 'feature')}>\n <LightbulbIcon />\n </span>\n <span>Feature</span>\n </button>\n </div>\n </div>\n\n {/* 설명 + 이미지 (flex row) */}\n <div style={descriptionRowStyle}>\n {/* 텍스트 영역 */}\n <div style={descriptionColStyle}>\n <label style={labelStyle}>Description</label>\n <div style={textareaWrapperStyle}>\n <textarea\n placeholder={currentPlaceholder}\n value={text}\n maxLength={maxLength}\n onInput={(e) => setText((e.target as HTMLTextAreaElement).value)}\n style={textareaStyle}\n />\n <span style={charCountStyle}>{text.length}/{maxLength}</span>\n </div>\n </div>\n\n {/* 이미지 업로드 (정사각형) */}\n <div style={uploadColStyle}>\n <label style={labelStyle}>Screenshot</label>\n {imagePreview ? (\n <div style={imagePreviewContainerStyle}>\n <img src={imagePreview} alt=\"Preview\" style={imagePreviewSquareStyle} />\n <button onClick={handleRemoveImage} style={removeImageButtonStyle}>\n <CloseIcon />\n </button>\n {isUploading && <div style={uploadingOverlayStyle}>...</div>}\n </div>\n ) : (\n <button\n onClick={() => fileInputRef.current?.click()}\n style={uploadButtonSquareStyle}\n >\n <ImageIcon />\n <span style={{ fontSize: '11px' }}>Upload</span>\n </button>\n )}\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n onChange={handleFileSelect}\n style={{ display: 'none' }}\n />\n </div>\n </div>\n\n {/* 이메일 */}\n {formFields.email.enabled && (\n <div style={sectionStyle}>\n <label style={labelStyle}>\n Email {formFields.email.required ? '' : '(optional)'}\n </label>\n <input\n type=\"email\"\n placeholder=\"your@email.com\"\n value={email}\n onInput={(e) => setEmail((e.target as HTMLInputElement).value)}\n style={inputStyle}\n />\n </div>\n )}\n\n {/* 에러 */}\n {error && <p style={errorStyle}>{error}</p>}\n\n {/* 제출 버튼 */}\n <button\n onClick={handleSubmit}\n disabled={isSubmitting || isUploading}\n style={styles.submitButton(isSubmitting || isUploading)}\n >\n {isSubmitting ? (\n <span style={spinnerContainerStyle}>\n <span className=\"voyage-spinner\" />\n Sending...\n </span>\n ) : (\n i18n.submitLabel\n )}\n </button>\n </div>\n </div>\n </div>\n );\n}\n\n// 이미지 처리 유틸: resize + WebP 변환\ninterface ProcessImageOptions {\n maxWidth: number;\n maxHeight: number;\n quality: number;\n}\n\nasync function processImage(file: File, options: ProcessImageOptions): Promise<File> {\n const { maxWidth, maxHeight, quality } = options;\n\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n // 비율 유지하면서 resize 계산\n let { width, height } = img;\n\n if (width > maxWidth || height > maxHeight) {\n const ratio = Math.min(maxWidth / width, maxHeight / height);\n width = Math.round(width * ratio);\n height = Math.round(height * ratio);\n }\n\n // Canvas에 그리기\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n reject(new Error('Failed to get canvas context'));\n return;\n }\n\n ctx.drawImage(img, 0, 0, width, height);\n\n // WebP로 변환\n canvas.toBlob(\n (blob) => {\n if (!blob) {\n reject(new Error('Failed to convert image'));\n return;\n }\n\n // Blob을 File로 변환\n const timestamp = Date.now();\n const newFile = new File([blob], `image_${timestamp}.webp`, {\n type: 'image/webp',\n });\n\n resolve(newFile);\n },\n 'image/webp',\n quality\n );\n };\n\n img.onerror = () => reject(new Error('Failed to load image'));\n img.src = URL.createObjectURL(file);\n });\n}\n\n// 정적 스타일 정의 (라이트 테마)\nconst headerLeftStyle: h.JSX.CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n};\n\nconst headerTitleStyle: h.JSX.CSSProperties = {\n fontSize: '16px',\n fontWeight: 700,\n color: colors.text,\n};\n\nconst closeButtonStyle: h.JSX.CSSProperties = {\n background: 'transparent',\n border: 'none',\n color: colors.textMuted,\n cursor: 'pointer',\n padding: '8px',\n borderRadius: '8px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n transition: 'all 0.2s',\n};\n\nconst contentStyle: h.JSX.CSSProperties = {\n padding: '16px 20px',\n};\n\nconst sectionStyle: h.JSX.CSSProperties = {\n marginBottom: '14px',\n};\n\nconst labelStyle: h.JSX.CSSProperties = {\n display: 'block',\n fontSize: '13px',\n fontWeight: 600,\n color: colors.text,\n marginBottom: '8px',\n};\n\nconst typeButtonsStyle: h.JSX.CSSProperties = {\n display: 'grid',\n gridTemplateColumns: '1fr 1fr',\n gap: '12px',\n};\n\nconst descriptionRowStyle: h.JSX.CSSProperties = {\n display: 'flex',\n gap: '14px',\n marginBottom: '14px',\n};\n\nconst descriptionColStyle: h.JSX.CSSProperties = {\n flex: 1,\n display: 'flex',\n flexDirection: 'column',\n};\n\nconst uploadColStyle: h.JSX.CSSProperties = {\n width: '120px',\n flexShrink: 0,\n display: 'flex',\n flexDirection: 'column',\n};\n\nconst uploadButtonSquareStyle: h.JSX.CSSProperties = {\n width: '100%',\n aspectRatio: '1',\n border: `2px dashed ${colors.border}`,\n borderRadius: '10px',\n backgroundColor: 'transparent',\n cursor: 'pointer',\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '4px',\n color: colors.textMuted,\n fontSize: '12px',\n transition: 'all 0.2s',\n};\n\nconst imagePreviewSquareStyle: h.JSX.CSSProperties = {\n width: '100%',\n aspectRatio: '1',\n objectFit: 'cover',\n borderRadius: '10px',\n};\n\nconst typeIconStyle = (active: boolean, type: 'bug' | 'feature'): h.JSX.CSSProperties => ({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: active\n ? (type === 'bug' ? colors.error : '#F59E0B')\n : colors.textMuted,\n});\n\nconst textareaWrapperStyle: h.JSX.CSSProperties = {\n position: 'relative',\n};\n\nconst textareaStyle: h.JSX.CSSProperties = {\n width: '100%',\n minHeight: '120px',\n padding: '14px',\n border: `1px solid ${colors.border}`,\n borderRadius: '12px',\n fontSize: '14px',\n resize: 'vertical',\n boxSizing: 'border-box',\n backgroundColor: colors.bgLight,\n color: colors.text,\n fontFamily: 'inherit',\n outline: 'none',\n};\n\nconst charCountStyle: h.JSX.CSSProperties = {\n position: 'absolute',\n bottom: '12px',\n right: '14px',\n fontSize: '12px',\n color: colors.textMuted,\n};\n\nconst inputStyle: h.JSX.CSSProperties = {\n width: '100%',\n padding: '10px 12px',\n border: `1px solid ${colors.border}`,\n borderRadius: '10px',\n fontSize: '13px',\n boxSizing: 'border-box',\n backgroundColor: colors.bgLight,\n color: colors.text,\n fontFamily: 'inherit',\n outline: 'none',\n};\n\nconst imagePreviewContainerStyle: h.JSX.CSSProperties = {\n position: 'relative',\n display: 'inline-block',\n borderRadius: '12px',\n overflow: 'hidden',\n};\n\nconst removeImageButtonStyle: h.JSX.CSSProperties = {\n position: 'absolute',\n top: '8px',\n right: '8px',\n width: '28px',\n height: '28px',\n borderRadius: '50%',\n backgroundColor: 'rgba(0, 0, 0, 0.7)',\n color: '#fff',\n border: 'none',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n};\n\nconst uploadingOverlayStyle: h.JSX.CSSProperties = {\n position: 'absolute',\n inset: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.7)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#fff',\n fontSize: '14px',\n borderRadius: '12px',\n};\n\nconst errorStyle: h.JSX.CSSProperties = {\n color: colors.error,\n fontSize: '14px',\n marginBottom: '16px',\n padding: '12px',\n backgroundColor: 'rgba(239, 68, 68, 0.1)',\n borderRadius: '8px',\n border: `1px solid rgba(239, 68, 68, 0.3)`,\n};\n\nconst successContainerStyle: h.JSX.CSSProperties = {\n padding: '48px 24px',\n textAlign: 'center',\n};\n\nconst successIconStyle: h.JSX.CSSProperties = {\n width: '64px',\n height: '64px',\n borderRadius: '50%',\n backgroundColor: 'rgba(34, 197, 94, 0.15)',\n color: colors.success,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n margin: '0 auto 20px',\n};\n\nconst successTitleStyle: h.JSX.CSSProperties = {\n fontSize: '20px',\n fontWeight: 700,\n color: colors.text,\n marginBottom: '8px',\n};\n\nconst successTextStyle: h.JSX.CSSProperties = {\n fontSize: '14px',\n color: colors.textMuted,\n marginBottom: '24px',\n};\n\nconst spinnerContainerStyle: h.JSX.CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '8px',\n};\n","import { h } from 'preact';\nimport { useState, useEffect } from 'preact/hooks';\nimport { Button } from './Button';\nimport { Modal } from './Modal';\nimport type { ProjectConfig, FeedbackData, FeedbackMetadata } from '../types';\n\ninterface WidgetProps {\n config: ProjectConfig;\n onSubmit: (data: FeedbackData) => Promise<boolean>;\n onUpload: (file: File) => Promise<string | null>;\n getMetadata: () => FeedbackMetadata;\n visible: boolean;\n defaultOpen?: boolean;\n hasError?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\nexport function Widget({\n config,\n onSubmit,\n onUpload,\n getMetadata,\n visible,\n defaultOpen = false,\n hasError = false,\n onOpenChange,\n}: WidgetProps) {\n const [isOpen, setIsOpen] = useState(defaultOpen);\n\n // SDK에서 open()/close() 호출 시 동기화\n useEffect(() => {\n setIsOpen(defaultOpen);\n }, [defaultOpen]);\n\n useEffect(() => {\n onOpenChange?.(isOpen);\n }, [isOpen, onOpenChange]);\n\n if (!visible) {\n return null;\n }\n\n const { theme, i18n } = config;\n\n return (\n <>\n {!isOpen && (\n <Button\n onClick={() => setIsOpen(true)}\n label={i18n.buttonLabel}\n position={theme.position}\n primaryColor={theme.primaryColor}\n hasError={hasError}\n />\n )}\n\n {isOpen && (\n <Modal\n config={config}\n metadata={getMetadata()}\n onClose={() => setIsOpen(false)}\n onSubmit={onSubmit}\n onUpload={onUpload}\n />\n )}\n </>\n );\n}\n","// SDK 전용 CSS 스타일 (동적 주입)\nexport const injectStyles = () => {\n if (typeof document === 'undefined') return;\n if (document.getElementById('voyage-sdk-styles')) return;\n\n const style = document.createElement('style');\n style.id = 'voyage-sdk-styles';\n style.textContent = `\n /* Voyage SDK Styles */\n\n /* Spinner Animation */\n @keyframes voyage-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n\n #voyage-widget-container * {\n box-sizing: border-box;\n }\n\n #voyage-widget-container button {\n font-family: 'Quicksand', 'Nunito', system-ui, sans-serif;\n }\n\n #voyage-widget-container textarea:focus,\n #voyage-widget-container input:focus {\n border-color: rgba(124, 58, 237, 0.5);\n box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);\n }\n\n #voyage-widget-container button:focus {\n outline: none;\n }\n\n /* Spinner */\n .voyage-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid rgba(255,255,255,0.3);\n border-top-color: #fff;\n border-radius: 50%;\n animation: voyage-spin 0.8s linear infinite;\n }\n\n /* Load Quicksand font if not present */\n @import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@400;500;600;700&display=swap');\n `;\n\n document.head.appendChild(style);\n};\n","import type { ProjectConfig, FeedbackData } from '../types';\n\n// Supabase Edge Functions URL\nconst API_BASE = 'https://rxflzurkkuqgopjkshjh.supabase.co/functions/v1';\n\nconst CACHE_KEY = 'voyage_config';\nconst CACHE_TTL = 60 * 60 * 1000; // 1시간\n\n// Timeout constants\nconst CONFIG_TIMEOUT = 5000; // 5초\nconst SUBMIT_TIMEOUT = 10000; // 10초\nconst UPLOAD_TIMEOUT = 30000; // 30초 (큰 파일 고려)\n\n// Request timeout utility\nfunction fetchWithTimeout(\n url: string,\n options: RequestInit,\n timeoutMs: number\n): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n return fetch(url, { ...options, signal: controller.signal }).finally(() =>\n clearTimeout(timeoutId)\n );\n}\n\ninterface CachedConfig {\n config: ProjectConfig;\n timestamp: number;\n}\n\nexport async function fetchProjectConfig(\n sdkKey: string,\n options: { forceRefresh?: boolean } = {}\n): Promise<ProjectConfig | null> {\n const { forceRefresh = false } = options;\n\n // 캐시 확인 (forceRefresh가 아닐 때만)\n if (!forceRefresh) {\n const cached = getFromCache(sdkKey);\n if (cached) {\n return cached;\n }\n }\n\n try {\n const response = await fetchWithTimeout(\n `${API_BASE}/get-widget-config`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'x-sdk-key': sdkKey,\n },\n },\n CONFIG_TIMEOUT\n );\n\n if (!response.ok) {\n console.error('[Voyage] Failed to fetch config:', response.status);\n return getFromCache(sdkKey, true); // 실패 시 만료된 캐시라도 사용\n }\n\n const config = (await response.json()) as ProjectConfig;\n saveToCache(sdkKey, config);\n return config;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n console.warn('[Voyage] Config fetch timeout, using cached config');\n } else {\n console.error('[Voyage] Network error:', error);\n }\n // 네트워크 실패 시 캐시 사용 (만료되어도)\n return getFromCache(sdkKey, true);\n }\n}\n\nexport async function submitFeedback(sdkKey: string, data: FeedbackData): Promise<boolean> {\n try {\n const response = await fetchWithTimeout(\n `${API_BASE}/submit-feedback`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-sdk-key': sdkKey,\n },\n body: JSON.stringify({\n label: data.label,\n content: data.text,\n email: data.email,\n imageUrl: data.imageUrl,\n metadata: data.metadata,\n }),\n },\n SUBMIT_TIMEOUT\n );\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n console.error('[Voyage] Failed to submit feedback:', response.status, errorData);\n return false;\n }\n\n return true;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n console.error('[Voyage] Feedback submission timeout');\n } else {\n console.error('[Voyage] Network error:', error);\n }\n return false;\n }\n}\n\nexport async function uploadImage(sdkKey: string, file: File): Promise<string | null> {\n // 검증\n if (!file.type.startsWith('image/')) {\n console.error('[Voyage] Only image files are allowed');\n return null;\n }\n\n if (file.size > 5 * 1024 * 1024) {\n console.error('[Voyage] Image must be under 5MB');\n return null;\n }\n\n try {\n const formData = new FormData();\n formData.append('file', file);\n\n const response = await fetchWithTimeout(\n `${API_BASE}/upload-feedback-image`,\n {\n method: 'POST',\n headers: {\n 'x-sdk-key': sdkKey,\n },\n body: formData,\n },\n UPLOAD_TIMEOUT\n );\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n console.error('[Voyage] Failed to upload image:', response.status, errorData);\n return null;\n }\n\n const result = await response.json();\n return result.url;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n console.error('[Voyage] Image upload timeout');\n } else {\n console.error('[Voyage] Network error:', error);\n }\n return null;\n }\n}\n\n// Export for optimistic loading\nexport function getCachedConfig(sdkKey: string): ProjectConfig | null {\n return getFromCache(sdkKey, true); // 만료되어도 반환\n}\n\nfunction getFromCache(sdkKey: string, ignoreExpiry = false): ProjectConfig | null {\n try {\n const raw = localStorage.getItem(`${CACHE_KEY}_${sdkKey}`);\n if (!raw) return null;\n\n const cached: CachedConfig = JSON.parse(raw);\n const isExpired = Date.now() - cached.timestamp > CACHE_TTL;\n\n if (isExpired && !ignoreExpiry) {\n return null;\n }\n\n return cached.config;\n } catch {\n return null;\n }\n}\n\nfunction saveToCache(sdkKey: string, config: ProjectConfig): void {\n try {\n const cached: CachedConfig = {\n config,\n timestamp: Date.now(),\n };\n localStorage.setItem(`${CACHE_KEY}_${sdkKey}`, JSON.stringify(cached));\n } catch {\n // localStorage 사용 불가 시 무시\n }\n}\n","import type { FeedbackMetadata } from '../types';\n\nexport function captureMetadata(): FeedbackMetadata {\n return {\n url: window.location.href,\n pathname: window.location.pathname,\n browser: navigator.userAgent,\n viewport: `${window.innerWidth}x${window.innerHeight}`,\n title: document.title,\n timestamp: new Date().toISOString(),\n locale: navigator.language,\n referrer: document.referrer,\n };\n}\n","// @voyage/sdk\n// Feedback Widget SDK for collecting user feedback\n\nimport { h, render } from 'preact';\n\nimport { Widget } from './components';\nimport { injectStyles } from './styles';\nimport {\n fetchProjectConfig,\n getCachedConfig,\n submitFeedback,\n uploadImage,\n} from './utils/api';\nimport { captureMetadata } from './utils/metadata';\n\nimport type { VoyageConfig, ProjectConfig, FeedbackData } from './types';\n\nexport type { VoyageConfig, ProjectConfig, FeedbackData, FeedbackMetadata } from './types';\n\nconst DEFAULT_CONFIG: ProjectConfig = {\n projectId: '',\n formFields: {\n email: { enabled: true, required: false },\n category: { enabled: true, options: ['bug', 'feature'] },\n },\n theme: {\n primaryColor: '#0ea5e9',\n position: 'bottom-right',\n },\n i18n: {\n buttonLabel: 'To : the Maker',\n placeholder: 'Describe your ideas to improve our product',\n bugPlaceholder: 'Please describe the bug in detail (e.g., clicked a button and it didn\\'t work)',\n featurePlaceholder: 'Describe your ideas to improve our product (e.g., I want to export TASK.md to Linear tickets)',\n submitLabel: 'Send to the Maker',\n successMessage: 'Thank you for your feedback!',\n },\n};\n\nclass VoyageSDK {\n private config: VoyageConfig | null = null;\n private serverConfig: ProjectConfig | null = null;\n private container: HTMLElement | null = null;\n private isWidgetVisible = false;\n private isModalOpen = false;\n private hasInitError = false;\n\n async init(config: VoyageConfig): Promise<void> {\n this.config = config;\n this.hasInitError = false;\n\n if (!config.sdkKey) {\n console.error('[Voyage] SDK Key is required. Get your key from the dashboard.');\n this.hasInitError = true;\n injectStyles();\n this.isWidgetVisible = true;\n this.serverConfig = { ...DEFAULT_CONFIG };\n this.renderWidget();\n return;\n }\n\n // Inject SDK styles\n injectStyles();\n\n // Check display control\n if (!this.shouldDisplay()) {\n console.log('[Voyage] Widget hidden by display rules');\n return;\n }\n\n // Optimistic loading: 캐시가 있으면 먼저 표시\n const cachedConfig = getCachedConfig(config.sdkKey);\n if (cachedConfig) {\n this.serverConfig = this.mergeConfig(cachedConfig, config);\n this.isWidgetVisible = true;\n this.renderWidget();\n console.log('[Voyage] Initialized (cached)');\n\n // 백그라운드에서 최신 config fetch\n this.refreshConfigInBackground();\n return;\n }\n\n // 캐시가 없으면 fetch 후 표시\n const fetchedConfig = await fetchProjectConfig(config.sdkKey);\n\n if (!fetchedConfig) {\n console.error('[Voyage] Failed to fetch config. Check your SDK Key or network connection.');\n this.hasInitError = true;\n this.serverConfig = { ...DEFAULT_CONFIG };\n this.isWidgetVisible = true;\n this.renderWidget();\n return;\n }\n\n this.serverConfig = this.mergeConfig(fetchedConfig, config);\n\n // Render widget\n this.isWidgetVisible = true;\n this.renderWidget();\n console.log('[Voyage] Initialized');\n }\n\n private async refreshConfigInBackground(): Promise<void> {\n if (!this.config) return;\n\n try {\n // 캐시를 무시하고 서버에서 최신 설정 가져오기\n const freshConfig = await fetchProjectConfig(this.config.sdkKey, { forceRefresh: true });\n if (freshConfig && this.serverConfig) {\n // 설정이 변경되었을 때만 re-render\n const newConfig = this.mergeConfig(freshConfig, this.config);\n if (JSON.stringify(newConfig) !== JSON.stringify(this.serverConfig)) {\n this.serverConfig = newConfig;\n this.renderWidget();\n console.log('[Voyage] Config updated');\n }\n }\n } catch {\n // 백그라운드 갱신 실패는 무시 (이미 캐시로 동작 중)\n }\n }\n\n show(): void {\n if (!this.config) {\n console.warn('[Voyage] SDK not initialized');\n return;\n }\n this.isWidgetVisible = true;\n this.renderWidget();\n }\n\n hide(): void {\n this.isWidgetVisible = false;\n this.renderWidget();\n }\n\n open(): void {\n if (!this.config) {\n console.warn('[Voyage] SDK not initialized');\n return;\n }\n this.isModalOpen = true;\n this.renderWidget();\n }\n\n close(): void {\n this.isModalOpen = false;\n this.renderWidget();\n }\n\n isOpen(): boolean {\n return this.isModalOpen;\n }\n\n isVisible(): boolean {\n return this.isWidgetVisible;\n }\n\n async refreshConfig(): Promise<void> {\n if (!this.config) return;\n // 캐시를 무시하고 서버에서 최신 설정 가져오기\n const fetchedConfig = await fetchProjectConfig(this.config.sdkKey, { forceRefresh: true });\n this.serverConfig = this.mergeConfig(fetchedConfig, this.config);\n this.renderWidget();\n }\n\n destroy(): void {\n if (this.container) {\n render(null, this.container);\n this.container.remove();\n this.container = null;\n }\n this.config = null;\n this.serverConfig = null;\n this.isWidgetVisible = false;\n this.isModalOpen = false;\n }\n\n private renderWidget(): void {\n if (!this.serverConfig || !this.config) return;\n\n // Create container if not exists\n if (!this.container) {\n this.container = document.createElement('div');\n this.container.id = 'voyage-widget-container';\n document.body.appendChild(this.container);\n }\n\n const sdkKey = this.config.sdkKey;\n\n render(\n h(Widget, {\n config: this.serverConfig,\n visible: this.isWidgetVisible,\n defaultOpen: this.isModalOpen,\n hasError: this.hasInitError,\n onOpenChange: (open: boolean) => {\n this.isModalOpen = open;\n },\n getMetadata: captureMetadata,\n onSubmit: async (data: FeedbackData) => {\n return submitFeedback(sdkKey, data);\n },\n onUpload: async (file: File) => {\n return uploadImage(sdkKey, file);\n },\n }),\n this.container\n );\n }\n\n private mergeConfig(server: ProjectConfig | null, _client: VoyageConfig): ProjectConfig {\n // Server config takes priority: use values set from dashboard\n // Client-side theme override disabled (to prevent config conflicts)\n return server || { ...DEFAULT_CONFIG };\n }\n\n private shouldDisplay(): boolean {\n if (!this.config) return false;\n\n const pathname = window.location.pathname;\n const { include, exclude } = this.config;\n\n // include takes priority over exclude\n if (include && include.length > 0) {\n return include.some((pattern) => this.matchPath(pathname, pattern));\n }\n\n if (exclude && exclude.length > 0) {\n return !exclude.some((pattern) => this.matchPath(pathname, pattern));\n }\n\n return true;\n }\n\n private matchPath(pathname: string, pattern: string): boolean {\n // Simple glob matching: /admin/* matches /admin/anything\n if (pattern.endsWith('/*')) {\n const prefix = pattern.slice(0, -2);\n return pathname.startsWith(prefix);\n }\n return pathname === pattern;\n }\n}\n\n// Singleton instance\nconst Voyage = new VoyageSDK();\n\nexport { Voyage };\nexport default Voyage;\n"]}
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {render,h}from'preact';import {useState,useEffect,useRef}from'preact/hooks';import {jsxs,Fragment,jsx}from'preact/jsx-runtime';function ge(){return jsx("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsx("path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"})})}function D({onClick:r,label:o,position:e,primaryColor:i,hasError:p=false}){let[a,u]=useState(false),[c,l]=useState(false),d=e==="bottom-right"?{right:"24px"}:{left:"24px"},g=()=>c?"scale(0.95)":a?"scale(1.02) translateY(-2px)":"scale(1)";return jsxs("div",{style:{position:"fixed",bottom:"24px",...d,zIndex:9998},children:[jsxs("button",{onClick:r,onMouseEnter:()=>u(true),onMouseLeave:()=>{u(false),l(false);},onMouseDown:()=>l(true),onMouseUp:()=>l(false),style:{position:"relative",display:"flex",alignItems:"center",gap:"10px",padding:"14px 24px",border:"none",borderRadius:"50px",cursor:"pointer",fontFamily:"'Quicksand', 'Nunito', system-ui, sans-serif",fontSize:"15px",fontWeight:600,color:"#fff",backgroundColor:i,boxShadow:a?`0 8px 32px ${i}60, 0 0 20px ${i}40`:`0 4px 20px ${i}50, 0 0 10px ${i}30`,transform:g(),transition:"all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1)"},children:[jsx(ge,{}),jsx("span",{children:o})]}),p&&jsx("div",{style:{position:"absolute",top:"-4px",right:"-4px",width:"18px",height:"18px",borderRadius:"50%",backgroundColor:"#EF4444",display:"flex",alignItems:"center",justifyContent:"center",color:"#fff",fontSize:"12px",fontWeight:"bold",boxShadow:"0 2px 6px rgba(239, 68, 68, 0.5)"},children:"!"})]})}function he({size:r=24}){return jsx("svg",{width:r,height:r,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsx("path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"})})}function me(){return jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsx("path",{d:"M8 2l1.88 1.88M14.12 3.88L16 2M9 7.13v-1a3.003 3.003 0 116 0v1"}),jsx("path",{d:"M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 014-4h4a4 4 0 014 4v3c0 3.3-2.7 6-6 6"}),jsx("path",{d:"M12 20v-9M6.53 9C4.6 8.8 3 7.1 3 5M6 13H2M6 17l-4 1M17.47 9c1.93-.2 3.53-1.9 3.53-4M18 13h4M18 17l4 1"})]})}function be(){return jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsx("path",{d:"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 006 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"}),jsx("path",{d:"M9 18h6M10 22h4"})]})}function ye(){return jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),jsx("circle",{cx:"8.5",cy:"8.5",r:"1.5"}),jsx("polyline",{points:"21 15 16 10 5 21"})]})}function _(){return jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsx("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),jsx("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})}function xe(){return jsx("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsx("polyline",{points:"20 6 9 17 4 12"})})}var n={bgLight:"#F8FAFC",bgCard:"rgba(255, 255, 255, 0.98)",border:"rgba(0, 0, 0, 0.08)",text:"#1F2937",textMuted:"#6B7280",error:"#EF4444",success:"#22C55E"};function X({config:r,metadata:o,onClose:e,onSubmit:i,onUpload:p}){let[a,u]=useState(null),[c,l]=useState(""),[d,g]=useState(""),[v,x]=useState(null),[P,k]=useState(null),[L,H]=useState(false),[j,B]=useState(false),[U,b]=useState(null),[se,ae]=useState(false),F=useRef(null),{i18n:C,formFields:E,theme:le}=r,S=le.primaryColor||"#0ea5e9",A=400,de=a==="bug"?C.bugPlaceholder||C.placeholder:C.featurePlaceholder||C.placeholder,ce=async h=>{let I=h.target.files?.[0];if(I){if(!I.type.startsWith("image/")){b("Only image files are allowed");return}if(I.size>10*1024*1024){b("Image must be under 10MB");return}B(true),b(null);try{let M=await Se(I,{maxWidth:1920,maxHeight:1080,quality:.8}),J=new FileReader;J.onload=()=>k(J.result),J.readAsDataURL(M);let N=await p(M);B(!1),N?x(N):(b("Failed to upload image"),k(null));}catch(M){console.error("[Voyage] Image processing error:",M),B(false),b("Failed to process image");}}},pe=()=>{x(null),k(null),F.current&&(F.current.value="");},ue=async()=>{if(!a){b("Please select a type");return}if(!c.trim()){b("Please enter your feedback");return}if(E.email.required&&!d.trim()){b("Please enter your email");return}H(true),b(null);let h={label:a,text:c.trim(),email:d.trim()||void 0,imageUrl:v||void 0,metadata:o},m=await i(h);H(false),m?ae(true):b("Failed to submit. Please try again.");},f=(()=>{let h=`${S}15`;return {overlay:{position:"fixed",top:0,left:0,right:0,bottom:0,backgroundColor:"rgba(0, 0, 0, 0.4)",backdropFilter:"blur(4px)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999,padding:"20px"},modal:{backgroundColor:n.bgCard,backdropFilter:"blur(20px)",borderRadius:"20px",width:"100%",maxWidth:"580px",maxHeight:"90vh",overflowY:"auto",position:"relative",fontFamily:"'Quicksand', 'Nunito', system-ui, sans-serif",border:`1px solid ${n.border}`,boxShadow:"0 25px 50px -12px rgba(0, 0, 0, 0.15)"},colorBar:{height:"4px",backgroundColor:S},header:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"14px 20px",borderBottom:`1px solid ${n.border}`,backgroundColor:n.bgLight},headerIcon:{width:"32px",height:"32px",borderRadius:"10px",backgroundColor:S,display:"flex",alignItems:"center",justifyContent:"center",color:"#fff"},typeButton:m=>({display:"flex",alignItems:"center",justifyContent:"center",gap:"6px",padding:"10px 12px",border:m?`2px solid ${S}`:`1px solid ${n.border}`,borderRadius:"10px",backgroundColor:m?h:n.bgLight,cursor:"pointer",fontWeight:600,fontSize:"13px",color:m?n.text:n.textMuted,transition:"all 0.2s"}),submitButton:m=>({width:"100%",padding:"12px",backgroundColor:m?n.bgLight:S,color:m?n.textMuted:"#fff",border:"none",borderRadius:"12px",fontSize:"15px",fontWeight:700,cursor:m?"not-allowed":"pointer",fontFamily:"inherit",transition:"all 0.2s",boxShadow:m?"none":`0 4px 15px ${S}40`}),primaryButton:{width:"100%",padding:"16px",backgroundColor:S,color:"#fff",border:"none",borderRadius:"12px",fontSize:"15px",fontWeight:700,cursor:"pointer",fontFamily:"inherit",marginTop:"8px"}}})();return se?jsx("div",{style:f.overlay,children:jsx("div",{style:f.modal,children:jsxs("div",{style:Te,children:[jsx("div",{style:Re,children:jsx(xe,{})}),jsx("h3",{style:Oe,children:C.successMessage}),jsx("p",{style:$e,children:"Your voice shapes what we build next."}),jsx("button",{onClick:e,style:f.primaryButton,children:"Done"})]})})}):jsx("div",{style:f.overlay,onClick:e,children:jsxs("div",{style:f.modal,onClick:h=>h.stopPropagation(),children:[jsxs("div",{style:f.header,children:[jsxs("div",{style:ve,children:[jsx("div",{style:f.headerIcon,children:jsx(he,{size:20})}),jsx("span",{style:Ce,children:"Help Us Improve"})]}),jsx("button",{onClick:e,style:ke,children:jsx(_,{})})]}),jsx("div",{style:f.colorBar}),jsxs("div",{style:we,children:[jsxs("div",{style:Q,children:[jsx("label",{style:W,children:"Feedback Type"}),jsxs("div",{style:Pe,children:[jsxs("button",{onClick:()=>u("bug"),style:f.typeButton(a==="bug"),children:[jsx("span",{style:Y(a==="bug","bug"),children:jsx(me,{})}),jsx("span",{children:"Bug"})]}),jsxs("button",{onClick:()=>u("feature"),style:f.typeButton(a==="feature"),children:[jsx("span",{style:Y(a==="feature","feature"),children:jsx(be,{})}),jsx("span",{children:"Feature"})]})]})]}),jsxs("div",{style:Fe,children:[jsxs("div",{style:Ie,children:[jsx("label",{style:W,children:"Description"}),jsxs("div",{style:je,children:[jsx("textarea",{placeholder:de,value:c,maxLength:A,onInput:h=>l(h.target.value),style:Be}),jsxs("span",{style:Ee,children:[c.length,"/",A]})]})]}),jsxs("div",{style:Me,children:[jsx("label",{style:W,children:"Screenshot"}),P?jsxs("div",{style:De,children:[jsx("img",{src:P,alt:"Preview",style:Le}),jsx("button",{onClick:pe,style:Xe,children:jsx(_,{})}),j&&jsx("div",{style:ze,children:"..."})]}):jsxs("button",{onClick:()=>F.current?.click(),style:We,children:[jsx(ye,{}),jsx("span",{style:{fontSize:"11px"},children:"Upload"})]}),jsx("input",{ref:F,type:"file",accept:"image/*",onChange:ce,style:{display:"none"}})]})]}),E.email.enabled&&jsxs("div",{style:Q,children:[jsxs("label",{style:W,children:["Email ",E.email.required?"":"(optional)"]}),jsx("input",{type:"email",placeholder:"your@email.com",value:d,onInput:h=>g(h.target.value),style:Je})]}),U&&jsx("p",{style:Ve,children:U}),jsx("button",{onClick:ue,disabled:L||j,style:f.submitButton(L||j),children:L?jsxs("span",{style:He,children:[jsx("span",{className:"voyage-spinner"}),"Sending..."]}):C.submitLabel})]})]})})}async function Se(r,o){let{maxWidth:e,maxHeight:i,quality:p}=o;return new Promise((a,u)=>{let c=new Image;c.onload=()=>{let{width:l,height:d}=c;if(l>e||d>i){let x=Math.min(e/l,i/d);l=Math.round(l*x),d=Math.round(d*x);}let g=document.createElement("canvas");g.width=l,g.height=d;let v=g.getContext("2d");if(!v){u(new Error("Failed to get canvas context"));return}v.drawImage(c,0,0,l,d),g.toBlob(x=>{if(!x){u(new Error("Failed to convert image"));return}let P=Date.now(),k=new File([x],`image_${P}.webp`,{type:"image/webp"});a(k);},"image/webp",p);},c.onerror=()=>u(new Error("Failed to load image")),c.src=URL.createObjectURL(r);})}var ve={display:"flex",alignItems:"center",gap:"12px"},Ce={fontSize:"16px",fontWeight:700,color:n.text},ke={background:"transparent",border:"none",color:n.textMuted,cursor:"pointer",padding:"8px",borderRadius:"8px",display:"flex",alignItems:"center",justifyContent:"center",transition:"all 0.2s"},we={padding:"16px 20px"},Q={marginBottom:"14px"},W={display:"block",fontSize:"13px",fontWeight:600,color:n.text,marginBottom:"8px"},Pe={display:"grid",gridTemplateColumns:"1fr 1fr",gap:"12px"},Fe={display:"flex",gap:"14px",marginBottom:"14px"},Ie={flex:1,display:"flex",flexDirection:"column"},Me={width:"120px",flexShrink:0,display:"flex",flexDirection:"column"},We={width:"100%",aspectRatio:"1",border:`2px dashed ${n.border}`,borderRadius:"10px",backgroundColor:"transparent",cursor:"pointer",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:"4px",color:n.textMuted,fontSize:"12px",transition:"all 0.2s"},Le={width:"100%",aspectRatio:"1",objectFit:"cover",borderRadius:"10px"},Y=(r,o)=>({display:"flex",alignItems:"center",justifyContent:"center",color:r?o==="bug"?n.error:"#F59E0B":n.textMuted}),je={position:"relative"},Be={width:"100%",minHeight:"120px",padding:"14px",border:`1px solid ${n.border}`,borderRadius:"12px",fontSize:"14px",resize:"vertical",boxSizing:"border-box",backgroundColor:n.bgLight,color:n.text,fontFamily:"inherit",outline:"none"},Ee={position:"absolute",bottom:"12px",right:"14px",fontSize:"12px",color:n.textMuted},Je={width:"100%",padding:"10px 12px",border:`1px solid ${n.border}`,borderRadius:"10px",fontSize:"13px",boxSizing:"border-box",backgroundColor:n.bgLight,color:n.text,fontFamily:"inherit",outline:"none"},De={position:"relative",display:"inline-block",borderRadius:"12px",overflow:"hidden"},Xe={position:"absolute",top:"8px",right:"8px",width:"28px",height:"28px",borderRadius:"50%",backgroundColor:"rgba(0, 0, 0, 0.7)",color:"#fff",border:"none",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center"},ze={position:"absolute",inset:0,backgroundColor:"rgba(0, 0, 0, 0.7)",display:"flex",alignItems:"center",justifyContent:"center",color:"#fff",fontSize:"14px",borderRadius:"12px"},Ve={color:n.error,fontSize:"14px",marginBottom:"16px",padding:"12px",backgroundColor:"rgba(239, 68, 68, 0.1)",borderRadius:"8px",border:"1px solid rgba(239, 68, 68, 0.3)"},Te={padding:"48px 24px",textAlign:"center"},Re={width:"64px",height:"64px",borderRadius:"50%",backgroundColor:"rgba(34, 197, 94, 0.15)",color:n.success,display:"flex",alignItems:"center",justifyContent:"center",margin:"0 auto 20px"},Oe={fontSize:"20px",fontWeight:700,color:n.text,marginBottom:"8px"},$e={fontSize:"14px",color:n.textMuted,marginBottom:"24px"},He={display:"flex",alignItems:"center",justifyContent:"center",gap:"8px"};function z({config:r,onSubmit:o,onUpload:e,getMetadata:i,visible:p,defaultOpen:a=false,hasError:u=false,onOpenChange:c}){let[l,d]=useState(a);if(useEffect(()=>{d(a);},[a]),useEffect(()=>{c?.(l);},[l,c]),!p)return null;let{theme:g,i18n:v}=r;return jsxs(Fragment,{children:[!l&&jsx(D,{onClick:()=>d(true),label:v.buttonLabel,position:g.position,primaryColor:g.primaryColor,hasError:u}),l&&jsx(X,{config:r,metadata:i(),onClose:()=>d(false),onSubmit:o,onUpload:e})]})}var V=()=>{if(typeof document>"u"||document.getElementById("voyage-sdk-styles"))return;let r=document.createElement("style");r.id="voyage-sdk-styles",r.textContent=`
|
|
1
|
+
import {render,h}from'preact';import {useState,useEffect,useRef}from'preact/hooks';import {jsxs,Fragment,jsx}from'preact/jsx-runtime';function he(){return jsx("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsx("path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"})})}function D({onClick:i,label:t,position:e,primaryColor:r,hasError:a=false}){let[l,p]=useState(false),[u,c]=useState(false),d=e==="bottom-right"?{right:"24px"}:{left:"24px"},g=()=>u?"scale(0.95)":l?"scale(1.02) translateY(-2px)":"scale(1)";return jsxs("div",{style:{position:"fixed",bottom:"24px",...d,zIndex:9998},children:[jsxs("button",{onClick:i,onMouseEnter:()=>p(true),onMouseLeave:()=>{p(false),c(false);},onMouseDown:()=>c(true),onMouseUp:()=>c(false),style:{position:"relative",display:"flex",alignItems:"center",gap:"10px",padding:"14px 24px",border:"none",borderRadius:"50px",cursor:"pointer",fontFamily:"'Quicksand', 'Nunito', system-ui, sans-serif",fontSize:"15px",fontWeight:600,color:"#fff",backgroundColor:r,boxShadow:l?`0 8px 32px ${r}60, 0 0 20px ${r}40`:`0 4px 20px ${r}50, 0 0 10px ${r}30`,transform:g(),transition:"all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1)"},children:[jsx(he,{}),jsx("span",{children:t})]}),a&&jsx("div",{style:{position:"absolute",top:"-4px",right:"-4px",width:"18px",height:"18px",borderRadius:"50%",backgroundColor:"#EF4444",display:"flex",alignItems:"center",justifyContent:"center",color:"#fff",fontSize:"12px",fontWeight:"bold",boxShadow:"0 2px 6px rgba(239, 68, 68, 0.5)"},children:"!"})]})}function be({size:i=24}){return jsx("svg",{width:i,height:i,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsx("path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"})})}function ye(){return jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsx("path",{d:"M8 2l1.88 1.88M14.12 3.88L16 2M9 7.13v-1a3.003 3.003 0 116 0v1"}),jsx("path",{d:"M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 014-4h4a4 4 0 014 4v3c0 3.3-2.7 6-6 6"}),jsx("path",{d:"M12 20v-9M6.53 9C4.6 8.8 3 7.1 3 5M6 13H2M6 17l-4 1M17.47 9c1.93-.2 3.53-1.9 3.53-4M18 13h4M18 17l4 1"})]})}function xe(){return jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsx("path",{d:"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 006 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"}),jsx("path",{d:"M9 18h6M10 22h4"})]})}function Se(){return jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),jsx("circle",{cx:"8.5",cy:"8.5",r:"1.5"}),jsx("polyline",{points:"21 15 16 10 5 21"})]})}function Q(){return jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsx("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),jsx("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})}function Ce(){return jsx("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsx("polyline",{points:"20 6 9 17 4 12"})})}var n={bgLight:"#F8FAFC",bgCard:"rgba(255, 255, 255, 0.98)",border:"rgba(0, 0, 0, 0.08)",text:"#1F2937",textMuted:"#6B7280",error:"#EF4444",success:"#22C55E"};function O({config:i,metadata:t,onClose:e,onSubmit:r,onUpload:a}){let[l,p]=useState(null),[u,c]=useState(""),[d,g]=useState(""),[C,x]=useState(null),[P,k]=useState(null),[B,H]=useState(false),[j,T]=useState(false),[_,b]=useState(null),[le,ce]=useState(false),I=useRef(null),{i18n:v,formFields:J,theme:de}=i,S=de.primaryColor||"#0ea5e9",N=400,ue=l==="bug"?v.bugPlaceholder||v.placeholder:v.featurePlaceholder||v.placeholder,pe=async h=>{let M=h.target.files?.[0];if(M){if(!M.type.startsWith("image/")){b("Only image files are allowed");return}if(M.size>10*1024*1024){b("Image must be under 10MB");return}T(true),b(null);try{let F=await ve(M,{maxWidth:1920,maxHeight:1080,quality:.8}),V=new FileReader;V.onload=()=>k(V.result),V.readAsDataURL(F);let q=await a(F);T(!1),q?x(q):(b("Failed to upload image"),k(null));}catch(F){console.error("[Voyage] Image processing error:",F),T(false),b("Failed to process image");}}},ge=()=>{x(null),k(null),I.current&&(I.current.value="");},fe=async()=>{if(!l){b("Please select a type");return}if(!u.trim()){b("Please enter your feedback");return}if(J.email.required&&!d.trim()){b("Please enter your email");return}H(true),b(null);let h={label:l,text:u.trim(),email:d.trim()||void 0,imageUrl:C||void 0,metadata:t},m=await r(h);H(false),m?ce(true):b("Failed to submit. Please try again.");},f=(()=>{let h=`${S}15`;return {overlay:{position:"fixed",top:0,left:0,right:0,bottom:0,backgroundColor:"rgba(0, 0, 0, 0.4)",backdropFilter:"blur(4px)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999,padding:"20px"},modal:{backgroundColor:n.bgCard,backdropFilter:"blur(20px)",borderRadius:"20px",width:"100%",maxWidth:"580px",maxHeight:"90vh",overflowY:"auto",position:"relative",fontFamily:"'Quicksand', 'Nunito', system-ui, sans-serif",border:`1px solid ${n.border}`,boxShadow:"0 25px 50px -12px rgba(0, 0, 0, 0.15)"},colorBar:{height:"4px",backgroundColor:S},header:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"14px 20px",borderBottom:`1px solid ${n.border}`,backgroundColor:n.bgLight},headerIcon:{width:"32px",height:"32px",borderRadius:"10px",backgroundColor:S,display:"flex",alignItems:"center",justifyContent:"center",color:"#fff"},typeButton:m=>({display:"flex",alignItems:"center",justifyContent:"center",gap:"6px",padding:"10px 12px",border:m?`2px solid ${S}`:`1px solid ${n.border}`,borderRadius:"10px",backgroundColor:m?h:n.bgLight,cursor:"pointer",fontWeight:600,fontSize:"13px",color:m?n.text:n.textMuted,transition:"all 0.2s"}),submitButton:m=>({width:"100%",padding:"12px",backgroundColor:m?n.bgLight:S,color:m?n.textMuted:"#fff",border:"none",borderRadius:"12px",fontSize:"15px",fontWeight:700,cursor:m?"not-allowed":"pointer",fontFamily:"inherit",transition:"all 0.2s",boxShadow:m?"none":`0 4px 15px ${S}40`}),primaryButton:{width:"100%",padding:"16px",backgroundColor:S,color:"#fff",border:"none",borderRadius:"12px",fontSize:"15px",fontWeight:700,cursor:"pointer",fontFamily:"inherit",marginTop:"8px"}}})();return le?jsx("div",{style:f.overlay,children:jsx("div",{style:f.modal,children:jsxs("div",{style:Re,children:[jsx("div",{style:Ue,children:jsx(Ce,{})}),jsx("h3",{style:$e,children:v.successMessage}),jsx("p",{style:Ae,children:"Your voice shapes what we build next."}),jsx("button",{onClick:e,style:f.primaryButton,children:"Done"})]})})}):jsx("div",{style:f.overlay,onClick:e,children:jsxs("div",{style:f.modal,onClick:h=>h.stopPropagation(),children:[jsxs("div",{style:f.header,children:[jsxs("div",{style:ke,children:[jsx("div",{style:f.headerIcon,children:jsx(be,{size:20})}),jsx("span",{style:we,children:"Help Us Improve"})]}),jsx("button",{onClick:e,style:Pe,children:jsx(Q,{})})]}),jsx("div",{style:f.colorBar}),jsxs("div",{style:Ie,children:[jsxs("div",{style:Y,children:[jsx("label",{style:E,children:"Feedback Type"}),jsxs("div",{style:Me,children:[jsxs("button",{onClick:()=>p("bug"),style:f.typeButton(l==="bug"),children:[jsx("span",{style:Z(l==="bug","bug"),children:jsx(ye,{})}),jsx("span",{children:"Bug"})]}),jsxs("button",{onClick:()=>p("feature"),style:f.typeButton(l==="feature"),children:[jsx("span",{style:Z(l==="feature","feature"),children:jsx(xe,{})}),jsx("span",{children:"Feature"})]})]})]}),jsxs("div",{style:Fe,children:[jsxs("div",{style:Ee,children:[jsx("label",{style:E,children:"Description"}),jsxs("div",{style:je,children:[jsx("textarea",{placeholder:ue,value:u,maxLength:N,onInput:h=>c(h.target.value),style:Te}),jsxs("span",{style:Je,children:[u.length,"/",N]})]})]}),jsxs("div",{style:We,children:[jsx("label",{style:E,children:"Screenshot"}),P?jsxs("div",{style:De,children:[jsx("img",{src:P,alt:"Preview",style:Be}),jsx("button",{onClick:ge,style:Oe,children:jsx(Q,{})}),j&&jsx("div",{style:ze,children:"..."})]}):jsxs("button",{onClick:()=>I.current?.click(),style:Le,children:[jsx(Se,{}),jsx("span",{style:{fontSize:"11px"},children:"Upload"})]}),jsx("input",{ref:I,type:"file",accept:"image/*",onChange:pe,style:{display:"none"}})]})]}),J.email.enabled&&jsxs("div",{style:Y,children:[jsxs("label",{style:E,children:["Email ",J.email.required?"":"(optional)"]}),jsx("input",{type:"email",placeholder:"your@email.com",value:d,onInput:h=>g(h.target.value),style:Ve})]}),_&&jsx("p",{style:Xe,children:_}),jsx("button",{onClick:fe,disabled:B||j,style:f.submitButton(B||j),children:B?jsxs("span",{style:He,children:[jsx("span",{className:"voyage-spinner"}),"Sending..."]}):v.submitLabel})]})]})})}async function ve(i,t){let{maxWidth:e,maxHeight:r,quality:a}=t;return new Promise((l,p)=>{let u=new Image;u.onload=()=>{let{width:c,height:d}=u;if(c>e||d>r){let x=Math.min(e/c,r/d);c=Math.round(c*x),d=Math.round(d*x);}let g=document.createElement("canvas");g.width=c,g.height=d;let C=g.getContext("2d");if(!C){p(new Error("Failed to get canvas context"));return}C.drawImage(u,0,0,c,d),g.toBlob(x=>{if(!x){p(new Error("Failed to convert image"));return}let P=Date.now(),k=new File([x],`image_${P}.webp`,{type:"image/webp"});l(k);},"image/webp",a);},u.onerror=()=>p(new Error("Failed to load image")),u.src=URL.createObjectURL(i);})}var ke={display:"flex",alignItems:"center",gap:"12px"},we={fontSize:"16px",fontWeight:700,color:n.text},Pe={background:"transparent",border:"none",color:n.textMuted,cursor:"pointer",padding:"8px",borderRadius:"8px",display:"flex",alignItems:"center",justifyContent:"center",transition:"all 0.2s"},Ie={padding:"16px 20px"},Y={marginBottom:"14px"},E={display:"block",fontSize:"13px",fontWeight:600,color:n.text,marginBottom:"8px"},Me={display:"grid",gridTemplateColumns:"1fr 1fr",gap:"12px"},Fe={display:"flex",gap:"14px",marginBottom:"14px"},Ee={flex:1,display:"flex",flexDirection:"column"},We={width:"120px",flexShrink:0,display:"flex",flexDirection:"column"},Le={width:"100%",aspectRatio:"1",border:`2px dashed ${n.border}`,borderRadius:"10px",backgroundColor:"transparent",cursor:"pointer",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:"4px",color:n.textMuted,fontSize:"12px",transition:"all 0.2s"},Be={width:"100%",aspectRatio:"1",objectFit:"cover",borderRadius:"10px"},Z=(i,t)=>({display:"flex",alignItems:"center",justifyContent:"center",color:i?t==="bug"?n.error:"#F59E0B":n.textMuted}),je={position:"relative"},Te={width:"100%",minHeight:"120px",padding:"14px",border:`1px solid ${n.border}`,borderRadius:"12px",fontSize:"14px",resize:"vertical",boxSizing:"border-box",backgroundColor:n.bgLight,color:n.text,fontFamily:"inherit",outline:"none"},Je={position:"absolute",bottom:"12px",right:"14px",fontSize:"12px",color:n.textMuted},Ve={width:"100%",padding:"10px 12px",border:`1px solid ${n.border}`,borderRadius:"10px",fontSize:"13px",boxSizing:"border-box",backgroundColor:n.bgLight,color:n.text,fontFamily:"inherit",outline:"none"},De={position:"relative",display:"inline-block",borderRadius:"12px",overflow:"hidden"},Oe={position:"absolute",top:"8px",right:"8px",width:"28px",height:"28px",borderRadius:"50%",backgroundColor:"rgba(0, 0, 0, 0.7)",color:"#fff",border:"none",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center"},ze={position:"absolute",inset:0,backgroundColor:"rgba(0, 0, 0, 0.7)",display:"flex",alignItems:"center",justifyContent:"center",color:"#fff",fontSize:"14px",borderRadius:"12px"},Xe={color:n.error,fontSize:"14px",marginBottom:"16px",padding:"12px",backgroundColor:"rgba(239, 68, 68, 0.1)",borderRadius:"8px",border:"1px solid rgba(239, 68, 68, 0.3)"},Re={padding:"48px 24px",textAlign:"center"},Ue={width:"64px",height:"64px",borderRadius:"50%",backgroundColor:"rgba(34, 197, 94, 0.15)",color:n.success,display:"flex",alignItems:"center",justifyContent:"center",margin:"0 auto 20px"},$e={fontSize:"20px",fontWeight:700,color:n.text,marginBottom:"8px"},Ae={fontSize:"14px",color:n.textMuted,marginBottom:"24px"},He={display:"flex",alignItems:"center",justifyContent:"center",gap:"8px"};function z({config:i,onSubmit:t,onUpload:e,getMetadata:r,visible:a,defaultOpen:l=false,hasError:p=false,onOpenChange:u}){let[c,d]=useState(l);if(useEffect(()=>{d(l);},[l]),useEffect(()=>{u?.(c);},[c,u]),!a)return null;let{theme:g,i18n:C}=i;return jsxs(Fragment,{children:[!c&&jsx(D,{onClick:()=>d(true),label:C.buttonLabel,position:g.position,primaryColor:g.primaryColor,hasError:p}),c&&jsx(O,{config:i,metadata:r(),onClose:()=>d(false),onSubmit:t,onUpload:e})]})}var X=()=>{if(typeof document>"u"||document.getElementById("voyage-sdk-styles"))return;let i=document.createElement("style");i.id="voyage-sdk-styles",i.textContent=`
|
|
2
2
|
/* Voyage SDK Styles */
|
|
3
3
|
|
|
4
4
|
/* Spinner Animation */
|
|
@@ -37,6 +37,6 @@ import {render,h}from'preact';import {useState,useEffect,useRef}from'preact/hook
|
|
|
37
37
|
|
|
38
38
|
/* Load Quicksand font if not present */
|
|
39
39
|
@import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@400;500;600;700&display=swap');
|
|
40
|
-
`,document.head.appendChild(
|
|
41
|
-
export{
|
|
40
|
+
`,document.head.appendChild(i);};var R="https://rxflzurkkuqgopjkshjh.supabase.co/functions/v1",oe="voyage_config";function U(i,t,e){let r=new AbortController,a=setTimeout(()=>r.abort(),e);return fetch(i,{...t,signal:r.signal}).finally(()=>clearTimeout(a))}async function L(i,t={}){let{forceRefresh:e=false}=t;if(!e){let r=W(i);if(r)return r}try{let r=await U(`${R}/get-widget-config`,{method:"GET",headers:{"Content-Type":"application/json","x-sdk-key":i}},5e3);if(!r.ok)return console.error("[Voyage] Failed to fetch config:",r.status),W(i,!0);let a=await r.json();return Ke(i,a),a}catch(r){return r instanceof Error&&r.name==="AbortError"?console.warn("[Voyage] Config fetch timeout, using cached config"):console.error("[Voyage] Network error:",r),W(i,true)}}async function re(i,t){try{let e=await U(`${R}/submit-feedback`,{method:"POST",headers:{"Content-Type":"application/json","x-sdk-key":i},body:JSON.stringify({label:t.label,content:t.text,email:t.email,imageUrl:t.imageUrl,metadata:t.metadata})},1e4);if(!e.ok){let r=await e.json().catch(()=>({}));return console.error("[Voyage] Failed to submit feedback:",e.status,r),!1}return !0}catch(e){return e instanceof Error&&e.name==="AbortError"?console.error("[Voyage] Feedback submission timeout"):console.error("[Voyage] Network error:",e),false}}async function ie(i,t){if(!t.type.startsWith("image/"))return console.error("[Voyage] Only image files are allowed"),null;if(t.size>5*1024*1024)return console.error("[Voyage] Image must be under 5MB"),null;try{let e=new FormData;e.append("file",t);let r=await U(`${R}/upload-feedback-image`,{method:"POST",headers:{"x-sdk-key":i},body:e},3e4);if(!r.ok){let l=await r.json().catch(()=>({}));return console.error("[Voyage] Failed to upload image:",r.status,l),null}return (await r.json()).url}catch(e){return e instanceof Error&&e.name==="AbortError"?console.error("[Voyage] Image upload timeout"):console.error("[Voyage] Network error:",e),null}}function ne(i){return W(i,true)}function W(i,t=false){try{let e=localStorage.getItem(`${oe}_${i}`);if(!e)return null;let r=JSON.parse(e);return Date.now()-r.timestamp>36e5&&!t?null:r.config}catch{return null}}function Ke(i,t){try{let e={config:t,timestamp:Date.now()};localStorage.setItem(`${oe}_${i}`,JSON.stringify(e));}catch{}}function se(){return {url:window.location.href,pathname:window.location.pathname,browser:navigator.userAgent,viewport:`${window.innerWidth}x${window.innerHeight}`,title:document.title,timestamp:new Date().toISOString(),locale:navigator.language,referrer:document.referrer}}var $={projectId:"",formFields:{email:{enabled:true,required:false},category:{enabled:true,options:["bug","feature"]}},theme:{primaryColor:"#0ea5e9",position:"bottom-right"},i18n:{buttonLabel:"To : the Maker",placeholder:"Describe your ideas to improve our product",bugPlaceholder:"Please describe the bug in detail (e.g., clicked a button and it didn't work)",featurePlaceholder:"Describe your ideas to improve our product (e.g., I want to export TASK.md to Linear tickets)",submitLabel:"Send to the Maker",successMessage:"Thank you for your feedback!"}},A=class{constructor(){this.config=null;this.serverConfig=null;this.container=null;this.isWidgetVisible=false;this.isModalOpen=false;this.hasInitError=false;}async init(t){if(this.config=t,this.hasInitError=false,!t.sdkKey){console.error("[Voyage] SDK Key is required. Get your key from the dashboard."),this.hasInitError=true,X(),this.isWidgetVisible=true,this.serverConfig={...$},this.renderWidget();return}if(X(),!this.shouldDisplay()){console.log("[Voyage] Widget hidden by display rules");return}let e=ne(t.sdkKey);if(e){this.serverConfig=this.mergeConfig(e,t),this.isWidgetVisible=true,this.renderWidget(),console.log("[Voyage] Initialized (cached)"),this.refreshConfigInBackground();return}let r=await L(t.sdkKey);if(!r){console.error("[Voyage] Failed to fetch config. Check your SDK Key or network connection."),this.hasInitError=true,this.serverConfig={...$},this.isWidgetVisible=true,this.renderWidget();return}this.serverConfig=this.mergeConfig(r,t),this.isWidgetVisible=true,this.renderWidget(),console.log("[Voyage] Initialized");}async refreshConfigInBackground(){if(this.config)try{let t=await L(this.config.sdkKey,{forceRefresh:!0});if(t&&this.serverConfig){let e=this.mergeConfig(t,this.config);JSON.stringify(e)!==JSON.stringify(this.serverConfig)&&(this.serverConfig=e,this.renderWidget(),console.log("[Voyage] Config updated"));}}catch{}}show(){if(!this.config){console.warn("[Voyage] SDK not initialized");return}this.isWidgetVisible=true,this.renderWidget();}hide(){this.isWidgetVisible=false,this.renderWidget();}open(){if(!this.config){console.warn("[Voyage] SDK not initialized");return}this.isModalOpen=true,this.renderWidget();}close(){this.isModalOpen=false,this.renderWidget();}isOpen(){return this.isModalOpen}isVisible(){return this.isWidgetVisible}async refreshConfig(){if(!this.config)return;let t=await L(this.config.sdkKey,{forceRefresh:true});this.serverConfig=this.mergeConfig(t,this.config),this.renderWidget();}destroy(){this.container&&(render(null,this.container),this.container.remove(),this.container=null),this.config=null,this.serverConfig=null,this.isWidgetVisible=false,this.isModalOpen=false;}renderWidget(){if(!this.serverConfig||!this.config)return;this.container||(this.container=document.createElement("div"),this.container.id="voyage-widget-container",document.body.appendChild(this.container));let t=this.config.sdkKey;render(h(z,{config:this.serverConfig,visible:this.isWidgetVisible,defaultOpen:this.isModalOpen,hasError:this.hasInitError,onOpenChange:e=>{this.isModalOpen=e;},getMetadata:se,onSubmit:async e=>re(t,e),onUpload:async e=>ie(t,e)}),this.container);}mergeConfig(t,e){return t||{...$}}shouldDisplay(){if(!this.config)return false;let t=window.location.pathname,{include:e,exclude:r}=this.config;return e&&e.length>0?e.some(a=>this.matchPath(t,a)):r&&r.length>0?!r.some(a=>this.matchPath(t,a)):true}matchPath(t,e){if(e.endsWith("/*")){let r=e.slice(0,-2);return t.startsWith(r)}return t===e}},Qe=new A;var vt=Qe;
|
|
41
|
+
export{Qe as Voyage,vt as default};//# sourceMappingURL=index.js.map
|
|
42
42
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Button.tsx","../src/components/Modal.tsx","../src/components/Widget.tsx","../src/styles.ts","../src/utils/api.ts","../src/utils/metadata.ts","../src/index.ts"],"names":["MessageIcon","jsx","Button","onClick","label","position","primaryColor","hasError","isHovered","setIsHovered","useState","isPressed","setIsPressed","positionStyle","getTransform","jsxs","size","BugIcon","LightbulbIcon","ImageIcon","CloseIcon","CheckIcon","colors","Modal","config","metadata","onClose","onSubmit","onUpload","setLabel","text","setText","email","setEmail","imageUrl","setImageUrl","imagePreview","setImagePreview","isSubmitting","setIsSubmitting","isUploading","setIsUploading","error","setError","success","setSuccess","fileInputRef","useRef","i18n","formFields","theme","maxLength","currentPlaceholder","handleFileSelect","e","file","processedFile","processImage","reader","url","err","handleRemoveImage","handleSubmit","feedbackData","result","styles","primaryBgLight","active","disabled","successContainerStyle","successIconStyle","successTitleStyle","successTextStyle","headerLeftStyle","headerTitleStyle","closeButtonStyle","contentStyle","sectionStyle","labelStyle","typeButtonsStyle","typeIconStyle","descriptionRowStyle","descriptionColStyle","textareaWrapperStyle","textareaStyle","charCountStyle","uploadColStyle","imagePreviewContainerStyle","imagePreviewSquareStyle","removeImageButtonStyle","uploadingOverlayStyle","uploadButtonSquareStyle","inputStyle","errorStyle","spinnerContainerStyle","options","maxWidth","maxHeight","quality","resolve","reject","img","width","height","ratio","canvas","ctx","blob","timestamp","newFile","type","Widget","getMetadata","visible","defaultOpen","onOpenChange","isOpen","setIsOpen","useEffect","Fragment","injectStyles","style","API_BASE","CACHE_KEY","fetchProjectConfig","sdkKey","cached","getFromCache","response","saveToCache","submitFeedback","data","errorData","uploadImage","formData","ignoreExpiry","raw","captureMetadata","DEFAULT_CONFIG","VoyageSDK","fetchedConfig","render","h","open","server","_client","pathname","include","exclude","pattern","prefix","Voyage","index_default"],"mappings":"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","file":"index.js","sourcesContent":["import { h } from 'preact';\nimport { useState } from 'preact/hooks';\n\ninterface ButtonProps {\n onClick: () => void;\n label: string;\n position: 'bottom-right' | 'bottom-left';\n primaryColor: string;\n hasError?: boolean;\n}\n\n// 말풍선 아이콘 SVG\nfunction MessageIcon() {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n );\n}\n\n// 에러 아이콘 (느낌표)\nfunction ErrorIcon() {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"#fff\"\n stroke=\"none\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"12\" fill=\"#EF4444\" />\n <text x=\"12\" y=\"17\" textAnchor=\"middle\" fill=\"#fff\" fontSize=\"14\" fontWeight=\"bold\">!</text>\n </svg>\n );\n}\n\nexport function Button({ onClick, label, position, primaryColor, hasError = false }: ButtonProps) {\n const [isHovered, setIsHovered] = useState(false);\n const [isPressed, setIsPressed] = useState(false);\n\n const positionStyle = position === 'bottom-right'\n ? { right: '24px' }\n : { left: '24px' };\n\n // Jelly 효과 transform\n const getTransform = () => {\n if (isPressed) return 'scale(0.95)';\n if (isHovered) return 'scale(1.02) translateY(-2px)';\n return 'scale(1)';\n };\n\n return (\n <div style={{ position: 'fixed', bottom: '24px', ...positionStyle, zIndex: 9998 }}>\n <button\n onClick={onClick}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => { setIsHovered(false); setIsPressed(false); }}\n onMouseDown={() => setIsPressed(true)}\n onMouseUp={() => setIsPressed(false)}\n style={{\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n padding: '14px 24px',\n border: 'none',\n borderRadius: '50px',\n cursor: 'pointer',\n fontFamily: \"'Quicksand', 'Nunito', system-ui, sans-serif\",\n fontSize: '15px',\n fontWeight: 600,\n color: '#fff',\n // primaryColor 적용\n backgroundColor: primaryColor,\n // 그림자 + glow 효과\n boxShadow: isHovered\n ? `0 8px 32px ${primaryColor}60, 0 0 20px ${primaryColor}40`\n : `0 4px 20px ${primaryColor}50, 0 0 10px ${primaryColor}30`,\n // Jelly 애니메이션\n transform: getTransform(),\n transition: 'all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1)',\n }}\n >\n <MessageIcon />\n <span>{label}</span>\n </button>\n {/* 에러 아이콘 - 우측 상단 */}\n {hasError && (\n <div\n style={{\n position: 'absolute',\n top: '-4px',\n right: '-4px',\n width: '18px',\n height: '18px',\n borderRadius: '50%',\n backgroundColor: '#EF4444',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#fff',\n fontSize: '12px',\n fontWeight: 'bold',\n boxShadow: '0 2px 6px rgba(239, 68, 68, 0.5)',\n }}\n >\n !\n </div>\n )}\n </div>\n );\n}\n","import { h } from 'preact';\nimport { useRef, useState } from 'preact/hooks';\n\nimport type { ProjectConfig, FeedbackData, FeedbackMetadata } from '../types';\n\ninterface ModalProps {\n config: ProjectConfig;\n metadata: FeedbackMetadata;\n onClose: () => void;\n onSubmit: (data: FeedbackData) => Promise<boolean>;\n onUpload: (file: File) => Promise<string | null>;\n}\n\n// 아이콘들\nfunction MessageIcon({ size = 24 }: { size?: number }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n );\n}\n\nfunction BugIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M8 2l1.88 1.88M14.12 3.88L16 2M9 7.13v-1a3.003 3.003 0 116 0v1\" />\n <path d=\"M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 014-4h4a4 4 0 014 4v3c0 3.3-2.7 6-6 6\" />\n <path d=\"M12 20v-9M6.53 9C4.6 8.8 3 7.1 3 5M6 13H2M6 17l-4 1M17.47 9c1.93-.2 3.53-1.9 3.53-4M18 13h4M18 17l4 1\" />\n </svg>\n );\n}\n\nfunction LightbulbIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 006 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\" />\n <path d=\"M9 18h6M10 22h4\" />\n </svg>\n );\n}\n\nfunction ImageIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\" />\n <polyline points=\"21 15 16 10 5 21\" />\n </svg>\n );\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\nfunction CheckIcon() {\n return (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n );\n}\n\n// 라이트 테마 색상\nconst colors = {\n bg: '#FFFFFF',\n bgLight: '#F8FAFC',\n bgCard: 'rgba(255, 255, 255, 0.98)',\n border: 'rgba(0, 0, 0, 0.08)',\n borderLight: 'rgba(0, 0, 0, 0.12)',\n text: '#1F2937',\n textMuted: '#6B7280',\n error: '#EF4444',\n success: '#22C55E',\n};\n\nexport function Modal({ config, metadata, onClose, onSubmit, onUpload }: ModalProps) {\n const [label, setLabel] = useState<'bug' | 'feature' | null>(null);\n const [text, setText] = useState('');\n const [email, setEmail] = useState('');\n const [imageUrl, setImageUrl] = useState<string | null>(null);\n const [imagePreview, setImagePreview] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [isUploading, setIsUploading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [success, setSuccess] = useState(false);\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const { i18n, formFields, theme } = config;\n const primaryColor = theme.primaryColor || '#0ea5e9';\n const maxLength = 400;\n\n // 동적 placeholder\n const currentPlaceholder = label === 'bug'\n ? (i18n.bugPlaceholder || i18n.placeholder)\n : (i18n.featurePlaceholder || i18n.placeholder);\n\n const handleFileSelect = async (e: Event) => {\n const target = e.target as HTMLInputElement;\n const file = target.files?.[0];\n if (!file) return;\n\n if (!file.type.startsWith('image/')) {\n setError('Only image files are allowed');\n return;\n }\n if (file.size > 10 * 1024 * 1024) {\n setError('Image must be under 10MB');\n return;\n }\n\n setIsUploading(true);\n setError(null);\n\n try {\n // 이미지를 WebP로 변환 및 resize\n const processedFile = await processImage(file, {\n maxWidth: 1920,\n maxHeight: 1080,\n quality: 0.8,\n });\n\n // 프리뷰 생성\n const reader = new FileReader();\n reader.onload = () => setImagePreview(reader.result as string);\n reader.readAsDataURL(processedFile);\n\n const url = await onUpload(processedFile);\n setIsUploading(false);\n\n if (url) {\n setImageUrl(url);\n } else {\n setError('Failed to upload image');\n setImagePreview(null);\n }\n } catch (err) {\n console.error('[Voyage] Image processing error:', err);\n setIsUploading(false);\n setError('Failed to process image');\n }\n };\n\n const handleRemoveImage = () => {\n setImageUrl(null);\n setImagePreview(null);\n if (fileInputRef.current) {\n fileInputRef.current.value = '';\n }\n };\n\n const handleSubmit = async () => {\n if (!label) {\n setError('Please select a type');\n return;\n }\n if (!text.trim()) {\n setError('Please enter your feedback');\n return;\n }\n if (formFields.email.required && !email.trim()) {\n setError('Please enter your email');\n return;\n }\n\n setIsSubmitting(true);\n setError(null);\n\n const feedbackData: FeedbackData = {\n label,\n text: text.trim(),\n email: email.trim() || undefined,\n imageUrl: imageUrl || undefined,\n metadata,\n };\n\n const result = await onSubmit(feedbackData);\n setIsSubmitting(false);\n\n if (result) {\n setSuccess(true);\n } else {\n setError('Failed to submit. Please try again.');\n }\n };\n\n // 스타일 함수 (primaryColor 적용)\n const getStyles = () => {\n const primaryBgLight = `${primaryColor}15`;\n\n return {\n overlay: {\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.4)',\n backdropFilter: 'blur(4px)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 9999,\n padding: '20px',\n } as h.JSX.CSSProperties,\n\n modal: {\n backgroundColor: colors.bgCard,\n backdropFilter: 'blur(20px)',\n borderRadius: '20px',\n width: '100%',\n maxWidth: '580px',\n maxHeight: '90vh',\n overflowY: 'auto',\n position: 'relative',\n fontFamily: \"'Quicksand', 'Nunito', system-ui, sans-serif\",\n border: `1px solid ${colors.border}`,\n boxShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.15)',\n } as h.JSX.CSSProperties,\n\n colorBar: {\n height: '4px',\n backgroundColor: primaryColor,\n } as h.JSX.CSSProperties,\n\n header: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '14px 20px',\n borderBottom: `1px solid ${colors.border}`,\n backgroundColor: colors.bgLight,\n } as h.JSX.CSSProperties,\n\n headerIcon: {\n width: '32px',\n height: '32px',\n borderRadius: '10px',\n backgroundColor: primaryColor,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#fff',\n } as h.JSX.CSSProperties,\n\n typeButton: (active: boolean) => ({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '6px',\n padding: '10px 12px',\n border: active ? `2px solid ${primaryColor}` : `1px solid ${colors.border}`,\n borderRadius: '10px',\n backgroundColor: active ? primaryBgLight : colors.bgLight,\n cursor: 'pointer',\n fontWeight: 600,\n fontSize: '13px',\n color: active ? colors.text : colors.textMuted,\n transition: 'all 0.2s',\n } as h.JSX.CSSProperties),\n\n submitButton: (disabled: boolean) => ({\n width: '100%',\n padding: '12px',\n backgroundColor: disabled ? colors.bgLight : primaryColor,\n color: disabled ? colors.textMuted : '#fff',\n border: 'none',\n borderRadius: '12px',\n fontSize: '15px',\n fontWeight: 700,\n cursor: disabled ? 'not-allowed' : 'pointer',\n fontFamily: 'inherit',\n transition: 'all 0.2s',\n boxShadow: disabled ? 'none' : `0 4px 15px ${primaryColor}40`,\n } as h.JSX.CSSProperties),\n\n primaryButton: {\n width: '100%',\n padding: '16px',\n backgroundColor: primaryColor,\n color: '#fff',\n border: 'none',\n borderRadius: '12px',\n fontSize: '15px',\n fontWeight: 700,\n cursor: 'pointer',\n fontFamily: 'inherit',\n marginTop: '8px',\n } as h.JSX.CSSProperties,\n };\n };\n\n const styles = getStyles();\n\n // 성공 화면\n if (success) {\n return (\n <div style={styles.overlay}>\n <div style={styles.modal}>\n <div style={successContainerStyle}>\n <div style={successIconStyle}>\n <CheckIcon />\n </div>\n <h3 style={successTitleStyle}>{i18n.successMessage}</h3>\n <p style={successTextStyle}>Your voice shapes what we build next.</p>\n <button onClick={onClose} style={styles.primaryButton}>\n Done\n </button>\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div style={styles.overlay} onClick={onClose}>\n <div style={styles.modal} onClick={(e) => e.stopPropagation()}>\n {/* 헤더 */}\n <div style={styles.header}>\n <div style={headerLeftStyle}>\n <div style={styles.headerIcon}>\n <MessageIcon size={20} />\n </div>\n <span style={headerTitleStyle}>Help Us Improve</span>\n </div>\n <button onClick={onClose} style={closeButtonStyle}>\n <CloseIcon />\n </button>\n </div>\n\n {/* 컬러 바 */}\n <div style={styles.colorBar} />\n\n {/* 컨텐츠 */}\n <div style={contentStyle}>\n {/* 이슈 타입 */}\n <div style={sectionStyle}>\n <label style={labelStyle}>Feedback Type</label>\n <div style={typeButtonsStyle}>\n <button\n onClick={() => setLabel('bug')}\n style={styles.typeButton(label === 'bug')}\n >\n <span style={typeIconStyle(label === 'bug', 'bug')}>\n <BugIcon />\n </span>\n <span>Bug</span>\n </button>\n <button\n onClick={() => setLabel('feature')}\n style={styles.typeButton(label === 'feature')}\n >\n <span style={typeIconStyle(label === 'feature', 'feature')}>\n <LightbulbIcon />\n </span>\n <span>Feature</span>\n </button>\n </div>\n </div>\n\n {/* 설명 + 이미지 (flex row) */}\n <div style={descriptionRowStyle}>\n {/* 텍스트 영역 */}\n <div style={descriptionColStyle}>\n <label style={labelStyle}>Description</label>\n <div style={textareaWrapperStyle}>\n <textarea\n placeholder={currentPlaceholder}\n value={text}\n maxLength={maxLength}\n onInput={(e) => setText((e.target as HTMLTextAreaElement).value)}\n style={textareaStyle}\n />\n <span style={charCountStyle}>{text.length}/{maxLength}</span>\n </div>\n </div>\n\n {/* 이미지 업로드 (정사각형) */}\n <div style={uploadColStyle}>\n <label style={labelStyle}>Screenshot</label>\n {imagePreview ? (\n <div style={imagePreviewContainerStyle}>\n <img src={imagePreview} alt=\"Preview\" style={imagePreviewSquareStyle} />\n <button onClick={handleRemoveImage} style={removeImageButtonStyle}>\n <CloseIcon />\n </button>\n {isUploading && <div style={uploadingOverlayStyle}>...</div>}\n </div>\n ) : (\n <button\n onClick={() => fileInputRef.current?.click()}\n style={uploadButtonSquareStyle}\n >\n <ImageIcon />\n <span style={{ fontSize: '11px' }}>Upload</span>\n </button>\n )}\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n onChange={handleFileSelect}\n style={{ display: 'none' }}\n />\n </div>\n </div>\n\n {/* 이메일 */}\n {formFields.email.enabled && (\n <div style={sectionStyle}>\n <label style={labelStyle}>\n Email {formFields.email.required ? '' : '(optional)'}\n </label>\n <input\n type=\"email\"\n placeholder=\"your@email.com\"\n value={email}\n onInput={(e) => setEmail((e.target as HTMLInputElement).value)}\n style={inputStyle}\n />\n </div>\n )}\n\n {/* 에러 */}\n {error && <p style={errorStyle}>{error}</p>}\n\n {/* 제출 버튼 */}\n <button\n onClick={handleSubmit}\n disabled={isSubmitting || isUploading}\n style={styles.submitButton(isSubmitting || isUploading)}\n >\n {isSubmitting ? (\n <span style={spinnerContainerStyle}>\n <span className=\"voyage-spinner\" />\n Sending...\n </span>\n ) : (\n i18n.submitLabel\n )}\n </button>\n </div>\n </div>\n </div>\n );\n}\n\n// 이미지 처리 유틸: resize + WebP 변환\ninterface ProcessImageOptions {\n maxWidth: number;\n maxHeight: number;\n quality: number;\n}\n\nasync function processImage(file: File, options: ProcessImageOptions): Promise<File> {\n const { maxWidth, maxHeight, quality } = options;\n\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n // 비율 유지하면서 resize 계산\n let { width, height } = img;\n\n if (width > maxWidth || height > maxHeight) {\n const ratio = Math.min(maxWidth / width, maxHeight / height);\n width = Math.round(width * ratio);\n height = Math.round(height * ratio);\n }\n\n // Canvas에 그리기\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n reject(new Error('Failed to get canvas context'));\n return;\n }\n\n ctx.drawImage(img, 0, 0, width, height);\n\n // WebP로 변환\n canvas.toBlob(\n (blob) => {\n if (!blob) {\n reject(new Error('Failed to convert image'));\n return;\n }\n\n // Blob을 File로 변환\n const timestamp = Date.now();\n const newFile = new File([blob], `image_${timestamp}.webp`, {\n type: 'image/webp',\n });\n\n resolve(newFile);\n },\n 'image/webp',\n quality\n );\n };\n\n img.onerror = () => reject(new Error('Failed to load image'));\n img.src = URL.createObjectURL(file);\n });\n}\n\n// 정적 스타일 정의 (라이트 테마)\nconst headerLeftStyle: h.JSX.CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n};\n\nconst headerTitleStyle: h.JSX.CSSProperties = {\n fontSize: '16px',\n fontWeight: 700,\n color: colors.text,\n};\n\nconst closeButtonStyle: h.JSX.CSSProperties = {\n background: 'transparent',\n border: 'none',\n color: colors.textMuted,\n cursor: 'pointer',\n padding: '8px',\n borderRadius: '8px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n transition: 'all 0.2s',\n};\n\nconst contentStyle: h.JSX.CSSProperties = {\n padding: '16px 20px',\n};\n\nconst sectionStyle: h.JSX.CSSProperties = {\n marginBottom: '14px',\n};\n\nconst labelStyle: h.JSX.CSSProperties = {\n display: 'block',\n fontSize: '13px',\n fontWeight: 600,\n color: colors.text,\n marginBottom: '8px',\n};\n\nconst typeButtonsStyle: h.JSX.CSSProperties = {\n display: 'grid',\n gridTemplateColumns: '1fr 1fr',\n gap: '12px',\n};\n\nconst descriptionRowStyle: h.JSX.CSSProperties = {\n display: 'flex',\n gap: '14px',\n marginBottom: '14px',\n};\n\nconst descriptionColStyle: h.JSX.CSSProperties = {\n flex: 1,\n display: 'flex',\n flexDirection: 'column',\n};\n\nconst uploadColStyle: h.JSX.CSSProperties = {\n width: '120px',\n flexShrink: 0,\n display: 'flex',\n flexDirection: 'column',\n};\n\nconst uploadButtonSquareStyle: h.JSX.CSSProperties = {\n width: '100%',\n aspectRatio: '1',\n border: `2px dashed ${colors.border}`,\n borderRadius: '10px',\n backgroundColor: 'transparent',\n cursor: 'pointer',\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '4px',\n color: colors.textMuted,\n fontSize: '12px',\n transition: 'all 0.2s',\n};\n\nconst imagePreviewSquareStyle: h.JSX.CSSProperties = {\n width: '100%',\n aspectRatio: '1',\n objectFit: 'cover',\n borderRadius: '10px',\n};\n\nconst typeIconStyle = (active: boolean, type: 'bug' | 'feature'): h.JSX.CSSProperties => ({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: active\n ? (type === 'bug' ? colors.error : '#F59E0B')\n : colors.textMuted,\n});\n\nconst textareaWrapperStyle: h.JSX.CSSProperties = {\n position: 'relative',\n};\n\nconst textareaStyle: h.JSX.CSSProperties = {\n width: '100%',\n minHeight: '120px',\n padding: '14px',\n border: `1px solid ${colors.border}`,\n borderRadius: '12px',\n fontSize: '14px',\n resize: 'vertical',\n boxSizing: 'border-box',\n backgroundColor: colors.bgLight,\n color: colors.text,\n fontFamily: 'inherit',\n outline: 'none',\n};\n\nconst charCountStyle: h.JSX.CSSProperties = {\n position: 'absolute',\n bottom: '12px',\n right: '14px',\n fontSize: '12px',\n color: colors.textMuted,\n};\n\nconst inputStyle: h.JSX.CSSProperties = {\n width: '100%',\n padding: '10px 12px',\n border: `1px solid ${colors.border}`,\n borderRadius: '10px',\n fontSize: '13px',\n boxSizing: 'border-box',\n backgroundColor: colors.bgLight,\n color: colors.text,\n fontFamily: 'inherit',\n outline: 'none',\n};\n\nconst imagePreviewContainerStyle: h.JSX.CSSProperties = {\n position: 'relative',\n display: 'inline-block',\n borderRadius: '12px',\n overflow: 'hidden',\n};\n\nconst removeImageButtonStyle: h.JSX.CSSProperties = {\n position: 'absolute',\n top: '8px',\n right: '8px',\n width: '28px',\n height: '28px',\n borderRadius: '50%',\n backgroundColor: 'rgba(0, 0, 0, 0.7)',\n color: '#fff',\n border: 'none',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n};\n\nconst uploadingOverlayStyle: h.JSX.CSSProperties = {\n position: 'absolute',\n inset: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.7)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#fff',\n fontSize: '14px',\n borderRadius: '12px',\n};\n\nconst errorStyle: h.JSX.CSSProperties = {\n color: colors.error,\n fontSize: '14px',\n marginBottom: '16px',\n padding: '12px',\n backgroundColor: 'rgba(239, 68, 68, 0.1)',\n borderRadius: '8px',\n border: `1px solid rgba(239, 68, 68, 0.3)`,\n};\n\nconst successContainerStyle: h.JSX.CSSProperties = {\n padding: '48px 24px',\n textAlign: 'center',\n};\n\nconst successIconStyle: h.JSX.CSSProperties = {\n width: '64px',\n height: '64px',\n borderRadius: '50%',\n backgroundColor: 'rgba(34, 197, 94, 0.15)',\n color: colors.success,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n margin: '0 auto 20px',\n};\n\nconst successTitleStyle: h.JSX.CSSProperties = {\n fontSize: '20px',\n fontWeight: 700,\n color: colors.text,\n marginBottom: '8px',\n};\n\nconst successTextStyle: h.JSX.CSSProperties = {\n fontSize: '14px',\n color: colors.textMuted,\n marginBottom: '24px',\n};\n\nconst spinnerContainerStyle: h.JSX.CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '8px',\n};\n","import { h } from 'preact';\nimport { useState, useEffect } from 'preact/hooks';\nimport { Button } from './Button';\nimport { Modal } from './Modal';\nimport type { ProjectConfig, FeedbackData, FeedbackMetadata } from '../types';\n\ninterface WidgetProps {\n config: ProjectConfig;\n onSubmit: (data: FeedbackData) => Promise<boolean>;\n onUpload: (file: File) => Promise<string | null>;\n getMetadata: () => FeedbackMetadata;\n visible: boolean;\n defaultOpen?: boolean;\n hasError?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\nexport function Widget({\n config,\n onSubmit,\n onUpload,\n getMetadata,\n visible,\n defaultOpen = false,\n hasError = false,\n onOpenChange,\n}: WidgetProps) {\n const [isOpen, setIsOpen] = useState(defaultOpen);\n\n // SDK에서 open()/close() 호출 시 동기화\n useEffect(() => {\n setIsOpen(defaultOpen);\n }, [defaultOpen]);\n\n useEffect(() => {\n onOpenChange?.(isOpen);\n }, [isOpen, onOpenChange]);\n\n if (!visible) {\n return null;\n }\n\n const { theme, i18n } = config;\n\n return (\n <>\n {!isOpen && (\n <Button\n onClick={() => setIsOpen(true)}\n label={i18n.buttonLabel}\n position={theme.position}\n primaryColor={theme.primaryColor}\n hasError={hasError}\n />\n )}\n\n {isOpen && (\n <Modal\n config={config}\n metadata={getMetadata()}\n onClose={() => setIsOpen(false)}\n onSubmit={onSubmit}\n onUpload={onUpload}\n />\n )}\n </>\n );\n}\n","// SDK 전용 CSS 스타일 (동적 주입)\nexport const injectStyles = () => {\n if (typeof document === 'undefined') return;\n if (document.getElementById('voyage-sdk-styles')) return;\n\n const style = document.createElement('style');\n style.id = 'voyage-sdk-styles';\n style.textContent = `\n /* Voyage SDK Styles */\n\n /* Spinner Animation */\n @keyframes voyage-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n\n #voyage-widget-container * {\n box-sizing: border-box;\n }\n\n #voyage-widget-container button {\n font-family: 'Quicksand', 'Nunito', system-ui, sans-serif;\n }\n\n #voyage-widget-container textarea:focus,\n #voyage-widget-container input:focus {\n border-color: rgba(124, 58, 237, 0.5);\n box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);\n }\n\n #voyage-widget-container button:focus {\n outline: none;\n }\n\n /* Spinner */\n .voyage-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid rgba(255,255,255,0.3);\n border-top-color: #fff;\n border-radius: 50%;\n animation: voyage-spin 0.8s linear infinite;\n }\n\n /* Load Quicksand font if not present */\n @import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@400;500;600;700&display=swap');\n `;\n\n document.head.appendChild(style);\n};\n","import type { ProjectConfig, FeedbackData } from '../types';\n\n// Supabase Edge Functions URL\nconst API_BASE = 'https://rxflzurkkuqgopjkshjh.supabase.co/functions/v1';\n\nconst CACHE_KEY = 'voyage_config';\nconst CACHE_TTL = 60 * 60 * 1000; // 1시간\n\ninterface CachedConfig {\n config: ProjectConfig;\n timestamp: number;\n}\n\nexport async function fetchProjectConfig(sdkKey: string): Promise<ProjectConfig | null> {\n // 캐시 확인\n const cached = getFromCache(sdkKey);\n if (cached) {\n return cached;\n }\n\n try {\n const response = await fetch(`${API_BASE}/get-widget-config`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'x-sdk-key': sdkKey,\n },\n });\n\n if (!response.ok) {\n console.error('[Voyage] Failed to fetch config:', response.status);\n return null;\n }\n\n const config = await response.json() as ProjectConfig;\n saveToCache(sdkKey, config);\n return config;\n } catch (error) {\n console.error('[Voyage] Network error:', error);\n // 네트워크 실패 시 캐시 사용 (만료되어도)\n return getFromCache(sdkKey, true);\n }\n}\n\nexport async function submitFeedback(sdkKey: string, data: FeedbackData): Promise<boolean> {\n try {\n const response = await fetch(`${API_BASE}/submit-feedback`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-sdk-key': sdkKey,\n },\n body: JSON.stringify({\n label: data.label,\n content: data.text,\n email: data.email,\n imageUrl: data.imageUrl,\n metadata: data.metadata,\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n console.error('[Voyage] Failed to submit feedback:', response.status, errorData);\n return false;\n }\n\n return true;\n } catch (error) {\n console.error('[Voyage] Network error:', error);\n return false;\n }\n}\n\nexport async function uploadImage(sdkKey: string, file: File): Promise<string | null> {\n // 검증\n if (!file.type.startsWith('image/')) {\n console.error('[Voyage] Only image files are allowed');\n return null;\n }\n\n if (file.size > 5 * 1024 * 1024) {\n console.error('[Voyage] Image must be under 5MB');\n return null;\n }\n\n try {\n const formData = new FormData();\n formData.append('file', file);\n\n const response = await fetch(`${API_BASE}/upload-feedback-image`, {\n method: 'POST',\n headers: {\n 'x-sdk-key': sdkKey,\n },\n body: formData,\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n console.error('[Voyage] Failed to upload image:', response.status, errorData);\n return null;\n }\n\n const result = await response.json();\n return result.url;\n } catch (error) {\n console.error('[Voyage] Network error:', error);\n return null;\n }\n}\n\nfunction getFromCache(sdkKey: string, ignoreExpiry = false): ProjectConfig | null {\n try {\n const raw = localStorage.getItem(`${CACHE_KEY}_${sdkKey}`);\n if (!raw) return null;\n\n const cached: CachedConfig = JSON.parse(raw);\n const isExpired = Date.now() - cached.timestamp > CACHE_TTL;\n\n if (isExpired && !ignoreExpiry) {\n return null;\n }\n\n return cached.config;\n } catch {\n return null;\n }\n}\n\nfunction saveToCache(sdkKey: string, config: ProjectConfig): void {\n try {\n const cached: CachedConfig = {\n config,\n timestamp: Date.now(),\n };\n localStorage.setItem(`${CACHE_KEY}_${sdkKey}`, JSON.stringify(cached));\n } catch {\n // localStorage 사용 불가 시 무시\n }\n}\n","import type { FeedbackMetadata } from '../types';\n\nexport function captureMetadata(): FeedbackMetadata {\n return {\n url: window.location.href,\n pathname: window.location.pathname,\n browser: navigator.userAgent,\n viewport: `${window.innerWidth}x${window.innerHeight}`,\n title: document.title,\n timestamp: new Date().toISOString(),\n locale: navigator.language,\n referrer: document.referrer,\n };\n}\n","// @voyage/sdk\n// Feedback Widget SDK for collecting user feedback\n\nimport { h, render } from 'preact';\n\nimport { Widget } from './components';\nimport { injectStyles } from './styles';\nimport { fetchProjectConfig, submitFeedback, uploadImage } from './utils/api';\nimport { captureMetadata } from './utils/metadata';\n\nimport type { VoyageConfig, ProjectConfig, FeedbackData } from './types';\n\nexport type { VoyageConfig, ProjectConfig, FeedbackData, FeedbackMetadata } from './types';\n\nconst DEFAULT_CONFIG: ProjectConfig = {\n projectId: '',\n formFields: {\n email: { enabled: true, required: false },\n category: { enabled: true, options: ['bug', 'feature'] },\n },\n theme: {\n primaryColor: '#0ea5e9',\n position: 'bottom-right',\n },\n i18n: {\n buttonLabel: 'To : the Maker',\n placeholder: 'Describe your ideas to improve our product',\n bugPlaceholder: 'Please describe the bug in detail (e.g., clicked a button and it didn\\'t work)',\n featurePlaceholder: 'Describe your ideas to improve our product (e.g., I want to export TASK.md to Linear tickets)',\n submitLabel: 'Send to the Maker',\n successMessage: 'Thank you for your feedback!',\n },\n};\n\nclass VoyageSDK {\n private config: VoyageConfig | null = null;\n private serverConfig: ProjectConfig | null = null;\n private container: HTMLElement | null = null;\n private isWidgetVisible = false;\n private isModalOpen = false;\n private hasInitError = false;\n\n async init(config: VoyageConfig): Promise<void> {\n this.config = config;\n this.hasInitError = false;\n\n if (!config.sdkKey) {\n console.error('[Voyage] SDK Key is required. Get your key from the dashboard.');\n this.hasInitError = true;\n injectStyles();\n this.isWidgetVisible = true;\n this.serverConfig = { ...DEFAULT_CONFIG };\n this.renderWidget();\n return;\n }\n\n // Inject SDK styles\n injectStyles();\n\n // Check display control\n if (!this.shouldDisplay()) {\n console.log('[Voyage] Widget hidden by display rules');\n return;\n }\n\n // Fetch server config\n const fetchedConfig = await fetchProjectConfig(config.sdkKey);\n\n if (!fetchedConfig) {\n console.error('[Voyage] Failed to fetch config. Check your SDK Key or network connection.');\n this.hasInitError = true;\n this.serverConfig = { ...DEFAULT_CONFIG };\n this.isWidgetVisible = true;\n this.renderWidget();\n return;\n }\n\n this.serverConfig = this.mergeConfig(fetchedConfig, config);\n\n // Render widget\n this.isWidgetVisible = true;\n this.renderWidget();\n console.log('[Voyage] Initialized');\n }\n\n show(): void {\n if (!this.config) {\n console.warn('[Voyage] SDK not initialized');\n return;\n }\n this.isWidgetVisible = true;\n this.renderWidget();\n }\n\n hide(): void {\n this.isWidgetVisible = false;\n this.renderWidget();\n }\n\n open(): void {\n if (!this.config) {\n console.warn('[Voyage] SDK not initialized');\n return;\n }\n this.isModalOpen = true;\n this.renderWidget();\n }\n\n close(): void {\n this.isModalOpen = false;\n this.renderWidget();\n }\n\n isOpen(): boolean {\n return this.isModalOpen;\n }\n\n isVisible(): boolean {\n return this.isWidgetVisible;\n }\n\n async refreshConfig(): Promise<void> {\n if (!this.config) return;\n const fetchedConfig = await fetchProjectConfig(this.config.sdkKey);\n this.serverConfig = this.mergeConfig(fetchedConfig, this.config);\n this.renderWidget();\n }\n\n destroy(): void {\n if (this.container) {\n render(null, this.container);\n this.container.remove();\n this.container = null;\n }\n this.config = null;\n this.serverConfig = null;\n this.isWidgetVisible = false;\n this.isModalOpen = false;\n }\n\n private renderWidget(): void {\n if (!this.serverConfig || !this.config) return;\n\n // Create container if not exists\n if (!this.container) {\n this.container = document.createElement('div');\n this.container.id = 'voyage-widget-container';\n document.body.appendChild(this.container);\n }\n\n const sdkKey = this.config.sdkKey;\n\n render(\n h(Widget, {\n config: this.serverConfig,\n visible: this.isWidgetVisible,\n defaultOpen: this.isModalOpen,\n hasError: this.hasInitError,\n onOpenChange: (open: boolean) => {\n this.isModalOpen = open;\n },\n getMetadata: captureMetadata,\n onSubmit: async (data: FeedbackData) => {\n return submitFeedback(sdkKey, data);\n },\n onUpload: async (file: File) => {\n return uploadImage(sdkKey, file);\n },\n }),\n this.container\n );\n }\n\n private mergeConfig(server: ProjectConfig | null, _client: VoyageConfig): ProjectConfig {\n // Server config takes priority: use values set from dashboard\n // Client-side theme override disabled (to prevent config conflicts)\n return server || { ...DEFAULT_CONFIG };\n }\n\n private shouldDisplay(): boolean {\n if (!this.config) return false;\n\n const pathname = window.location.pathname;\n const { include, exclude } = this.config;\n\n // include takes priority over exclude\n if (include && include.length > 0) {\n return include.some((pattern) => this.matchPath(pathname, pattern));\n }\n\n if (exclude && exclude.length > 0) {\n return !exclude.some((pattern) => this.matchPath(pathname, pattern));\n }\n\n return true;\n }\n\n private matchPath(pathname: string, pattern: string): boolean {\n // Simple glob matching: /admin/* matches /admin/anything\n if (pattern.endsWith('/*')) {\n const prefix = pattern.slice(0, -2);\n return pathname.startsWith(prefix);\n }\n return pathname === pattern;\n }\n}\n\n// Singleton instance\nconst Voyage = new VoyageSDK();\n\nexport { Voyage };\nexport default Voyage;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/Button.tsx","../src/components/Modal.tsx","../src/components/Widget.tsx","../src/styles.ts","../src/utils/api.ts","../src/utils/metadata.ts","../src/index.ts"],"names":["MessageIcon","jsx","Button","onClick","label","position","primaryColor","hasError","isHovered","setIsHovered","useState","isPressed","setIsPressed","positionStyle","getTransform","jsxs","size","BugIcon","LightbulbIcon","ImageIcon","CloseIcon","CheckIcon","colors","Modal","config","metadata","onClose","onSubmit","onUpload","setLabel","text","setText","email","setEmail","imageUrl","setImageUrl","imagePreview","setImagePreview","isSubmitting","setIsSubmitting","isUploading","setIsUploading","error","setError","success","setSuccess","fileInputRef","useRef","i18n","formFields","theme","maxLength","currentPlaceholder","handleFileSelect","e","file","processedFile","processImage","reader","url","err","handleRemoveImage","handleSubmit","feedbackData","result","styles","primaryBgLight","active","disabled","successContainerStyle","successIconStyle","successTitleStyle","successTextStyle","headerLeftStyle","headerTitleStyle","closeButtonStyle","contentStyle","sectionStyle","labelStyle","typeButtonsStyle","typeIconStyle","descriptionRowStyle","descriptionColStyle","textareaWrapperStyle","textareaStyle","charCountStyle","uploadColStyle","imagePreviewContainerStyle","imagePreviewSquareStyle","removeImageButtonStyle","uploadingOverlayStyle","uploadButtonSquareStyle","inputStyle","errorStyle","spinnerContainerStyle","options","maxWidth","maxHeight","quality","resolve","reject","img","width","height","ratio","canvas","ctx","blob","timestamp","newFile","type","Widget","getMetadata","visible","defaultOpen","onOpenChange","isOpen","setIsOpen","useEffect","Fragment","injectStyles","style","API_BASE","CACHE_KEY","fetchWithTimeout","timeoutMs","controller","timeoutId","fetchProjectConfig","sdkKey","forceRefresh","cached","getFromCache","response","saveToCache","submitFeedback","data","errorData","uploadImage","formData","getCachedConfig","ignoreExpiry","raw","captureMetadata","DEFAULT_CONFIG","VoyageSDK","cachedConfig","fetchedConfig","freshConfig","newConfig","render","h","open","server","_client","pathname","include","exclude","pattern","prefix","Voyage","index_default"],"mappings":"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","file":"index.js","sourcesContent":["import { h } from 'preact';\nimport { useState } from 'preact/hooks';\n\ninterface ButtonProps {\n onClick: () => void;\n label: string;\n position: 'bottom-right' | 'bottom-left';\n primaryColor: string;\n hasError?: boolean;\n}\n\n// 말풍선 아이콘 SVG\nfunction MessageIcon() {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n );\n}\n\n// 에러 아이콘 (느낌표)\nfunction ErrorIcon() {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"#fff\"\n stroke=\"none\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"12\" fill=\"#EF4444\" />\n <text x=\"12\" y=\"17\" textAnchor=\"middle\" fill=\"#fff\" fontSize=\"14\" fontWeight=\"bold\">!</text>\n </svg>\n );\n}\n\nexport function Button({ onClick, label, position, primaryColor, hasError = false }: ButtonProps) {\n const [isHovered, setIsHovered] = useState(false);\n const [isPressed, setIsPressed] = useState(false);\n\n const positionStyle = position === 'bottom-right'\n ? { right: '24px' }\n : { left: '24px' };\n\n // Jelly 효과 transform\n const getTransform = () => {\n if (isPressed) return 'scale(0.95)';\n if (isHovered) return 'scale(1.02) translateY(-2px)';\n return 'scale(1)';\n };\n\n return (\n <div style={{ position: 'fixed', bottom: '24px', ...positionStyle, zIndex: 9998 }}>\n <button\n onClick={onClick}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => { setIsHovered(false); setIsPressed(false); }}\n onMouseDown={() => setIsPressed(true)}\n onMouseUp={() => setIsPressed(false)}\n style={{\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n padding: '14px 24px',\n border: 'none',\n borderRadius: '50px',\n cursor: 'pointer',\n fontFamily: \"'Quicksand', 'Nunito', system-ui, sans-serif\",\n fontSize: '15px',\n fontWeight: 600,\n color: '#fff',\n // primaryColor 적용\n backgroundColor: primaryColor,\n // 그림자 + glow 효과\n boxShadow: isHovered\n ? `0 8px 32px ${primaryColor}60, 0 0 20px ${primaryColor}40`\n : `0 4px 20px ${primaryColor}50, 0 0 10px ${primaryColor}30`,\n // Jelly 애니메이션\n transform: getTransform(),\n transition: 'all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1)',\n }}\n >\n <MessageIcon />\n <span>{label}</span>\n </button>\n {/* 에러 아이콘 - 우측 상단 */}\n {hasError && (\n <div\n style={{\n position: 'absolute',\n top: '-4px',\n right: '-4px',\n width: '18px',\n height: '18px',\n borderRadius: '50%',\n backgroundColor: '#EF4444',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#fff',\n fontSize: '12px',\n fontWeight: 'bold',\n boxShadow: '0 2px 6px rgba(239, 68, 68, 0.5)',\n }}\n >\n !\n </div>\n )}\n </div>\n );\n}\n","import { h } from 'preact';\nimport { useRef, useState } from 'preact/hooks';\n\nimport type { ProjectConfig, FeedbackData, FeedbackMetadata } from '../types';\n\ninterface ModalProps {\n config: ProjectConfig;\n metadata: FeedbackMetadata;\n onClose: () => void;\n onSubmit: (data: FeedbackData) => Promise<boolean>;\n onUpload: (file: File) => Promise<string | null>;\n}\n\n// 아이콘들\nfunction MessageIcon({ size = 24 }: { size?: number }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n );\n}\n\nfunction BugIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M8 2l1.88 1.88M14.12 3.88L16 2M9 7.13v-1a3.003 3.003 0 116 0v1\" />\n <path d=\"M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 014-4h4a4 4 0 014 4v3c0 3.3-2.7 6-6 6\" />\n <path d=\"M12 20v-9M6.53 9C4.6 8.8 3 7.1 3 5M6 13H2M6 17l-4 1M17.47 9c1.93-.2 3.53-1.9 3.53-4M18 13h4M18 17l4 1\" />\n </svg>\n );\n}\n\nfunction LightbulbIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 006 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\" />\n <path d=\"M9 18h6M10 22h4\" />\n </svg>\n );\n}\n\nfunction ImageIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\" />\n <polyline points=\"21 15 16 10 5 21\" />\n </svg>\n );\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\nfunction CheckIcon() {\n return (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n );\n}\n\n// 라이트 테마 색상\nconst colors = {\n bg: '#FFFFFF',\n bgLight: '#F8FAFC',\n bgCard: 'rgba(255, 255, 255, 0.98)',\n border: 'rgba(0, 0, 0, 0.08)',\n borderLight: 'rgba(0, 0, 0, 0.12)',\n text: '#1F2937',\n textMuted: '#6B7280',\n error: '#EF4444',\n success: '#22C55E',\n};\n\nexport function Modal({ config, metadata, onClose, onSubmit, onUpload }: ModalProps) {\n const [label, setLabel] = useState<'bug' | 'feature' | null>(null);\n const [text, setText] = useState('');\n const [email, setEmail] = useState('');\n const [imageUrl, setImageUrl] = useState<string | null>(null);\n const [imagePreview, setImagePreview] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [isUploading, setIsUploading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [success, setSuccess] = useState(false);\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const { i18n, formFields, theme } = config;\n const primaryColor = theme.primaryColor || '#0ea5e9';\n const maxLength = 400;\n\n // 동적 placeholder\n const currentPlaceholder = label === 'bug'\n ? (i18n.bugPlaceholder || i18n.placeholder)\n : (i18n.featurePlaceholder || i18n.placeholder);\n\n const handleFileSelect = async (e: Event) => {\n const target = e.target as HTMLInputElement;\n const file = target.files?.[0];\n if (!file) return;\n\n if (!file.type.startsWith('image/')) {\n setError('Only image files are allowed');\n return;\n }\n if (file.size > 10 * 1024 * 1024) {\n setError('Image must be under 10MB');\n return;\n }\n\n setIsUploading(true);\n setError(null);\n\n try {\n // 이미지를 WebP로 변환 및 resize\n const processedFile = await processImage(file, {\n maxWidth: 1920,\n maxHeight: 1080,\n quality: 0.8,\n });\n\n // 프리뷰 생성\n const reader = new FileReader();\n reader.onload = () => setImagePreview(reader.result as string);\n reader.readAsDataURL(processedFile);\n\n const url = await onUpload(processedFile);\n setIsUploading(false);\n\n if (url) {\n setImageUrl(url);\n } else {\n setError('Failed to upload image');\n setImagePreview(null);\n }\n } catch (err) {\n console.error('[Voyage] Image processing error:', err);\n setIsUploading(false);\n setError('Failed to process image');\n }\n };\n\n const handleRemoveImage = () => {\n setImageUrl(null);\n setImagePreview(null);\n if (fileInputRef.current) {\n fileInputRef.current.value = '';\n }\n };\n\n const handleSubmit = async () => {\n if (!label) {\n setError('Please select a type');\n return;\n }\n if (!text.trim()) {\n setError('Please enter your feedback');\n return;\n }\n if (formFields.email.required && !email.trim()) {\n setError('Please enter your email');\n return;\n }\n\n setIsSubmitting(true);\n setError(null);\n\n const feedbackData: FeedbackData = {\n label,\n text: text.trim(),\n email: email.trim() || undefined,\n imageUrl: imageUrl || undefined,\n metadata,\n };\n\n const result = await onSubmit(feedbackData);\n setIsSubmitting(false);\n\n if (result) {\n setSuccess(true);\n } else {\n setError('Failed to submit. Please try again.');\n }\n };\n\n // 스타일 함수 (primaryColor 적용)\n const getStyles = () => {\n const primaryBgLight = `${primaryColor}15`;\n\n return {\n overlay: {\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.4)',\n backdropFilter: 'blur(4px)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 9999,\n padding: '20px',\n } as h.JSX.CSSProperties,\n\n modal: {\n backgroundColor: colors.bgCard,\n backdropFilter: 'blur(20px)',\n borderRadius: '20px',\n width: '100%',\n maxWidth: '580px',\n maxHeight: '90vh',\n overflowY: 'auto',\n position: 'relative',\n fontFamily: \"'Quicksand', 'Nunito', system-ui, sans-serif\",\n border: `1px solid ${colors.border}`,\n boxShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.15)',\n } as h.JSX.CSSProperties,\n\n colorBar: {\n height: '4px',\n backgroundColor: primaryColor,\n } as h.JSX.CSSProperties,\n\n header: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '14px 20px',\n borderBottom: `1px solid ${colors.border}`,\n backgroundColor: colors.bgLight,\n } as h.JSX.CSSProperties,\n\n headerIcon: {\n width: '32px',\n height: '32px',\n borderRadius: '10px',\n backgroundColor: primaryColor,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#fff',\n } as h.JSX.CSSProperties,\n\n typeButton: (active: boolean) => ({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '6px',\n padding: '10px 12px',\n border: active ? `2px solid ${primaryColor}` : `1px solid ${colors.border}`,\n borderRadius: '10px',\n backgroundColor: active ? primaryBgLight : colors.bgLight,\n cursor: 'pointer',\n fontWeight: 600,\n fontSize: '13px',\n color: active ? colors.text : colors.textMuted,\n transition: 'all 0.2s',\n } as h.JSX.CSSProperties),\n\n submitButton: (disabled: boolean) => ({\n width: '100%',\n padding: '12px',\n backgroundColor: disabled ? colors.bgLight : primaryColor,\n color: disabled ? colors.textMuted : '#fff',\n border: 'none',\n borderRadius: '12px',\n fontSize: '15px',\n fontWeight: 700,\n cursor: disabled ? 'not-allowed' : 'pointer',\n fontFamily: 'inherit',\n transition: 'all 0.2s',\n boxShadow: disabled ? 'none' : `0 4px 15px ${primaryColor}40`,\n } as h.JSX.CSSProperties),\n\n primaryButton: {\n width: '100%',\n padding: '16px',\n backgroundColor: primaryColor,\n color: '#fff',\n border: 'none',\n borderRadius: '12px',\n fontSize: '15px',\n fontWeight: 700,\n cursor: 'pointer',\n fontFamily: 'inherit',\n marginTop: '8px',\n } as h.JSX.CSSProperties,\n };\n };\n\n const styles = getStyles();\n\n // 성공 화면\n if (success) {\n return (\n <div style={styles.overlay}>\n <div style={styles.modal}>\n <div style={successContainerStyle}>\n <div style={successIconStyle}>\n <CheckIcon />\n </div>\n <h3 style={successTitleStyle}>{i18n.successMessage}</h3>\n <p style={successTextStyle}>Your voice shapes what we build next.</p>\n <button onClick={onClose} style={styles.primaryButton}>\n Done\n </button>\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div style={styles.overlay} onClick={onClose}>\n <div style={styles.modal} onClick={(e) => e.stopPropagation()}>\n {/* 헤더 */}\n <div style={styles.header}>\n <div style={headerLeftStyle}>\n <div style={styles.headerIcon}>\n <MessageIcon size={20} />\n </div>\n <span style={headerTitleStyle}>Help Us Improve</span>\n </div>\n <button onClick={onClose} style={closeButtonStyle}>\n <CloseIcon />\n </button>\n </div>\n\n {/* 컬러 바 */}\n <div style={styles.colorBar} />\n\n {/* 컨텐츠 */}\n <div style={contentStyle}>\n {/* 이슈 타입 */}\n <div style={sectionStyle}>\n <label style={labelStyle}>Feedback Type</label>\n <div style={typeButtonsStyle}>\n <button\n onClick={() => setLabel('bug')}\n style={styles.typeButton(label === 'bug')}\n >\n <span style={typeIconStyle(label === 'bug', 'bug')}>\n <BugIcon />\n </span>\n <span>Bug</span>\n </button>\n <button\n onClick={() => setLabel('feature')}\n style={styles.typeButton(label === 'feature')}\n >\n <span style={typeIconStyle(label === 'feature', 'feature')}>\n <LightbulbIcon />\n </span>\n <span>Feature</span>\n </button>\n </div>\n </div>\n\n {/* 설명 + 이미지 (flex row) */}\n <div style={descriptionRowStyle}>\n {/* 텍스트 영역 */}\n <div style={descriptionColStyle}>\n <label style={labelStyle}>Description</label>\n <div style={textareaWrapperStyle}>\n <textarea\n placeholder={currentPlaceholder}\n value={text}\n maxLength={maxLength}\n onInput={(e) => setText((e.target as HTMLTextAreaElement).value)}\n style={textareaStyle}\n />\n <span style={charCountStyle}>{text.length}/{maxLength}</span>\n </div>\n </div>\n\n {/* 이미지 업로드 (정사각형) */}\n <div style={uploadColStyle}>\n <label style={labelStyle}>Screenshot</label>\n {imagePreview ? (\n <div style={imagePreviewContainerStyle}>\n <img src={imagePreview} alt=\"Preview\" style={imagePreviewSquareStyle} />\n <button onClick={handleRemoveImage} style={removeImageButtonStyle}>\n <CloseIcon />\n </button>\n {isUploading && <div style={uploadingOverlayStyle}>...</div>}\n </div>\n ) : (\n <button\n onClick={() => fileInputRef.current?.click()}\n style={uploadButtonSquareStyle}\n >\n <ImageIcon />\n <span style={{ fontSize: '11px' }}>Upload</span>\n </button>\n )}\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n onChange={handleFileSelect}\n style={{ display: 'none' }}\n />\n </div>\n </div>\n\n {/* 이메일 */}\n {formFields.email.enabled && (\n <div style={sectionStyle}>\n <label style={labelStyle}>\n Email {formFields.email.required ? '' : '(optional)'}\n </label>\n <input\n type=\"email\"\n placeholder=\"your@email.com\"\n value={email}\n onInput={(e) => setEmail((e.target as HTMLInputElement).value)}\n style={inputStyle}\n />\n </div>\n )}\n\n {/* 에러 */}\n {error && <p style={errorStyle}>{error}</p>}\n\n {/* 제출 버튼 */}\n <button\n onClick={handleSubmit}\n disabled={isSubmitting || isUploading}\n style={styles.submitButton(isSubmitting || isUploading)}\n >\n {isSubmitting ? (\n <span style={spinnerContainerStyle}>\n <span className=\"voyage-spinner\" />\n Sending...\n </span>\n ) : (\n i18n.submitLabel\n )}\n </button>\n </div>\n </div>\n </div>\n );\n}\n\n// 이미지 처리 유틸: resize + WebP 변환\ninterface ProcessImageOptions {\n maxWidth: number;\n maxHeight: number;\n quality: number;\n}\n\nasync function processImage(file: File, options: ProcessImageOptions): Promise<File> {\n const { maxWidth, maxHeight, quality } = options;\n\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n // 비율 유지하면서 resize 계산\n let { width, height } = img;\n\n if (width > maxWidth || height > maxHeight) {\n const ratio = Math.min(maxWidth / width, maxHeight / height);\n width = Math.round(width * ratio);\n height = Math.round(height * ratio);\n }\n\n // Canvas에 그리기\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n reject(new Error('Failed to get canvas context'));\n return;\n }\n\n ctx.drawImage(img, 0, 0, width, height);\n\n // WebP로 변환\n canvas.toBlob(\n (blob) => {\n if (!blob) {\n reject(new Error('Failed to convert image'));\n return;\n }\n\n // Blob을 File로 변환\n const timestamp = Date.now();\n const newFile = new File([blob], `image_${timestamp}.webp`, {\n type: 'image/webp',\n });\n\n resolve(newFile);\n },\n 'image/webp',\n quality\n );\n };\n\n img.onerror = () => reject(new Error('Failed to load image'));\n img.src = URL.createObjectURL(file);\n });\n}\n\n// 정적 스타일 정의 (라이트 테마)\nconst headerLeftStyle: h.JSX.CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n};\n\nconst headerTitleStyle: h.JSX.CSSProperties = {\n fontSize: '16px',\n fontWeight: 700,\n color: colors.text,\n};\n\nconst closeButtonStyle: h.JSX.CSSProperties = {\n background: 'transparent',\n border: 'none',\n color: colors.textMuted,\n cursor: 'pointer',\n padding: '8px',\n borderRadius: '8px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n transition: 'all 0.2s',\n};\n\nconst contentStyle: h.JSX.CSSProperties = {\n padding: '16px 20px',\n};\n\nconst sectionStyle: h.JSX.CSSProperties = {\n marginBottom: '14px',\n};\n\nconst labelStyle: h.JSX.CSSProperties = {\n display: 'block',\n fontSize: '13px',\n fontWeight: 600,\n color: colors.text,\n marginBottom: '8px',\n};\n\nconst typeButtonsStyle: h.JSX.CSSProperties = {\n display: 'grid',\n gridTemplateColumns: '1fr 1fr',\n gap: '12px',\n};\n\nconst descriptionRowStyle: h.JSX.CSSProperties = {\n display: 'flex',\n gap: '14px',\n marginBottom: '14px',\n};\n\nconst descriptionColStyle: h.JSX.CSSProperties = {\n flex: 1,\n display: 'flex',\n flexDirection: 'column',\n};\n\nconst uploadColStyle: h.JSX.CSSProperties = {\n width: '120px',\n flexShrink: 0,\n display: 'flex',\n flexDirection: 'column',\n};\n\nconst uploadButtonSquareStyle: h.JSX.CSSProperties = {\n width: '100%',\n aspectRatio: '1',\n border: `2px dashed ${colors.border}`,\n borderRadius: '10px',\n backgroundColor: 'transparent',\n cursor: 'pointer',\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '4px',\n color: colors.textMuted,\n fontSize: '12px',\n transition: 'all 0.2s',\n};\n\nconst imagePreviewSquareStyle: h.JSX.CSSProperties = {\n width: '100%',\n aspectRatio: '1',\n objectFit: 'cover',\n borderRadius: '10px',\n};\n\nconst typeIconStyle = (active: boolean, type: 'bug' | 'feature'): h.JSX.CSSProperties => ({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: active\n ? (type === 'bug' ? colors.error : '#F59E0B')\n : colors.textMuted,\n});\n\nconst textareaWrapperStyle: h.JSX.CSSProperties = {\n position: 'relative',\n};\n\nconst textareaStyle: h.JSX.CSSProperties = {\n width: '100%',\n minHeight: '120px',\n padding: '14px',\n border: `1px solid ${colors.border}`,\n borderRadius: '12px',\n fontSize: '14px',\n resize: 'vertical',\n boxSizing: 'border-box',\n backgroundColor: colors.bgLight,\n color: colors.text,\n fontFamily: 'inherit',\n outline: 'none',\n};\n\nconst charCountStyle: h.JSX.CSSProperties = {\n position: 'absolute',\n bottom: '12px',\n right: '14px',\n fontSize: '12px',\n color: colors.textMuted,\n};\n\nconst inputStyle: h.JSX.CSSProperties = {\n width: '100%',\n padding: '10px 12px',\n border: `1px solid ${colors.border}`,\n borderRadius: '10px',\n fontSize: '13px',\n boxSizing: 'border-box',\n backgroundColor: colors.bgLight,\n color: colors.text,\n fontFamily: 'inherit',\n outline: 'none',\n};\n\nconst imagePreviewContainerStyle: h.JSX.CSSProperties = {\n position: 'relative',\n display: 'inline-block',\n borderRadius: '12px',\n overflow: 'hidden',\n};\n\nconst removeImageButtonStyle: h.JSX.CSSProperties = {\n position: 'absolute',\n top: '8px',\n right: '8px',\n width: '28px',\n height: '28px',\n borderRadius: '50%',\n backgroundColor: 'rgba(0, 0, 0, 0.7)',\n color: '#fff',\n border: 'none',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n};\n\nconst uploadingOverlayStyle: h.JSX.CSSProperties = {\n position: 'absolute',\n inset: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.7)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#fff',\n fontSize: '14px',\n borderRadius: '12px',\n};\n\nconst errorStyle: h.JSX.CSSProperties = {\n color: colors.error,\n fontSize: '14px',\n marginBottom: '16px',\n padding: '12px',\n backgroundColor: 'rgba(239, 68, 68, 0.1)',\n borderRadius: '8px',\n border: `1px solid rgba(239, 68, 68, 0.3)`,\n};\n\nconst successContainerStyle: h.JSX.CSSProperties = {\n padding: '48px 24px',\n textAlign: 'center',\n};\n\nconst successIconStyle: h.JSX.CSSProperties = {\n width: '64px',\n height: '64px',\n borderRadius: '50%',\n backgroundColor: 'rgba(34, 197, 94, 0.15)',\n color: colors.success,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n margin: '0 auto 20px',\n};\n\nconst successTitleStyle: h.JSX.CSSProperties = {\n fontSize: '20px',\n fontWeight: 700,\n color: colors.text,\n marginBottom: '8px',\n};\n\nconst successTextStyle: h.JSX.CSSProperties = {\n fontSize: '14px',\n color: colors.textMuted,\n marginBottom: '24px',\n};\n\nconst spinnerContainerStyle: h.JSX.CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '8px',\n};\n","import { h } from 'preact';\nimport { useState, useEffect } from 'preact/hooks';\nimport { Button } from './Button';\nimport { Modal } from './Modal';\nimport type { ProjectConfig, FeedbackData, FeedbackMetadata } from '../types';\n\ninterface WidgetProps {\n config: ProjectConfig;\n onSubmit: (data: FeedbackData) => Promise<boolean>;\n onUpload: (file: File) => Promise<string | null>;\n getMetadata: () => FeedbackMetadata;\n visible: boolean;\n defaultOpen?: boolean;\n hasError?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\nexport function Widget({\n config,\n onSubmit,\n onUpload,\n getMetadata,\n visible,\n defaultOpen = false,\n hasError = false,\n onOpenChange,\n}: WidgetProps) {\n const [isOpen, setIsOpen] = useState(defaultOpen);\n\n // SDK에서 open()/close() 호출 시 동기화\n useEffect(() => {\n setIsOpen(defaultOpen);\n }, [defaultOpen]);\n\n useEffect(() => {\n onOpenChange?.(isOpen);\n }, [isOpen, onOpenChange]);\n\n if (!visible) {\n return null;\n }\n\n const { theme, i18n } = config;\n\n return (\n <>\n {!isOpen && (\n <Button\n onClick={() => setIsOpen(true)}\n label={i18n.buttonLabel}\n position={theme.position}\n primaryColor={theme.primaryColor}\n hasError={hasError}\n />\n )}\n\n {isOpen && (\n <Modal\n config={config}\n metadata={getMetadata()}\n onClose={() => setIsOpen(false)}\n onSubmit={onSubmit}\n onUpload={onUpload}\n />\n )}\n </>\n );\n}\n","// SDK 전용 CSS 스타일 (동적 주입)\nexport const injectStyles = () => {\n if (typeof document === 'undefined') return;\n if (document.getElementById('voyage-sdk-styles')) return;\n\n const style = document.createElement('style');\n style.id = 'voyage-sdk-styles';\n style.textContent = `\n /* Voyage SDK Styles */\n\n /* Spinner Animation */\n @keyframes voyage-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n\n #voyage-widget-container * {\n box-sizing: border-box;\n }\n\n #voyage-widget-container button {\n font-family: 'Quicksand', 'Nunito', system-ui, sans-serif;\n }\n\n #voyage-widget-container textarea:focus,\n #voyage-widget-container input:focus {\n border-color: rgba(124, 58, 237, 0.5);\n box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);\n }\n\n #voyage-widget-container button:focus {\n outline: none;\n }\n\n /* Spinner */\n .voyage-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid rgba(255,255,255,0.3);\n border-top-color: #fff;\n border-radius: 50%;\n animation: voyage-spin 0.8s linear infinite;\n }\n\n /* Load Quicksand font if not present */\n @import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@400;500;600;700&display=swap');\n `;\n\n document.head.appendChild(style);\n};\n","import type { ProjectConfig, FeedbackData } from '../types';\n\n// Supabase Edge Functions URL\nconst API_BASE = 'https://rxflzurkkuqgopjkshjh.supabase.co/functions/v1';\n\nconst CACHE_KEY = 'voyage_config';\nconst CACHE_TTL = 60 * 60 * 1000; // 1시간\n\n// Timeout constants\nconst CONFIG_TIMEOUT = 5000; // 5초\nconst SUBMIT_TIMEOUT = 10000; // 10초\nconst UPLOAD_TIMEOUT = 30000; // 30초 (큰 파일 고려)\n\n// Request timeout utility\nfunction fetchWithTimeout(\n url: string,\n options: RequestInit,\n timeoutMs: number\n): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n return fetch(url, { ...options, signal: controller.signal }).finally(() =>\n clearTimeout(timeoutId)\n );\n}\n\ninterface CachedConfig {\n config: ProjectConfig;\n timestamp: number;\n}\n\nexport async function fetchProjectConfig(\n sdkKey: string,\n options: { forceRefresh?: boolean } = {}\n): Promise<ProjectConfig | null> {\n const { forceRefresh = false } = options;\n\n // 캐시 확인 (forceRefresh가 아닐 때만)\n if (!forceRefresh) {\n const cached = getFromCache(sdkKey);\n if (cached) {\n return cached;\n }\n }\n\n try {\n const response = await fetchWithTimeout(\n `${API_BASE}/get-widget-config`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'x-sdk-key': sdkKey,\n },\n },\n CONFIG_TIMEOUT\n );\n\n if (!response.ok) {\n console.error('[Voyage] Failed to fetch config:', response.status);\n return getFromCache(sdkKey, true); // 실패 시 만료된 캐시라도 사용\n }\n\n const config = (await response.json()) as ProjectConfig;\n saveToCache(sdkKey, config);\n return config;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n console.warn('[Voyage] Config fetch timeout, using cached config');\n } else {\n console.error('[Voyage] Network error:', error);\n }\n // 네트워크 실패 시 캐시 사용 (만료되어도)\n return getFromCache(sdkKey, true);\n }\n}\n\nexport async function submitFeedback(sdkKey: string, data: FeedbackData): Promise<boolean> {\n try {\n const response = await fetchWithTimeout(\n `${API_BASE}/submit-feedback`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-sdk-key': sdkKey,\n },\n body: JSON.stringify({\n label: data.label,\n content: data.text,\n email: data.email,\n imageUrl: data.imageUrl,\n metadata: data.metadata,\n }),\n },\n SUBMIT_TIMEOUT\n );\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n console.error('[Voyage] Failed to submit feedback:', response.status, errorData);\n return false;\n }\n\n return true;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n console.error('[Voyage] Feedback submission timeout');\n } else {\n console.error('[Voyage] Network error:', error);\n }\n return false;\n }\n}\n\nexport async function uploadImage(sdkKey: string, file: File): Promise<string | null> {\n // 검증\n if (!file.type.startsWith('image/')) {\n console.error('[Voyage] Only image files are allowed');\n return null;\n }\n\n if (file.size > 5 * 1024 * 1024) {\n console.error('[Voyage] Image must be under 5MB');\n return null;\n }\n\n try {\n const formData = new FormData();\n formData.append('file', file);\n\n const response = await fetchWithTimeout(\n `${API_BASE}/upload-feedback-image`,\n {\n method: 'POST',\n headers: {\n 'x-sdk-key': sdkKey,\n },\n body: formData,\n },\n UPLOAD_TIMEOUT\n );\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n console.error('[Voyage] Failed to upload image:', response.status, errorData);\n return null;\n }\n\n const result = await response.json();\n return result.url;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n console.error('[Voyage] Image upload timeout');\n } else {\n console.error('[Voyage] Network error:', error);\n }\n return null;\n }\n}\n\n// Export for optimistic loading\nexport function getCachedConfig(sdkKey: string): ProjectConfig | null {\n return getFromCache(sdkKey, true); // 만료되어도 반환\n}\n\nfunction getFromCache(sdkKey: string, ignoreExpiry = false): ProjectConfig | null {\n try {\n const raw = localStorage.getItem(`${CACHE_KEY}_${sdkKey}`);\n if (!raw) return null;\n\n const cached: CachedConfig = JSON.parse(raw);\n const isExpired = Date.now() - cached.timestamp > CACHE_TTL;\n\n if (isExpired && !ignoreExpiry) {\n return null;\n }\n\n return cached.config;\n } catch {\n return null;\n }\n}\n\nfunction saveToCache(sdkKey: string, config: ProjectConfig): void {\n try {\n const cached: CachedConfig = {\n config,\n timestamp: Date.now(),\n };\n localStorage.setItem(`${CACHE_KEY}_${sdkKey}`, JSON.stringify(cached));\n } catch {\n // localStorage 사용 불가 시 무시\n }\n}\n","import type { FeedbackMetadata } from '../types';\n\nexport function captureMetadata(): FeedbackMetadata {\n return {\n url: window.location.href,\n pathname: window.location.pathname,\n browser: navigator.userAgent,\n viewport: `${window.innerWidth}x${window.innerHeight}`,\n title: document.title,\n timestamp: new Date().toISOString(),\n locale: navigator.language,\n referrer: document.referrer,\n };\n}\n","// @voyage/sdk\n// Feedback Widget SDK for collecting user feedback\n\nimport { h, render } from 'preact';\n\nimport { Widget } from './components';\nimport { injectStyles } from './styles';\nimport {\n fetchProjectConfig,\n getCachedConfig,\n submitFeedback,\n uploadImage,\n} from './utils/api';\nimport { captureMetadata } from './utils/metadata';\n\nimport type { VoyageConfig, ProjectConfig, FeedbackData } from './types';\n\nexport type { VoyageConfig, ProjectConfig, FeedbackData, FeedbackMetadata } from './types';\n\nconst DEFAULT_CONFIG: ProjectConfig = {\n projectId: '',\n formFields: {\n email: { enabled: true, required: false },\n category: { enabled: true, options: ['bug', 'feature'] },\n },\n theme: {\n primaryColor: '#0ea5e9',\n position: 'bottom-right',\n },\n i18n: {\n buttonLabel: 'To : the Maker',\n placeholder: 'Describe your ideas to improve our product',\n bugPlaceholder: 'Please describe the bug in detail (e.g., clicked a button and it didn\\'t work)',\n featurePlaceholder: 'Describe your ideas to improve our product (e.g., I want to export TASK.md to Linear tickets)',\n submitLabel: 'Send to the Maker',\n successMessage: 'Thank you for your feedback!',\n },\n};\n\nclass VoyageSDK {\n private config: VoyageConfig | null = null;\n private serverConfig: ProjectConfig | null = null;\n private container: HTMLElement | null = null;\n private isWidgetVisible = false;\n private isModalOpen = false;\n private hasInitError = false;\n\n async init(config: VoyageConfig): Promise<void> {\n this.config = config;\n this.hasInitError = false;\n\n if (!config.sdkKey) {\n console.error('[Voyage] SDK Key is required. Get your key from the dashboard.');\n this.hasInitError = true;\n injectStyles();\n this.isWidgetVisible = true;\n this.serverConfig = { ...DEFAULT_CONFIG };\n this.renderWidget();\n return;\n }\n\n // Inject SDK styles\n injectStyles();\n\n // Check display control\n if (!this.shouldDisplay()) {\n console.log('[Voyage] Widget hidden by display rules');\n return;\n }\n\n // Optimistic loading: 캐시가 있으면 먼저 표시\n const cachedConfig = getCachedConfig(config.sdkKey);\n if (cachedConfig) {\n this.serverConfig = this.mergeConfig(cachedConfig, config);\n this.isWidgetVisible = true;\n this.renderWidget();\n console.log('[Voyage] Initialized (cached)');\n\n // 백그라운드에서 최신 config fetch\n this.refreshConfigInBackground();\n return;\n }\n\n // 캐시가 없으면 fetch 후 표시\n const fetchedConfig = await fetchProjectConfig(config.sdkKey);\n\n if (!fetchedConfig) {\n console.error('[Voyage] Failed to fetch config. Check your SDK Key or network connection.');\n this.hasInitError = true;\n this.serverConfig = { ...DEFAULT_CONFIG };\n this.isWidgetVisible = true;\n this.renderWidget();\n return;\n }\n\n this.serverConfig = this.mergeConfig(fetchedConfig, config);\n\n // Render widget\n this.isWidgetVisible = true;\n this.renderWidget();\n console.log('[Voyage] Initialized');\n }\n\n private async refreshConfigInBackground(): Promise<void> {\n if (!this.config) return;\n\n try {\n // 캐시를 무시하고 서버에서 최신 설정 가져오기\n const freshConfig = await fetchProjectConfig(this.config.sdkKey, { forceRefresh: true });\n if (freshConfig && this.serverConfig) {\n // 설정이 변경되었을 때만 re-render\n const newConfig = this.mergeConfig(freshConfig, this.config);\n if (JSON.stringify(newConfig) !== JSON.stringify(this.serverConfig)) {\n this.serverConfig = newConfig;\n this.renderWidget();\n console.log('[Voyage] Config updated');\n }\n }\n } catch {\n // 백그라운드 갱신 실패는 무시 (이미 캐시로 동작 중)\n }\n }\n\n show(): void {\n if (!this.config) {\n console.warn('[Voyage] SDK not initialized');\n return;\n }\n this.isWidgetVisible = true;\n this.renderWidget();\n }\n\n hide(): void {\n this.isWidgetVisible = false;\n this.renderWidget();\n }\n\n open(): void {\n if (!this.config) {\n console.warn('[Voyage] SDK not initialized');\n return;\n }\n this.isModalOpen = true;\n this.renderWidget();\n }\n\n close(): void {\n this.isModalOpen = false;\n this.renderWidget();\n }\n\n isOpen(): boolean {\n return this.isModalOpen;\n }\n\n isVisible(): boolean {\n return this.isWidgetVisible;\n }\n\n async refreshConfig(): Promise<void> {\n if (!this.config) return;\n // 캐시를 무시하고 서버에서 최신 설정 가져오기\n const fetchedConfig = await fetchProjectConfig(this.config.sdkKey, { forceRefresh: true });\n this.serverConfig = this.mergeConfig(fetchedConfig, this.config);\n this.renderWidget();\n }\n\n destroy(): void {\n if (this.container) {\n render(null, this.container);\n this.container.remove();\n this.container = null;\n }\n this.config = null;\n this.serverConfig = null;\n this.isWidgetVisible = false;\n this.isModalOpen = false;\n }\n\n private renderWidget(): void {\n if (!this.serverConfig || !this.config) return;\n\n // Create container if not exists\n if (!this.container) {\n this.container = document.createElement('div');\n this.container.id = 'voyage-widget-container';\n document.body.appendChild(this.container);\n }\n\n const sdkKey = this.config.sdkKey;\n\n render(\n h(Widget, {\n config: this.serverConfig,\n visible: this.isWidgetVisible,\n defaultOpen: this.isModalOpen,\n hasError: this.hasInitError,\n onOpenChange: (open: boolean) => {\n this.isModalOpen = open;\n },\n getMetadata: captureMetadata,\n onSubmit: async (data: FeedbackData) => {\n return submitFeedback(sdkKey, data);\n },\n onUpload: async (file: File) => {\n return uploadImage(sdkKey, file);\n },\n }),\n this.container\n );\n }\n\n private mergeConfig(server: ProjectConfig | null, _client: VoyageConfig): ProjectConfig {\n // Server config takes priority: use values set from dashboard\n // Client-side theme override disabled (to prevent config conflicts)\n return server || { ...DEFAULT_CONFIG };\n }\n\n private shouldDisplay(): boolean {\n if (!this.config) return false;\n\n const pathname = window.location.pathname;\n const { include, exclude } = this.config;\n\n // include takes priority over exclude\n if (include && include.length > 0) {\n return include.some((pattern) => this.matchPath(pathname, pattern));\n }\n\n if (exclude && exclude.length > 0) {\n return !exclude.some((pattern) => this.matchPath(pathname, pattern));\n }\n\n return true;\n }\n\n private matchPath(pathname: string, pattern: string): boolean {\n // Simple glob matching: /admin/* matches /admin/anything\n if (pattern.endsWith('/*')) {\n const prefix = pattern.slice(0, -2);\n return pathname.startsWith(prefix);\n }\n return pathname === pattern;\n }\n}\n\n// Singleton instance\nconst Voyage = new VoyageSDK();\n\nexport { Voyage };\nexport default Voyage;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyage-sdk/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Voyage Feedback Widget SDK - Collect user feedback with ease",
|
|
5
5
|
"author": "Voyage",
|
|
6
6
|
"homepage": "https://voyagefeedback.com",
|
|
@@ -44,4 +44,4 @@
|
|
|
44
44
|
"morphprd"
|
|
45
45
|
],
|
|
46
46
|
"license": "MIT"
|
|
47
|
-
}
|
|
47
|
+
}
|