@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 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
- ### ES Module
21
+ ### HTML / Vanilla JS
21
22
 
22
- ```javascript
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
- Voyage.init({
26
- sdkKey: 'your-sdk-key-here'
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
- ### CDN / Script Tag
49
+ ### Vue.js
31
50
 
32
- ```html
33
- <script src="https://unpkg.com/@voyage-sdk/core"></script>
34
- <link rel="stylesheet" href="https://unpkg.com/@voyage-sdk/core/dist/style.css" />
35
- <script>
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(r);};var T="https://rxflzurkkuqgopjkshjh.supabase.co/functions/v1",te="voyage_config";async function R(r){let o=ee(r);if(o)return o;try{let e=await fetch(`${T}/get-widget-config`,{method:"GET",headers:{"Content-Type":"application/json","x-sdk-key":r}});if(!e.ok)return console.error("[Voyage] Failed to fetch config:",e.status),null;let i=await e.json();return qe(r,i),i}catch(e){return console.error("[Voyage] Network error:",e),ee(r,true)}}async function oe(r,o){try{let e=await fetch(`${T}/submit-feedback`,{method:"POST",headers:{"Content-Type":"application/json","x-sdk-key":r},body:JSON.stringify({label:o.label,content:o.text,email:o.email,imageUrl:o.imageUrl,metadata:o.metadata})});if(!e.ok){let i=await e.json().catch(()=>({}));return console.error("[Voyage] Failed to submit feedback:",e.status,i),!1}return !0}catch(e){return console.error("[Voyage] Network error:",e),false}}async function re(r,o){if(!o.type.startsWith("image/"))return console.error("[Voyage] Only image files are allowed"),null;if(o.size>5*1024*1024)return console.error("[Voyage] Image must be under 5MB"),null;try{let e=new FormData;e.append("file",o);let i=await fetch(`${T}/upload-feedback-image`,{method:"POST",headers:{"x-sdk-key":r},body:e});if(!i.ok){let a=await i.json().catch(()=>({}));return console.error("[Voyage] Failed to upload image:",i.status,a),null}return (await i.json()).url}catch(e){return console.error("[Voyage] Network error:",e),null}}function ee(r,o=false){try{let e=localStorage.getItem(`${te}_${r}`);if(!e)return null;let i=JSON.parse(e);return Date.now()-i.timestamp>36e5&&!o?null:i.config}catch{return null}}function qe(r,o){try{let e={config:o,timestamp:Date.now()};localStorage.setItem(`${te}_${r}`,JSON.stringify(e));}catch{}}function ie(){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 O={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!"}},$=class{constructor(){this.config=null;this.serverConfig=null;this.container=null;this.isWidgetVisible=false;this.isModalOpen=false;this.hasInitError=false;}async init(o){if(this.config=o,this.hasInitError=false,!o.sdkKey){console.error("[Voyage] SDK Key is required. Get your key from the dashboard."),this.hasInitError=true,V(),this.isWidgetVisible=true,this.serverConfig={...O},this.renderWidget();return}if(V(),!this.shouldDisplay()){console.log("[Voyage] Widget hidden by display rules");return}let e=await R(o.sdkKey);if(!e){console.error("[Voyage] Failed to fetch config. Check your SDK Key or network connection."),this.hasInitError=true,this.serverConfig={...O},this.isWidgetVisible=true,this.renderWidget();return}this.serverConfig=this.mergeConfig(e,o),this.isWidgetVisible=true,this.renderWidget(),console.log("[Voyage] Initialized");}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 o=await R(this.config.sdkKey);this.serverConfig=this.mergeConfig(o,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 o=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:ie,onSubmit:async e=>oe(o,e),onUpload:async e=>re(o,e)}),this.container);}mergeConfig(o,e){return o||{...O}}shouldDisplay(){if(!this.config)return false;let o=window.location.pathname,{include:e,exclude:i}=this.config;return e&&e.length>0?e.some(p=>this.matchPath(o,p)):i&&i.length>0?!i.some(p=>this.matchPath(o,p)):true}matchPath(o,e){if(e.endsWith("/*")){let i=e.slice(0,-2);return o.startsWith(i)}return o===e}},_e=new $;var St=_e;
41
- exports.Voyage=_e;exports.default=St;//# sourceMappingURL=index.cjs.map
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
@@ -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
@@ -56,6 +56,7 @@ declare class VoyageSDK {
56
56
  private isModalOpen;
57
57
  private hasInitError;
58
58
  init(config: VoyageConfig): Promise<void>;
59
+ private refreshConfigInBackground;
59
60
  show(): void;
60
61
  hide(): void;
61
62
  open(): void;
package/dist/index.d.ts CHANGED
@@ -56,6 +56,7 @@ declare class VoyageSDK {
56
56
  private isModalOpen;
57
57
  private hasInitError;
58
58
  init(config: VoyageConfig): Promise<void>;
59
+ private refreshConfigInBackground;
59
60
  show(): void;
60
61
  hide(): void;
61
62
  open(): void;
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(r);};var T="https://rxflzurkkuqgopjkshjh.supabase.co/functions/v1",te="voyage_config";async function R(r){let o=ee(r);if(o)return o;try{let e=await fetch(`${T}/get-widget-config`,{method:"GET",headers:{"Content-Type":"application/json","x-sdk-key":r}});if(!e.ok)return console.error("[Voyage] Failed to fetch config:",e.status),null;let i=await e.json();return qe(r,i),i}catch(e){return console.error("[Voyage] Network error:",e),ee(r,true)}}async function oe(r,o){try{let e=await fetch(`${T}/submit-feedback`,{method:"POST",headers:{"Content-Type":"application/json","x-sdk-key":r},body:JSON.stringify({label:o.label,content:o.text,email:o.email,imageUrl:o.imageUrl,metadata:o.metadata})});if(!e.ok){let i=await e.json().catch(()=>({}));return console.error("[Voyage] Failed to submit feedback:",e.status,i),!1}return !0}catch(e){return console.error("[Voyage] Network error:",e),false}}async function re(r,o){if(!o.type.startsWith("image/"))return console.error("[Voyage] Only image files are allowed"),null;if(o.size>5*1024*1024)return console.error("[Voyage] Image must be under 5MB"),null;try{let e=new FormData;e.append("file",o);let i=await fetch(`${T}/upload-feedback-image`,{method:"POST",headers:{"x-sdk-key":r},body:e});if(!i.ok){let a=await i.json().catch(()=>({}));return console.error("[Voyage] Failed to upload image:",i.status,a),null}return (await i.json()).url}catch(e){return console.error("[Voyage] Network error:",e),null}}function ee(r,o=false){try{let e=localStorage.getItem(`${te}_${r}`);if(!e)return null;let i=JSON.parse(e);return Date.now()-i.timestamp>36e5&&!o?null:i.config}catch{return null}}function qe(r,o){try{let e={config:o,timestamp:Date.now()};localStorage.setItem(`${te}_${r}`,JSON.stringify(e));}catch{}}function ie(){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 O={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!"}},$=class{constructor(){this.config=null;this.serverConfig=null;this.container=null;this.isWidgetVisible=false;this.isModalOpen=false;this.hasInitError=false;}async init(o){if(this.config=o,this.hasInitError=false,!o.sdkKey){console.error("[Voyage] SDK Key is required. Get your key from the dashboard."),this.hasInitError=true,V(),this.isWidgetVisible=true,this.serverConfig={...O},this.renderWidget();return}if(V(),!this.shouldDisplay()){console.log("[Voyage] Widget hidden by display rules");return}let e=await R(o.sdkKey);if(!e){console.error("[Voyage] Failed to fetch config. Check your SDK Key or network connection."),this.hasInitError=true,this.serverConfig={...O},this.isWidgetVisible=true,this.renderWidget();return}this.serverConfig=this.mergeConfig(e,o),this.isWidgetVisible=true,this.renderWidget(),console.log("[Voyage] Initialized");}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 o=await R(this.config.sdkKey);this.serverConfig=this.mergeConfig(o,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 o=this.config.sdkKey;render(h(z,{config:this.serverConfig,visible:this.isWidgetVisible,defaultOpen:this.isModalOpen,hasError:this.hasInitError,onOpenChange:e=>{this.isModalOpen=e;},getMetadata:ie,onSubmit:async e=>oe(o,e),onUpload:async e=>re(o,e)}),this.container);}mergeConfig(o,e){return o||{...O}}shouldDisplay(){if(!this.config)return false;let o=window.location.pathname,{include:e,exclude:i}=this.config;return e&&e.length>0?e.some(p=>this.matchPath(o,p)):i&&i.length>0?!i.some(p=>this.matchPath(o,p)):true}matchPath(o,e){if(e.endsWith("/*")){let i=e.slice(0,-2);return o.startsWith(i)}return o===e}},_e=new $;var St=_e;
41
- export{_e as Voyage,St as default};//# sourceMappingURL=index.js.map
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",
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
+ }