vg-coder-cli 2.0.31 → 2.0.33
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 +0 -11
- package/dist/vg-coder-bundle.js +42 -0
- package/package.json +19 -11
- package/src/index.js +28 -220
- package/src/server/api-server.js +120 -428
- package/src/server/views/css/bubble.css +81 -0
- package/src/server/views/css/code-viewer.css +58 -0
- package/src/server/views/css/terminal.css +59 -155
- package/src/server/views/dashboard.css +78 -678
- package/src/server/views/dashboard.html +39 -278
- package/src/server/views/js/api.js +2 -22
- package/src/server/views/js/config.js +27 -15
- package/src/server/views/js/event-protocol.js +263 -0
- package/src/server/views/js/features/bubble-features/index.js +125 -0
- package/src/server/views/js/features/bubble-features/paste-run-feature.js +16 -0
- package/src/server/views/js/features/bubble-features/terminal-feature.js +16 -0
- package/src/server/views/js/features/bubble.js +175 -0
- package/src/server/views/js/features/code-viewer.js +90 -0
- package/src/server/views/js/features/commands.js +34 -81
- package/src/server/views/js/features/editor-tabs.js +19 -46
- package/src/server/views/js/features/git-view.js +63 -81
- package/src/server/views/js/features/iframe-manager.js +3 -97
- package/src/server/views/js/features/monaco-manager.js +19 -39
- package/src/server/views/js/features/project-switcher.js +7 -63
- package/src/server/views/js/features/resize.js +5 -16
- package/src/server/views/js/features/structure.js +38 -106
- package/src/server/views/js/features/terminal.js +102 -418
- package/src/server/views/js/handlers.js +60 -43
- package/src/server/views/js/main.js +75 -179
- package/src/server/views/js/shadow-entry.js +21 -0
- package/src/server/views/js/utils.js +48 -28
- package/src/server/views/vg-coder/_metadata/generated_indexed_rulesets/_ruleset1 +0 -0
- package/src/server/views/vg-coder/controller.js +33 -258
- package/.vgignore +0 -10
- package/src/server/views/dashboard.js +0 -457
- package/test-pty.js +0 -31
- package/vetgo-auto/README.md +0 -3
- package/vetgo-auto/chrome/CSP_IMPROVEMENTS.md +0 -147
- package/vetgo-auto/chrome/MANIFEST_V3_MIGRATION.md +0 -123
- package/vetgo-auto/chrome/assets/icon128.png +0 -0
- package/vetgo-auto/chrome/assets/icon16.png +0 -0
- package/vetgo-auto/chrome/assets/icon48.png +0 -0
- package/vetgo-auto/chrome/environments/environment.ts +0 -13
- package/vetgo-auto/chrome/manifest.json +0 -66
- package/vetgo-auto/chrome/rules.json +0 -23
- package/vetgo-auto/chrome/src/background.ts +0 -200
- package/vetgo-auto/chrome/src/controller.ts +0 -172
- package/vetgo-auto/chrome/src/controllers/common.firebase.ts +0 -31
- package/vetgo-auto/chrome/src/controllers/firebase-crud.ts +0 -147
- package/vetgo-auto/chrome/src/controllers/load-common-fuc.controller.ts +0 -24
- package/vetgo-auto/chrome/src/controllers/load-script.controller.ts +0 -23
- package/vetgo-auto/chrome/src/script-injector.ts +0 -305
- package/vetgo-auto/chrome/src/sidepanel.css +0 -166
- package/vetgo-auto/chrome/src/sidepanel.html +0 -48
- package/vetgo-auto/chrome/src/sidepanel.ts +0 -127
- package/vetgo-auto/chrome/src/utils/ai-domains.ts +0 -33
- package/vetgo-auto/chrome/src/utils/db-utils.ts +0 -2
- package/vetgo-auto/chrome/src/utils/environment-storage.service.ts +0 -85
- package/vetgo-auto/chrome/src/utils/injector-script.ts +0 -272
- package/vetgo-auto/chrome/webpack.config.js +0 -53
- package/vetgo-auto/chrome/webpack.config.prod.js +0 -54
- package/vetgo-auto/package.json +0 -30
- package/vetgo-auto/tsconfig.json +0 -27
- package/vetgo-auto/vg-coder.zip +0 -0
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="vi">
|
|
3
|
-
|
|
4
|
-
<head>
|
|
5
|
-
<meta charset="UTF-8">
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
-
<title>VetGo Pro - Cấu hình</title>
|
|
8
|
-
<link rel="stylesheet" href="sidepanel.css">
|
|
9
|
-
</head>
|
|
10
|
-
|
|
11
|
-
<body>
|
|
12
|
-
<div class="container">
|
|
13
|
-
<h1>⚙️ Cấu hình VetGo Pro</h1>
|
|
14
|
-
<p class="subtitle">Quản lý cài đặt môi trường cho extension</p>
|
|
15
|
-
|
|
16
|
-
<div id="message" class="message"></div>
|
|
17
|
-
|
|
18
|
-
<div class="current-value">
|
|
19
|
-
<strong>Môi trường hiện tại:</strong> <span id="currentEnv">Đang tải...</span>
|
|
20
|
-
</div>
|
|
21
|
-
|
|
22
|
-
<form id="configForm">
|
|
23
|
-
<div class="form-group">
|
|
24
|
-
<label for="environmentName">Tên môi trường (Environment Name)</label>
|
|
25
|
-
<input type="text" id="environmentName" name="environmentName"
|
|
26
|
-
placeholder="Nhập tên môi trường (ví dụ: midjourney, production, test)" required />
|
|
27
|
-
<p class="hint">Tên môi trường sẽ được sử dụng để load scripts từ Firebase: ENV/{environmentName}/script</p>
|
|
28
|
-
</div>
|
|
29
|
-
|
|
30
|
-
<div class="form-group">
|
|
31
|
-
<label for="firebaseConfig">Cấu hình Firebase (JSON)</label>
|
|
32
|
-
<textarea id="firebaseConfig" name="firebaseConfig" rows="8"
|
|
33
|
-
placeholder='{"apiKey": "...", "authDomain": "...", "databaseURL": "..."}'
|
|
34
|
-
style="width: 100%; padding: 12px; border: 2px solid #e0e0e0; border-radius: 8px; font-family: monospace; font-size: 13px;"></textarea>
|
|
35
|
-
<p class="hint">Để trống để sử dụng cấu hình mặc định của hệ thống. Nhập JSON object chứa apiKey, authDomain, databaseURL...</p>
|
|
36
|
-
</div>
|
|
37
|
-
|
|
38
|
-
<div class="button-group">
|
|
39
|
-
<button type="submit" class="btn-primary">💾 Lưu cấu hình</button>
|
|
40
|
-
<button type="button" id="resetBtn" class="btn-secondary">🔄 Đặt lại mặc định</button>
|
|
41
|
-
</div>
|
|
42
|
-
</form>
|
|
43
|
-
</div>
|
|
44
|
-
|
|
45
|
-
<script src="sidepanel.js"></script>
|
|
46
|
-
</body>
|
|
47
|
-
|
|
48
|
-
</html>
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { EnvironmentStorageService } from './utils/environment-storage.service';
|
|
2
|
-
import { environment } from '../environments/environment';
|
|
3
|
-
|
|
4
|
-
// DOM Elements
|
|
5
|
-
const form = document.getElementById('configForm') as HTMLFormElement;
|
|
6
|
-
const environmentInput = document.getElementById('environmentName') as HTMLInputElement;
|
|
7
|
-
const firebaseConfigInput = document.getElementById('firebaseConfig') as HTMLTextAreaElement;
|
|
8
|
-
const resetBtn = document.getElementById('resetBtn') as HTMLButtonElement;
|
|
9
|
-
const messageDiv = document.getElementById('message') as HTMLDivElement;
|
|
10
|
-
const currentEnvSpan = document.getElementById('currentEnv') as HTMLSpanElement;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Hiển thị thông báo cho người dùng
|
|
14
|
-
*/
|
|
15
|
-
function showMessage(text: string, type: 'success' | 'error') {
|
|
16
|
-
messageDiv.textContent = text;
|
|
17
|
-
messageDiv.className = `message ${type}`;
|
|
18
|
-
|
|
19
|
-
// Tự động ẩn thông báo sau 3 giây
|
|
20
|
-
setTimeout(() => {
|
|
21
|
-
messageDiv.className = 'message';
|
|
22
|
-
}, 3000);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Load và hiển thị giá trị hiện tại
|
|
27
|
-
*/
|
|
28
|
-
async function loadCurrentConfig() {
|
|
29
|
-
try {
|
|
30
|
-
// Load Env Name
|
|
31
|
-
const envName = await EnvironmentStorageService.getEnvironmentName();
|
|
32
|
-
currentEnvSpan.textContent = envName;
|
|
33
|
-
environmentInput.value = envName;
|
|
34
|
-
|
|
35
|
-
// Load Firebase Config
|
|
36
|
-
const fbConfig = await EnvironmentStorageService.getFirebaseConfig();
|
|
37
|
-
|
|
38
|
-
// Kiểm tra xem có phải config mặc định không
|
|
39
|
-
const isDefault = JSON.stringify(fbConfig) === JSON.stringify(environment.firebaseConfig);
|
|
40
|
-
|
|
41
|
-
if (!isDefault) {
|
|
42
|
-
firebaseConfigInput.value = JSON.stringify(fbConfig, null, 2);
|
|
43
|
-
} else {
|
|
44
|
-
firebaseConfigInput.value = ''; // Để trống nếu đang dùng default
|
|
45
|
-
firebaseConfigInput.placeholder = `Đang sử dụng mặc định:\n${JSON.stringify(environment.firebaseConfig, null, 2)}`;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
} catch (error) {
|
|
49
|
-
console.error('Error loading config:', error);
|
|
50
|
-
currentEnvSpan.textContent = 'Lỗi khi tải cấu hình';
|
|
51
|
-
showMessage('Không thể tải cấu hình hiện tại', 'error');
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Xử lý sự kiện submit form
|
|
57
|
-
*/
|
|
58
|
-
async function handleSubmit(event: Event) {
|
|
59
|
-
event.preventDefault();
|
|
60
|
-
|
|
61
|
-
const newEnvName = environmentInput.value.trim();
|
|
62
|
-
const firebaseConfigStr = firebaseConfigInput.value.trim();
|
|
63
|
-
|
|
64
|
-
if (!newEnvName) {
|
|
65
|
-
showMessage('Vui lòng nhập tên môi trường', 'error');
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
try {
|
|
70
|
-
// 1. Lưu Environment Name
|
|
71
|
-
await EnvironmentStorageService.setEnvironmentName(newEnvName);
|
|
72
|
-
currentEnvSpan.textContent = newEnvName;
|
|
73
|
-
|
|
74
|
-
// 2. Lưu Firebase Config
|
|
75
|
-
if (firebaseConfigStr) {
|
|
76
|
-
try {
|
|
77
|
-
const configObj = JSON.parse(firebaseConfigStr);
|
|
78
|
-
// Validate sơ bộ
|
|
79
|
-
if (!configObj.apiKey || !configObj.databaseURL) {
|
|
80
|
-
throw new Error("Config thiếu apiKey hoặc databaseURL");
|
|
81
|
-
}
|
|
82
|
-
await EnvironmentStorageService.setFirebaseConfig(configObj);
|
|
83
|
-
} catch (e) {
|
|
84
|
-
showMessage('❌ JSON Firebase Config không hợp lệ: ' + (e as Error).message, 'error');
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
} else {
|
|
88
|
-
// Nếu để trống, xóa custom config để dùng default
|
|
89
|
-
await new Promise<void>((resolve) => {
|
|
90
|
-
chrome.storage.sync.remove('firebaseConfig', () => resolve());
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
showMessage('✅ Lưu cấu hình thành công!', 'success');
|
|
95
|
-
// Reload lại hiển thị để update placeholder/value
|
|
96
|
-
loadCurrentConfig();
|
|
97
|
-
|
|
98
|
-
} catch (error) {
|
|
99
|
-
console.error('Error saving settings:', error);
|
|
100
|
-
showMessage('❌ Lỗi khi lưu cấu hình: ' + (error as Error).message, 'error');
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Xử lý sự kiện reset về mặc định
|
|
106
|
-
*/
|
|
107
|
-
async function handleReset() {
|
|
108
|
-
if (!confirm('Bạn có chắc muốn đặt lại tất cả về mặc định?')) {
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
try {
|
|
113
|
-
await EnvironmentStorageService.resetToDefault();
|
|
114
|
-
await loadCurrentConfig(); // Reload UI
|
|
115
|
-
showMessage('✅ Đã đặt lại về cấu hình mặc định!', 'success');
|
|
116
|
-
} catch (error) {
|
|
117
|
-
console.error('Error resetting environment:', error);
|
|
118
|
-
showMessage('❌ Lỗi khi đặt lại cấu hình', 'error');
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Event Listeners
|
|
123
|
-
form.addEventListener('submit', handleSubmit);
|
|
124
|
-
resetBtn.addEventListener('click', handleReset);
|
|
125
|
-
|
|
126
|
-
// Load giá trị hiện tại khi trang được mở
|
|
127
|
-
loadCurrentConfig();
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
// AI Chat Providers Configuration
|
|
2
|
-
// Domains for automatic VG Coder iframe injection
|
|
3
|
-
|
|
4
|
-
export const AI_DOMAINS = [
|
|
5
|
-
'chat.openai.com', // ChatGPT (old URL)
|
|
6
|
-
'chatgpt.com', // ChatGPT (new URL)
|
|
7
|
-
'gemini.google.com', // Google Gemini
|
|
8
|
-
'aistudio.google.com', // Google AI Studio
|
|
9
|
-
'chat.deepseek.com', // DeepSeek
|
|
10
|
-
'kimi.com', // Kimi AI
|
|
11
|
-
'www.kimi.com', // Kimi AI (www)
|
|
12
|
-
'grok.com', // Grok
|
|
13
|
-
'claude.ai', // Claude (Anthropic)
|
|
14
|
-
'poe.com', // Poe
|
|
15
|
-
'perplexity.ai', // Perplexity
|
|
16
|
-
'www.perplexity.ai', // Perplexity (www)
|
|
17
|
-
];
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Check if domain should have VG Coder iframe injected
|
|
21
|
-
*/
|
|
22
|
-
export function isAIChatDomain(hostname: string): boolean {
|
|
23
|
-
const cleanHostname = hostname.toLowerCase().replace(/^www\./, '');
|
|
24
|
-
console.log('🔍 Checking AI domain:', cleanHostname);
|
|
25
|
-
|
|
26
|
-
const isMatch = AI_DOMAINS.some(domain => {
|
|
27
|
-
const cleanDomain = domain.toLowerCase().replace(/^www\./, '');
|
|
28
|
-
return cleanHostname === cleanDomain || cleanHostname.endsWith('.' + cleanDomain);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
console.log('🎯 AI domain match:', isMatch);
|
|
32
|
-
return isMatch;
|
|
33
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { environment } from "../../environments/environment";
|
|
2
|
-
|
|
3
|
-
const STORAGE_KEY = 'environmentName';
|
|
4
|
-
const FIREBASE_CONFIG_KEY = 'firebaseConfig';
|
|
5
|
-
const DEFAULT_ENVIRONMENT = environment.environmentName;
|
|
6
|
-
|
|
7
|
-
export class EnvironmentStorageService {
|
|
8
|
-
/**
|
|
9
|
-
* Lấy environment name từ chrome.storage
|
|
10
|
-
*/
|
|
11
|
-
static async getEnvironmentName(): Promise<string> {
|
|
12
|
-
return new Promise((resolve) => {
|
|
13
|
-
chrome.storage.sync.get([STORAGE_KEY], (result) => {
|
|
14
|
-
const envName = result[STORAGE_KEY] || DEFAULT_ENVIRONMENT;
|
|
15
|
-
resolve(envName);
|
|
16
|
-
});
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Lưu environment name vào chrome.storage
|
|
22
|
-
*/
|
|
23
|
-
static async setEnvironmentName(name: string): Promise<void> {
|
|
24
|
-
return new Promise((resolve, reject) => {
|
|
25
|
-
if (!name || name.trim() === '') {
|
|
26
|
-
reject(new Error('Environment name cannot be empty'));
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
chrome.storage.sync.set({ [STORAGE_KEY]: name.trim() }, () => {
|
|
31
|
-
if (chrome.runtime.lastError) {
|
|
32
|
-
reject(chrome.runtime.lastError);
|
|
33
|
-
} else {
|
|
34
|
-
resolve();
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Lấy cấu hình Firebase. Ưu tiên storage, fallback về environment mặc định
|
|
42
|
-
*/
|
|
43
|
-
static async getFirebaseConfig(): Promise<any> {
|
|
44
|
-
return new Promise((resolve) => {
|
|
45
|
-
chrome.storage.sync.get([FIREBASE_CONFIG_KEY], (result) => {
|
|
46
|
-
const customConfig = result[FIREBASE_CONFIG_KEY];
|
|
47
|
-
if (customConfig && Object.keys(customConfig).length > 0) {
|
|
48
|
-
resolve(customConfig);
|
|
49
|
-
} else {
|
|
50
|
-
resolve(environment.firebaseConfig);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Lưu cấu hình Firebase tùy chỉnh
|
|
58
|
-
*/
|
|
59
|
-
static async setFirebaseConfig(config: any): Promise<void> {
|
|
60
|
-
return new Promise((resolve, reject) => {
|
|
61
|
-
chrome.storage.sync.set({ [FIREBASE_CONFIG_KEY]: config }, () => {
|
|
62
|
-
if (chrome.runtime.lastError) {
|
|
63
|
-
reject(chrome.runtime.lastError);
|
|
64
|
-
} else {
|
|
65
|
-
resolve();
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Reset về giá trị mặc định
|
|
73
|
-
*/
|
|
74
|
-
static async resetToDefault(): Promise<void> {
|
|
75
|
-
try {
|
|
76
|
-
await this.setEnvironmentName(DEFAULT_ENVIRONMENT);
|
|
77
|
-
// Xóa config firebase custom để dùng mặc định
|
|
78
|
-
await new Promise<void>((resolve) => {
|
|
79
|
-
chrome.storage.sync.remove(FIREBASE_CONFIG_KEY, () => resolve());
|
|
80
|
-
});
|
|
81
|
-
} catch (e) {
|
|
82
|
-
throw e;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
// VG Coder Iframe Injector Script (Bundled for Extension)
|
|
2
|
-
// Two-Button Toggle with hidden fullscreen when collapsed
|
|
3
|
-
|
|
4
|
-
export const VG_CODER_INJECTOR_SCRIPT = `
|
|
5
|
-
(function() {
|
|
6
|
-
'use strict';
|
|
7
|
-
|
|
8
|
-
const CONFIG = {
|
|
9
|
-
VG_CODER_URL: 'http://localhost:6868?embedded=true',
|
|
10
|
-
IFRAME_ID: 'vg-coder-side-iframe',
|
|
11
|
-
CONTAINER_ID: 'vg-coder-container',
|
|
12
|
-
CONTROLS_ID: 'vg-coder-controls',
|
|
13
|
-
RESIZE_HANDLE_ID: 'vg-coder-resize-handle',
|
|
14
|
-
DEFAULT_WIDTH: '420px',
|
|
15
|
-
FULLSCREEN_WIDTH: '100%',
|
|
16
|
-
MIN_WIDTH: 300,
|
|
17
|
-
MAX_WIDTH_PERCENT: 70,
|
|
18
|
-
STATE_DEFAULT: 'default',
|
|
19
|
-
STATE_FULLSCREEN: 'fullscreen',
|
|
20
|
-
STATE_COLLAPSED: 'collapsed',
|
|
21
|
-
Z_INDEX: 9999,
|
|
22
|
-
STORAGE_KEY_WIDTH: 'vg_coder_width',
|
|
23
|
-
STORAGE_KEY_STATE: 'vg_coder_state',
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
if (sessionStorage.getItem('VG_CODER_NESTED') === 'true') {
|
|
27
|
-
console.log('🚫 VG Coder iframe injection skipped - nested context');
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (window.self !== window.top && document.referrer.includes(':6868')) {
|
|
32
|
-
console.log('🚫 VG Coder iframe injection skipped - parent is :6868');
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (document.getElementById(CONFIG.CONTAINER_ID)) {
|
|
37
|
-
console.log('⚠️ VG Coder iframe already injected');
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function getState() {
|
|
42
|
-
return localStorage.getItem(CONFIG.STORAGE_KEY_STATE) || CONFIG.STATE_DEFAULT;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function getWidth() {
|
|
46
|
-
return localStorage.getItem(CONFIG.STORAGE_KEY_WIDTH) || CONFIG.DEFAULT_WIDTH;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function setState(state) {
|
|
50
|
-
localStorage.setItem(CONFIG.STORAGE_KEY_STATE, state);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function setWidth(width) {
|
|
54
|
-
localStorage.setItem(CONFIG.STORAGE_KEY_WIDTH, width);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function updateBodyMargin(width) {
|
|
58
|
-
if (!document.body.style.transition.includes('margin')) {
|
|
59
|
-
document.body.style.transition = 'margin-left 0.3s ease';
|
|
60
|
-
}
|
|
61
|
-
document.body.style.marginLeft = width;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function removeBodyMargin() {
|
|
65
|
-
document.body.style.marginLeft = '0';
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function injectStyles() {
|
|
69
|
-
const style = document.createElement('style');
|
|
70
|
-
style.textContent = '#' + CONFIG.CONTAINER_ID + ' {' +
|
|
71
|
-
'position: fixed; top: 0; left: 0; bottom: 0;' +
|
|
72
|
-
'width: ' + getWidth() + ';' +
|
|
73
|
-
'background: #1a1a1a; z-index: ' + CONFIG.Z_INDEX + ';' +
|
|
74
|
-
'display: flex; flex-direction: column;' +
|
|
75
|
-
'box-shadow: 4px 0 12px rgba(0, 0, 0, 0.3);' +
|
|
76
|
-
'transition: width 0.3s ease, transform 0.3s ease;' +
|
|
77
|
-
'}' +
|
|
78
|
-
'#' + CONFIG.CONTAINER_ID + '.collapsed { transform: translateX(-100%); }' +
|
|
79
|
-
'#' + CONFIG.IFRAME_ID + ' {' +
|
|
80
|
-
'flex: 1; border: none; width: 100%; height: 100%; background: white;' +
|
|
81
|
-
'}' +
|
|
82
|
-
'#' + CONFIG.CONTROLS_ID + ' {' +
|
|
83
|
-
'position: absolute; top: 50%; right: -36px; transform: translateY(-50%);' +
|
|
84
|
-
'z-index: ' + (CONFIG.Z_INDEX + 1) + '; display: flex; flex-direction: column; gap: 4px;' +
|
|
85
|
-
'transition: right 0.3s ease;' +
|
|
86
|
-
'}' +
|
|
87
|
-
'#' + CONFIG.CONTROLS_ID + '.fullscreen {' +
|
|
88
|
-
'right: 12px;' +
|
|
89
|
-
'}' +
|
|
90
|
-
'#' + CONFIG.CONTROLS_ID + ' button {' +
|
|
91
|
-
'background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);' +
|
|
92
|
-
'color: white; border: none; border-radius: 0 6px 6px 0;' +
|
|
93
|
-
'padding: 8px 6px; cursor: pointer; font-size: 18px;' +
|
|
94
|
-
'box-shadow: -2px 2px 6px rgba(0, 0, 0, 0.2);' +
|
|
95
|
-
'transition: all 0.2s ease; width: 32px; height: 32px;' +
|
|
96
|
-
'display: flex; align-items: center; justify-content: center;' +
|
|
97
|
-
'}' +
|
|
98
|
-
'#' + CONFIG.CONTROLS_ID + ' button.hidden {' +
|
|
99
|
-
'display: none;' +
|
|
100
|
-
'}' +
|
|
101
|
-
'#' + CONFIG.CONTROLS_ID + ' button:hover {' +
|
|
102
|
-
'background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);' +
|
|
103
|
-
'box-shadow: -3px 3px 8px rgba(0, 0, 0, 0.3);' +
|
|
104
|
-
'}' +
|
|
105
|
-
'#' + CONFIG.RESIZE_HANDLE_ID + ' {' +
|
|
106
|
-
'position: absolute; right: 0; top: 0; bottom: 0; width: 6px;' +
|
|
107
|
-
'cursor: ew-resize; background: transparent; transition: background 0.2s ease;' +
|
|
108
|
-
'}' +
|
|
109
|
-
'#' + CONFIG.RESIZE_HANDLE_ID + ':hover { background: rgba(102, 126, 234, 0.5); }' +
|
|
110
|
-
'#' + CONFIG.RESIZE_HANDLE_ID + '.resizing { background: rgba(102, 126, 234, 0.8); }';
|
|
111
|
-
document.head.appendChild(style);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function createContainer() {
|
|
115
|
-
const container = document.createElement('div');
|
|
116
|
-
container.id = CONFIG.CONTAINER_ID;
|
|
117
|
-
const currentState = getState();
|
|
118
|
-
if (currentState === CONFIG.STATE_COLLAPSED) {
|
|
119
|
-
container.classList.add('collapsed');
|
|
120
|
-
} else if (currentState === CONFIG.STATE_FULLSCREEN) {
|
|
121
|
-
container.style.width = CONFIG.FULLSCREEN_WIDTH;
|
|
122
|
-
}
|
|
123
|
-
return container;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function createIframe() {
|
|
127
|
-
const iframe = document.createElement('iframe');
|
|
128
|
-
iframe.id = CONFIG.IFRAME_ID;
|
|
129
|
-
iframe.src = CONFIG.VG_CODER_URL;
|
|
130
|
-
iframe.title = 'VG Coder Dashboard';
|
|
131
|
-
iframe.allow = 'clipboard-read; clipboard-write';
|
|
132
|
-
return iframe;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function createResizeHandle() {
|
|
136
|
-
const handle = document.createElement('div');
|
|
137
|
-
handle.id = CONFIG.RESIZE_HANDLE_ID;
|
|
138
|
-
return handle;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function createControls() {
|
|
142
|
-
const controls = document.createElement('div');
|
|
143
|
-
controls.id = CONFIG.CONTROLS_ID;
|
|
144
|
-
const currentState = getState();
|
|
145
|
-
if (currentState === CONFIG.STATE_FULLSCREEN) {
|
|
146
|
-
controls.classList.add('fullscreen');
|
|
147
|
-
}
|
|
148
|
-
const btnFullscreen = document.createElement('button');
|
|
149
|
-
btnFullscreen.innerHTML = currentState === CONFIG.STATE_FULLSCREEN ? '◧' : '▣';
|
|
150
|
-
btnFullscreen.title = currentState === CONFIG.STATE_FULLSCREEN ? 'Default (45%)' : 'Fullscreen (100%)';
|
|
151
|
-
if (currentState === CONFIG.STATE_COLLAPSED) {
|
|
152
|
-
btnFullscreen.classList.add('hidden');
|
|
153
|
-
}
|
|
154
|
-
const btnCollapse = document.createElement('button');
|
|
155
|
-
btnCollapse.innerHTML = currentState === CONFIG.STATE_COLLAPSED ? '▶' : '◄';
|
|
156
|
-
btnCollapse.title = currentState === CONFIG.STATE_COLLAPSED ? 'Expand' : 'Collapse';
|
|
157
|
-
controls.appendChild(btnFullscreen);
|
|
158
|
-
controls.appendChild(btnCollapse);
|
|
159
|
-
return controls;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function initResize(container, handle, controls) {
|
|
163
|
-
let isResizing = false, startX = 0, startWidth = 0;
|
|
164
|
-
handle.addEventListener('mousedown', (e) => {
|
|
165
|
-
isResizing = true; startX = e.clientX; startWidth = container.offsetWidth;
|
|
166
|
-
handle.classList.add('resizing');
|
|
167
|
-
document.body.style.cursor = 'ew-resize';
|
|
168
|
-
document.body.style.userSelect = 'none';
|
|
169
|
-
e.preventDefault();
|
|
170
|
-
});
|
|
171
|
-
document.addEventListener('mousemove', (e) => {
|
|
172
|
-
if (!isResizing) return;
|
|
173
|
-
const deltaX = e.clientX - startX;
|
|
174
|
-
const newWidth = startWidth + deltaX;
|
|
175
|
-
const maxWidth = window.innerWidth * (CONFIG.MAX_WIDTH_PERCENT / 100);
|
|
176
|
-
if (newWidth >= CONFIG.MIN_WIDTH && newWidth <= maxWidth) {
|
|
177
|
-
const widthPercent = (newWidth / window.innerWidth) * 100;
|
|
178
|
-
container.style.width = widthPercent + '%';
|
|
179
|
-
setWidth(widthPercent + '%');
|
|
180
|
-
updateBodyMargin(widthPercent + '%');
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
document.addEventListener('mouseup', () => {
|
|
184
|
-
if (isResizing) {
|
|
185
|
-
isResizing = false; handle.classList.remove('resizing');
|
|
186
|
-
document.body.style.cursor = '';
|
|
187
|
-
document.body.style.userSelect = '';
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function initControls(container, controls) {
|
|
193
|
-
const buttons = controls.querySelectorAll('button');
|
|
194
|
-
const btnFullscreen = buttons[0];
|
|
195
|
-
const btnCollapse = buttons[1];
|
|
196
|
-
btnFullscreen.addEventListener('click', () => {
|
|
197
|
-
const currentState = getState();
|
|
198
|
-
if (currentState === CONFIG.STATE_FULLSCREEN) {
|
|
199
|
-
setState(CONFIG.STATE_DEFAULT);
|
|
200
|
-
container.style.width = CONFIG.DEFAULT_WIDTH;
|
|
201
|
-
controls.classList.remove('fullscreen');
|
|
202
|
-
btnFullscreen.innerHTML = '▣';
|
|
203
|
-
btnFullscreen.title = 'Fullscreen (100%)';
|
|
204
|
-
updateBodyMargin(CONFIG.DEFAULT_WIDTH);
|
|
205
|
-
} else {
|
|
206
|
-
setState(CONFIG.STATE_FULLSCREEN);
|
|
207
|
-
container.style.width = CONFIG.FULLSCREEN_WIDTH;
|
|
208
|
-
controls.classList.add('fullscreen');
|
|
209
|
-
btnFullscreen.innerHTML = '◧';
|
|
210
|
-
btnFullscreen.title = 'Default (45%)';
|
|
211
|
-
updateBodyMargin(CONFIG.FULLSCREEN_WIDTH);
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
btnCollapse.addEventListener('click', () => {
|
|
215
|
-
const currentState = getState();
|
|
216
|
-
if (currentState === CONFIG.STATE_COLLAPSED) {
|
|
217
|
-
setState(CONFIG.STATE_DEFAULT);
|
|
218
|
-
container.classList.remove('collapsed');
|
|
219
|
-
container.style.width = CONFIG.DEFAULT_WIDTH;
|
|
220
|
-
controls.classList.remove('fullscreen');
|
|
221
|
-
btnCollapse.innerHTML = '◄';
|
|
222
|
-
btnCollapse.title = 'Collapse';
|
|
223
|
-
btnFullscreen.classList.remove('hidden');
|
|
224
|
-
btnFullscreen.innerHTML = '▣';
|
|
225
|
-
btnFullscreen.title = 'Fullscreen (100%)';
|
|
226
|
-
updateBodyMargin(CONFIG.DEFAULT_WIDTH);
|
|
227
|
-
} else {
|
|
228
|
-
const wasFullscreen = currentState === CONFIG.STATE_FULLSCREEN;
|
|
229
|
-
setState(CONFIG.STATE_COLLAPSED);
|
|
230
|
-
container.classList.add('collapsed');
|
|
231
|
-
if (wasFullscreen) {
|
|
232
|
-
controls.classList.remove('fullscreen');
|
|
233
|
-
}
|
|
234
|
-
btnFullscreen.classList.add('hidden');
|
|
235
|
-
btnCollapse.innerHTML = '▶';
|
|
236
|
-
btnCollapse.title = 'Expand';
|
|
237
|
-
removeBodyMargin();
|
|
238
|
-
}
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
function init() {
|
|
243
|
-
if (!document.body) {
|
|
244
|
-
setTimeout(init, 100);
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
console.log('🚀 Initializing VG Coder iframe injection...');
|
|
248
|
-
injectStyles();
|
|
249
|
-
const container = createContainer();
|
|
250
|
-
const iframe = createIframe();
|
|
251
|
-
const resizeHandle = createResizeHandle();
|
|
252
|
-
const controls = createControls();
|
|
253
|
-
container.appendChild(resizeHandle);
|
|
254
|
-
container.appendChild(iframe);
|
|
255
|
-
container.appendChild(controls);
|
|
256
|
-
document.body.appendChild(container);
|
|
257
|
-
initResize(container, resizeHandle, controls);
|
|
258
|
-
initControls(container, controls);
|
|
259
|
-
const currentState = getState();
|
|
260
|
-
if (currentState !== CONFIG.STATE_COLLAPSED) {
|
|
261
|
-
const width = currentState === CONFIG.STATE_FULLSCREEN ? CONFIG.FULLSCREEN_WIDTH : getWidth();
|
|
262
|
-
updateBodyMargin(width);
|
|
263
|
-
}
|
|
264
|
-
console.log('✅ VG Coder iframe injected successfully');
|
|
265
|
-
}
|
|
266
|
-
if (document.readyState === 'loading') {
|
|
267
|
-
document.addEventListener('DOMContentLoaded', init);
|
|
268
|
-
} else {
|
|
269
|
-
init();
|
|
270
|
-
}
|
|
271
|
-
})();
|
|
272
|
-
`;
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
const { join } = require('path');
|
|
2
|
-
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
|
3
|
-
|
|
4
|
-
module.exports = {
|
|
5
|
-
mode: 'development',
|
|
6
|
-
devtool: 'inline-source-map',
|
|
7
|
-
entry: {
|
|
8
|
-
background: join(__dirname, 'src/background.ts'),
|
|
9
|
-
controller: join(__dirname, 'src/controller.ts'),
|
|
10
|
-
sidepanel: join(__dirname, 'src/sidepanel.ts'),
|
|
11
|
-
},
|
|
12
|
-
module: {
|
|
13
|
-
rules: [
|
|
14
|
-
{
|
|
15
|
-
test: /\.ts?$/,
|
|
16
|
-
use: 'ts-loader',
|
|
17
|
-
exclude: /node_modules/,
|
|
18
|
-
},
|
|
19
|
-
],
|
|
20
|
-
},
|
|
21
|
-
output: {
|
|
22
|
-
path: join(__dirname, 'dist'),
|
|
23
|
-
filename: '[name].js'
|
|
24
|
-
},
|
|
25
|
-
plugins: [
|
|
26
|
-
new CopyWebpackPlugin({
|
|
27
|
-
patterns: [
|
|
28
|
-
{
|
|
29
|
-
from: join(__dirname, 'manifest.json'),
|
|
30
|
-
to: join(__dirname, 'dist')
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
from: join(__dirname, 'rules.json'),
|
|
34
|
-
to: join(__dirname, 'dist')
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
from: join(__dirname, 'src/sidepanel.html'),
|
|
38
|
-
to: join(__dirname, 'dist')
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
from: join(__dirname, 'src/sidepanel.css'),
|
|
42
|
-
to: join(__dirname, 'dist')
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
from: join(__dirname, 'assets'),
|
|
46
|
-
to: join(__dirname, 'dist/assets')
|
|
47
|
-
}
|
|
48
|
-
]
|
|
49
|
-
})],
|
|
50
|
-
resolve: {
|
|
51
|
-
extensions: ['.ts', '.js']
|
|
52
|
-
}
|
|
53
|
-
};
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
const { join } = require('path');
|
|
2
|
-
const { optimize } = require('webpack');
|
|
3
|
-
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
|
4
|
-
|
|
5
|
-
module.exports = {
|
|
6
|
-
mode: 'production',
|
|
7
|
-
entry: {
|
|
8
|
-
background: join(__dirname, 'src/background.ts'),
|
|
9
|
-
controller: join(__dirname, 'src/controller.ts'),
|
|
10
|
-
sidepanel: join(__dirname, 'src/sidepanel.ts'),
|
|
11
|
-
},
|
|
12
|
-
module: {
|
|
13
|
-
rules: [
|
|
14
|
-
{
|
|
15
|
-
test: /\.ts?$/,
|
|
16
|
-
use: 'ts-loader',
|
|
17
|
-
exclude: /node_modules/,
|
|
18
|
-
},
|
|
19
|
-
],
|
|
20
|
-
},
|
|
21
|
-
output: {
|
|
22
|
-
path: join(__dirname, 'dist'),
|
|
23
|
-
filename: '[name].js'
|
|
24
|
-
},
|
|
25
|
-
plugins: [
|
|
26
|
-
new optimize.AggressiveMergingPlugin(),
|
|
27
|
-
new CopyWebpackPlugin({
|
|
28
|
-
patterns: [
|
|
29
|
-
{
|
|
30
|
-
from: join(__dirname, 'manifest.json'),
|
|
31
|
-
to: join(__dirname, 'dist')
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
from: join(__dirname, 'rules.json'),
|
|
35
|
-
to: join(__dirname, 'dist')
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
from: join(__dirname, 'src/sidepanel.html'),
|
|
39
|
-
to: join(__dirname, 'dist')
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
from: join(__dirname, 'src/sidepanel.css'),
|
|
43
|
-
to: join(__dirname, 'dist')
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
from: join(__dirname, 'assets'),
|
|
47
|
-
to: join(__dirname, 'dist/assets')
|
|
48
|
-
}
|
|
49
|
-
]
|
|
50
|
-
})],
|
|
51
|
-
resolve: {
|
|
52
|
-
extensions: ['.ts', '.js']
|
|
53
|
-
}
|
|
54
|
-
};
|