@the-it-dept/bugsplat 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ .splat-widget{--splat-primary: #6366f1;--splat-bg: #ffffff;--splat-text: #1f2937;--splat-text-secondary: #6b7280;--splat-border: #e5e7eb;--splat-error: #ef4444;--splat-success: #22c55e;position:fixed;z-index:99999;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:14px;line-height:1.5}.splat-widget.splat-contained{position:absolute}.splat-bottom-right{bottom:20px;right:20px}.splat-bottom-left{bottom:20px;left:20px}.splat-trigger-mode{position:fixed;top:0;left:0;right:0;bottom:0;pointer-events:none}.splat-trigger-mode .splat-backdrop,.splat-trigger-mode .splat-panel{pointer-events:auto}.splat-backdrop{position:fixed;top:0;left:0;right:0;bottom:0;background:#00000080;z-index:1;animation:splat-fade-in .2s ease}@keyframes splat-fade-in{0%{opacity:0}to{opacity:1}}.splat-panel.splat-modal{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:2;animation:splat-slide-up .2s ease}@keyframes splat-slide-up{0%{opacity:0;transform:translate(-50%,-48%)}to{opacity:1;transform:translate(-50%,-50%)}}.splat-button{display:flex;align-items:center;gap:8px;padding:12px 16px;background:var(--splat-primary);color:#fff;border:none;border-radius:8px;cursor:pointer;font-size:14px;font-weight:500;box-shadow:0 4px 12px #00000026;transition:transform .2s,box-shadow .2s}.splat-button:hover{transform:translateY(-2px);box-shadow:0 6px 16px #0003}.splat-panel{width:380px;max-height:520px;background:var(--splat-bg);border-radius:12px;box-shadow:0 8px 30px #0000001f;overflow:hidden;display:flex;flex-direction:column}.splat-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--splat-border)}.splat-footer{padding:10px 16px;border-top:1px solid var(--splat-border);text-align:center}.splat-footer a{font-size:11px;color:var(--splat-text-secondary);text-decoration:none;transition:color .15s ease}.splat-footer a:hover{color:var(--splat-primary)}.splat-footer strong{font-weight:600}.splat-tabs{display:flex;gap:4px}.splat-tabs button{padding:6px 12px;background:transparent;border:none;border-radius:6px;color:var(--splat-text-secondary);cursor:pointer;font-size:13px;font-weight:500;transition:background .2s,color .2s}.splat-tabs button:hover{background:#f3f4f6}.splat-tabs button.active{background:var(--splat-primary);color:#fff}.splat-close{padding:6px;background:transparent;border:none;border-radius:6px;color:var(--splat-text-secondary);cursor:pointer;transition:background .2s}.splat-close:hover{background:#f3f4f6}.splat-content{flex:1;overflow-y:auto;padding:16px}.splat-form{display:flex;flex-direction:column;gap:16px}.splat-field{display:flex;flex-direction:column;gap:6px}.splat-field label{font-size:13px;font-weight:500;color:var(--splat-text)}.splat-field input,.splat-field textarea{padding:10px 12px;border:1px solid var(--splat-border);border-radius:8px;font-size:14px;color:var(--splat-text);background:var(--splat-bg);transition:border-color .2s,box-shadow .2s}.splat-field input:focus,.splat-field textarea:focus{outline:none;border-color:var(--splat-primary);box-shadow:0 0 0 3px #6366f11a}.splat-field textarea{resize:vertical;min-height:80px}.splat-submit{padding:12px 16px;background:var(--splat-primary);color:#fff;border:none;border-radius:8px;font-size:14px;font-weight:500;cursor:pointer;transition:opacity .2s}.splat-submit:hover{opacity:.9}.splat-submit:disabled{opacity:.6;cursor:not-allowed}.splat-error{padding:12px;background:#fef2f2;border:1px solid #fecaca;border-radius:8px;color:var(--splat-error);font-size:13px}.splat-loading,.splat-empty{padding:40px 20px;text-align:center;color:var(--splat-text-secondary)}.splat-empty p{margin:4px 0}.splat-success{padding:40px 20px;text-align:center;display:flex;flex-direction:column;align-items:center;gap:12px}.splat-success-icon{width:56px;height:56px;background:var(--splat-success);border-radius:50%;display:flex;align-items:center;justify-content:center;color:#fff}.splat-success h3{margin:0;font-size:18px;font-weight:600;color:var(--splat-text)}.splat-success p{margin:0;color:var(--splat-text-secondary)}.splat-success-id{font-family:monospace;font-size:12px;color:var(--splat-text-secondary);background:#0000000d;padding:4px 8px;border-radius:4px}.splat-success .splat-submit{margin-top:8px}.splat-history{display:flex;flex-direction:column;gap:8px}.splat-report-item{display:flex;flex-direction:column;gap:4px;padding:12px;background:#f9fafb;border:1px solid var(--splat-border);border-radius:8px;cursor:pointer;text-align:left;transition:border-color .2s}.splat-report-item:hover{border-color:var(--splat-primary)}.splat-report-header{display:flex;align-items:center;justify-content:space-between;gap:8px}.splat-report-title{font-weight:500;color:var(--splat-text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.splat-report-meta{font-size:12px;color:var(--splat-text-secondary)}.splat-status{padding:2px 8px;border-radius:12px;font-size:11px;font-weight:500;text-transform:uppercase}.splat-status-pending{background:#fef3c7;color:#92400e}.splat-status-open{background:#dbeafe;color:#1e40af}.splat-status-closed{background:#dcfce7;color:#166534}.splat-detail{display:flex;flex-direction:column;gap:16px}.splat-back{display:flex;align-items:center;gap:6px;padding:6px 0;background:transparent;border:none;color:var(--splat-text-secondary);cursor:pointer;font-size:13px}.splat-back:hover{color:var(--splat-text)}.splat-detail-header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.splat-detail-header h2{margin:0;font-size:16px;font-weight:600;color:var(--splat-text)}.splat-detail-description{margin:0;color:var(--splat-text-secondary);white-space:pre-wrap}.splat-github-link{display:inline-block;padding:8px 12px;background:#f3f4f6;border-radius:6px;color:var(--splat-text);text-decoration:none;font-size:13px;font-weight:500}.splat-github-link:hover{background:#e5e7eb}.splat-comments{border-top:1px solid var(--splat-border);padding-top:16px}.splat-comments h3{margin:0 0 12px;font-size:14px;font-weight:600;color:var(--splat-text)}.splat-comment{padding:12px;background:#f9fafb;border-radius:8px;margin-bottom:8px}.splat-comment-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.splat-avatar{width:24px;height:24px;border-radius:50%}.splat-author{font-weight:500;color:var(--splat-text)}.splat-date{font-size:12px;color:var(--splat-text-secondary)}.splat-comment-body{color:var(--splat-text-secondary);white-space:pre-wrap}.splat-screenshot-section{display:flex;flex-direction:column;gap:8px}.splat-section-label{font-size:13px;font-weight:500;color:var(--splat-text)}.splat-screenshot-options{display:flex;align-items:center;gap:10px}.splat-screenshot-btn{display:inline-flex;align-items:center;gap:6px;padding:8px 12px;background:#f3f4f6;border:1px solid var(--splat-border);border-radius:6px;font-size:13px;font-weight:500;color:var(--splat-text);cursor:pointer;transition:background .2s,border-color .2s}.splat-screenshot-btn:hover{background:#e5e7eb;border-color:#d1d5db}.splat-screenshot-btn:disabled{opacity:.6;cursor:not-allowed}.splat-upload-btn{cursor:pointer}.splat-or{font-size:12px;color:var(--splat-text-secondary)}.splat-screenshot-preview{position:relative;border:1px solid var(--splat-border);border-radius:8px;overflow:hidden;background:#f9fafb}.splat-screenshot-preview img{display:block;width:100%;max-height:150px;object-fit:contain}.splat-screenshot-remove{position:absolute;top:6px;right:6px;width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:#0009;border:none;border-radius:50%;color:#fff;font-size:16px;cursor:pointer;transition:background .2s}.splat-screenshot-remove:hover{background:#000c}.splat-spinner-small{display:inline-block;width:12px;height:12px;border:2px solid var(--splat-border);border-top-color:var(--splat-primary);border-radius:50%;animation:splat-spin .8s linear infinite}@keyframes splat-spin{to{transform:rotate(360deg)}}.splat-theme-dark{--splat-bg: #1f2937;--splat-text: #f9fafb;--splat-text-secondary: #9ca3af;--splat-border: #374151}.splat-theme-dark .splat-tabs button:hover,.splat-theme-dark .splat-close:hover{background:#374151}.splat-theme-dark .splat-report-item,.splat-theme-dark .splat-comment{background:#111827}.splat-theme-dark .splat-github-link{background:#374151}.splat-theme-dark .splat-github-link:hover{background:#4b5563}.splat-theme-dark .splat-error{background:#7f1d1d;border-color:#991b1b}.splat-theme-dark .splat-screenshot-btn{background:#374151;border-color:#4b5563}.splat-theme-dark .splat-screenshot-btn:hover{background:#4b5563;border-color:#6b7280}.splat-theme-dark .splat-screenshot-preview{background:#111827;border-color:#374151}
@@ -0,0 +1,60 @@
1
+ export interface SplatConfig {
2
+ apiKey: string;
3
+ apiUrl?: string;
4
+ /**
5
+ * Position of the widget button.
6
+ * - 'bottom-right' / 'bottom-left': Floating button in corner
7
+ * - 'trigger': No button shown, use trigger() method to open as modal
8
+ */
9
+ position?: 'bottom-right' | 'bottom-left' | 'trigger';
10
+ primaryColor?: string;
11
+ onSubmit?: (report: Report) => void;
12
+ /** Container element or selector to constrain widget to (default: document.body) */
13
+ container?: HTMLElement | string;
14
+ /** Preview mode: skip API fetch and use these values directly */
15
+ previewMode?: boolean;
16
+ buttonText?: string;
17
+ accentColor?: string;
18
+ theme?: 'light' | 'dark';
19
+ title?: string;
20
+ placeholder?: string;
21
+ historyEnabled?: boolean;
22
+ }
23
+ export interface WidgetConfig {
24
+ position: 'bottom-right' | 'bottom-left' | 'trigger';
25
+ buttonText: string;
26
+ accentColor: string;
27
+ theme: 'light' | 'dark';
28
+ title: string;
29
+ placeholder: string;
30
+ /** Whether reporters can view their submission history */
31
+ historyEnabled: boolean;
32
+ }
33
+ export interface Report {
34
+ id: string;
35
+ title: string;
36
+ description: string;
37
+ email: string;
38
+ status: ReportStatus;
39
+ githubIssueUrl?: string;
40
+ createdAt: string;
41
+ }
42
+ export type ReportStatus = 'pending' | 'open' | 'closed';
43
+ export interface ReportSummary {
44
+ id: string;
45
+ title: string;
46
+ status: ReportStatus;
47
+ githubIssueUrl?: string;
48
+ createdAt: string;
49
+ }
50
+ export interface Comment {
51
+ id: string;
52
+ authorLogin: string;
53
+ authorAvatarUrl?: string;
54
+ body: string;
55
+ createdAt: string;
56
+ }
57
+ export interface ReportDetail extends Report {
58
+ comments: Comment[];
59
+ }
60
+ export type { ReportMetadata } from '../utils/metadata';
@@ -0,0 +1,25 @@
1
+ export interface ReportMetadata {
2
+ url: string;
3
+ referrer: string;
4
+ pageTitle: string;
5
+ userAgent: string;
6
+ browser: string;
7
+ browserVersion: string;
8
+ platform: string;
9
+ language: string;
10
+ cookiesEnabled: boolean;
11
+ screenWidth: number;
12
+ screenHeight: number;
13
+ viewportWidth: number;
14
+ viewportHeight: number;
15
+ devicePixelRatio: number;
16
+ colorDepth: number;
17
+ timestamp: string;
18
+ timezone: string;
19
+ timezoneOffset: number;
20
+ connection?: string;
21
+ }
22
+ /**
23
+ * Collect comprehensive browser/device metadata for bug reports
24
+ */
25
+ export declare function collectMetadata(): ReportMetadata;
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@the-it-dept/bugsplat",
3
+ "version": "0.0.1",
4
+ "description": "Embeddable bug report widget for BugSplat",
5
+ "type": "module",
6
+ "main": "./dist/bugsplat.umd.cjs",
7
+ "module": "./dist/bugsplat.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/bugsplat.js",
12
+ "require": "./dist/bugsplat.umd.cjs",
13
+ "types": "./dist/index.d.ts"
14
+ },
15
+ "./style.css": "./dist/style.css"
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "scripts": {
21
+ "dev": "vite",
22
+ "build": "tsc && vite build",
23
+ "preview": "vite preview",
24
+ "lint": "eslint src --ext ts,tsx"
25
+ },
26
+ "dependencies": {
27
+ "html2canvas": "^1.4.1"
28
+ },
29
+ "peerDependencies": {
30
+ "react": "^18.0.0",
31
+ "react-dom": "^18.0.0"
32
+ },
33
+ "devDependencies": {
34
+ "@types/react": "^18.2.0",
35
+ "@types/react-dom": "^18.2.0",
36
+ "@vitejs/plugin-react": "^4.2.0",
37
+ "react": "^18.2.0",
38
+ "react-dom": "^18.2.0",
39
+ "typescript": "^5.3.0",
40
+ "vite": "^5.0.0",
41
+ "vite-plugin-dts": "^3.7.0"
42
+ }
43
+ }