antigravity-rtl-patcher 3.0.2 → 3.0.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "antigravity-rtl-patcher",
3
- "version": "3.0.2",
3
+ "version": "3.0.5",
4
4
  "description": "Advanced RTL and Persian/Arabic typography patcher for Antigravity with customizable UI",
5
5
  "main": "src/patcher.js",
6
6
  "bin": {
Binary file
@@ -13,9 +13,7 @@ win.webContents.on('console-message', (event, ...args) => {
13
13
  const configData = message.substring(16);
14
14
  const configPath = require('path').join(require('os').homedir(), '.antigravity-rtl.json');
15
15
  require('fs').writeFileSync(configPath, configData, 'utf8');
16
- } catch (err) {
17
- console.error('[RTL] Config save failed:', err);
18
- }
16
+ } catch (err) {}
19
17
  }
20
18
  });
21
19
 
@@ -38,52 +36,276 @@ win.webContents.on('dom-ready', () => {
38
36
  window.__RTL_LOADED__ = true;
39
37
 
40
38
  let rtlEnabled = ${rtlConfig.enabled};
39
+ let panelVisible = false;
40
+
41
+ // RTL Detection Function
42
+ function isRTLText(text) {
43
+ if (!text || typeof text !== 'string') return false;
44
+ const rtlChars = /[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]/;
45
+ const cleanText = text.trim();
46
+ if (cleanText.length === 0) return false;
47
+
48
+ // Check first non-whitespace character
49
+ for (let char of cleanText) {
50
+ if (char.trim()) {
51
+ return rtlChars.test(char);
52
+ }
53
+ }
54
+ return false;
55
+ }
56
+
57
+ // Apply RTL to text elements dynamically
58
+ function applyRTLToContent() {
59
+ if (!rtlEnabled) return;
60
+
61
+ // Target message containers and paragraphs
62
+ const textElements = document.querySelectorAll('p, h1, h2, h3, h4, h5, h6, li, blockquote, td, th');
63
+
64
+ textElements.forEach(el => {
65
+ // Skip if already processed or is UI element
66
+ if (el.classList.contains('rtl-ui') || el.classList.contains('rtl-processed')) return;
67
+
68
+ // Skip code blocks
69
+ if (el.closest('pre, code')) return;
70
+
71
+ const text = el.textContent;
72
+ if (isRTLText(text)) {
73
+ el.setAttribute('dir', 'rtl');
74
+ el.classList.add('rtl-processed');
75
+ } else if (el.hasAttribute('dir') && el.getAttribute('dir') === 'rtl') {
76
+ el.removeAttribute('dir');
77
+ el.classList.remove('rtl-processed');
78
+ }
79
+ });
80
+ }
81
+
82
+ // Observe DOM changes
83
+ const observer = new MutationObserver((mutations) => {
84
+ if (rtlEnabled) {
85
+ applyRTLToContent();
86
+ }
87
+ });
88
+
89
+ // Start observing after a short delay
90
+ setTimeout(() => {
91
+ observer.observe(document.body, {
92
+ childList: true,
93
+ subtree: true,
94
+ characterData: true
95
+ });
96
+ applyRTLToContent();
97
+ }, 500);
41
98
 
42
99
  const CSS = \`
43
- p, h1, h2, h3, h4, h5, h6, ul, ol, li, div, span {
44
- unicode-bidi: plaintext;
45
- text-align: start;
100
+ /* Vazirmatn Font */
101
+ @font-face {
102
+ font-family: 'Vazirmatn';
103
+ src: url('./Vazirmatn-Variable.woff2') format('woff2');
104
+ font-weight: 100 900;
105
+ font-display: swap;
46
106
  }
47
107
 
48
- [dir="rtl"] ul, [dir="rtl"] ol {
49
- padding-left: 0 !important;
50
- padding-right: 1.5rem !important;
108
+ /* Apply Vazirmatn to all text when RTL is active */
109
+ body.rtl-active {
110
+ font-family: 'Vazirmatn', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif !important;
51
111
  }
52
112
 
53
- pre, code, pre *, code * {
113
+ /* RTL Styles - Only for message content */
114
+ body.rtl-active [dir="rtl"] {
115
+ direction: rtl !important;
116
+ text-align: right !important;
54
117
  unicode-bidi: isolate !important;
118
+ }
119
+
120
+ /* Keep paragraphs and headings with proper bidi */
121
+ body.rtl-active p,
122
+ body.rtl-active h1, body.rtl-active h2, body.rtl-active h3,
123
+ body.rtl-active h4, body.rtl-active h5, body.rtl-active h6 {
124
+ unicode-bidi: plaintext !important;
125
+ text-align: start !important;
126
+ }
127
+
128
+ /* Lists in RTL context */
129
+ body.rtl-active [dir="rtl"] ul,
130
+ body.rtl-active [dir="rtl"] ol {
131
+ padding-left: 0 !important;
132
+ padding-right: 2rem !important;
133
+ }
134
+
135
+ /* Code blocks always LTR */
136
+ body.rtl-active pre,
137
+ body.rtl-active code,
138
+ body.rtl-active pre *,
139
+ body.rtl-active code * {
55
140
  direction: ltr !important;
56
141
  text-align: left !important;
142
+ unicode-bidi: isolate !important;
143
+ font-family: 'Courier New', Consolas, Monaco, monospace !important;
57
144
  }
58
145
 
59
- #rtl-toggle-btn {
146
+ /* Panel Container */
147
+ #rtl-trigger {
60
148
  position: fixed;
61
149
  bottom: 20px;
62
150
  right: 20px;
63
- z-index: 999999;
151
+ z-index: 999998;
64
152
  width: 50px;
65
153
  height: 50px;
66
154
  border-radius: 50%;
67
- background: rgba(60, 60, 60, 0.9);
68
- border: 2px solid rgba(100, 100, 100, 0.5);
155
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
156
+ border: none;
69
157
  color: white;
70
158
  cursor: pointer;
71
159
  display: flex;
72
160
  align-items: center;
73
161
  justify-content: center;
74
162
  font-size: 24px;
75
- transition: all 0.3s;
76
- box-shadow: 0 2px 10px rgba(0,0,0,0.3);
163
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
164
+ box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
165
+ }
166
+
167
+ #rtl-trigger:hover {
168
+ transform: scale(1.1) rotate(180deg);
169
+ box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6);
170
+ }
171
+
172
+ #rtl-trigger.active {
173
+ background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
174
+ box-shadow: 0 4px 12px rgba(245, 87, 108, 0.4);
175
+ }
176
+
177
+ #rtl-panel {
178
+ position: fixed;
179
+ bottom: 80px;
180
+ right: 20px;
181
+ z-index: 999999;
182
+ width: 300px;
183
+ background: rgba(255, 255, 255, 0.95);
184
+ backdrop-filter: blur(10px);
185
+ border-radius: 16px;
186
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
187
+ opacity: 0;
188
+ transform: translateY(20px) scale(0.9);
189
+ pointer-events: none;
190
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
191
+ overflow: hidden;
192
+ }
193
+
194
+ #rtl-panel.visible {
195
+ opacity: 1;
196
+ transform: translateY(0) scale(1);
197
+ pointer-events: auto;
198
+ }
199
+
200
+ @media (prefers-color-scheme: dark) {
201
+ #rtl-panel {
202
+ background: rgba(30, 30, 40, 0.95);
203
+ color: #e0e0e0;
204
+ }
205
+ }
206
+
207
+ .rtl-panel-header {
208
+ padding: 20px;
209
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
210
+ color: white;
211
+ text-align: center;
212
+ font-weight: 600;
213
+ font-size: 16px;
214
+ }
215
+
216
+ .rtl-panel-body {
217
+ padding: 24px;
77
218
  }
78
219
 
79
- #rtl-toggle-btn:hover {
80
- background: rgba(80, 80, 80, 0.95);
81
- transform: scale(1.1);
220
+ .rtl-row {
221
+ display: flex;
222
+ align-items: center;
223
+ justify-content: space-between;
224
+ margin-bottom: 16px;
82
225
  }
83
226
 
84
- #rtl-toggle-btn.active {
85
- background: rgba(70, 130, 180, 0.9);
86
- border-color: rgba(70, 130, 180, 0.8);
227
+ .rtl-label {
228
+ font-size: 14px;
229
+ font-weight: 500;
230
+ color: #333;
231
+ }
232
+
233
+ @media (prefers-color-scheme: dark) {
234
+ .rtl-label {
235
+ color: #e0e0e0;
236
+ }
237
+ }
238
+
239
+ /* Toggle Switch */
240
+ .rtl-switch {
241
+ position: relative;
242
+ width: 52px;
243
+ height: 28px;
244
+ background: #ddd;
245
+ border-radius: 14px;
246
+ cursor: pointer;
247
+ transition: background 0.3s;
248
+ }
249
+
250
+ .rtl-switch.active {
251
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
252
+ }
253
+
254
+ .rtl-switch::after {
255
+ content: '';
256
+ position: absolute;
257
+ width: 22px;
258
+ height: 22px;
259
+ background: white;
260
+ border-radius: 50%;
261
+ top: 3px;
262
+ left: 3px;
263
+ transition: transform 0.3s;
264
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
265
+ }
266
+
267
+ .rtl-switch.active::after {
268
+ transform: translateX(24px);
269
+ }
270
+
271
+ .rtl-panel-footer {
272
+ padding: 16px 24px;
273
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
274
+ display: flex;
275
+ justify-content: center;
276
+ }
277
+
278
+ @media (prefers-color-scheme: dark) {
279
+ .rtl-panel-footer {
280
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
281
+ }
282
+ }
283
+
284
+ .rtl-github-btn {
285
+ display: flex;
286
+ align-items: center;
287
+ gap: 8px;
288
+ padding: 10px 20px;
289
+ background: #24292e;
290
+ color: white;
291
+ border: none;
292
+ border-radius: 8px;
293
+ cursor: pointer;
294
+ font-size: 13px;
295
+ font-weight: 500;
296
+ text-decoration: none;
297
+ transition: all 0.2s;
298
+ }
299
+
300
+ .rtl-github-btn:hover {
301
+ background: #1a1f23;
302
+ transform: translateY(-2px);
303
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
304
+ }
305
+
306
+ .rtl-github-icon {
307
+ width: 18px;
308
+ height: 18px;
87
309
  }
88
310
  \`;
89
311
 
@@ -92,96 +314,87 @@ win.webContents.on('dom-ready', () => {
92
314
  styleEl.textContent = CSS;
93
315
  document.head.appendChild(styleEl);
94
316
 
95
- function detectRTL(text) {
96
- if (!text || text.trim().length === 0) return false;
97
- const cleaned = text.replace(/[\\u200B-\\u200F\\uFEFF]/g, '').trim();
98
- if (cleaned.length === 0) return false;
99
-
100
- const firstChar = cleaned.match(/[A-Za-z\\u0600-\\u06FF\\u0750-\\u077F\\u08A0-\\u08FF\\uFB50-\\uFDFF\\uFE70-\\uFEFF]/);
101
- if (!firstChar) return false;
102
-
103
- return /[\\u0600-\\u06FF\\u0750-\\u077F\\u08A0-\\u08FF\\uFB50-\\uFDFF\\uFE70-\\uFEFF]/.test(firstChar[0]);
317
+ // Apply RTL class if enabled
318
+ if (rtlEnabled) {
319
+ document.body.classList.add('rtl-active');
104
320
  }
105
321
 
106
- function updateDirections() {
107
- if (!rtlEnabled) return;
108
-
109
- document.querySelectorAll('[contenteditable="true"], [contenteditable="true"] p, textarea').forEach(el => {
110
- const text = el.tagName === 'TEXTAREA' ? el.value : el.textContent;
111
- const cleaned = text.replace(/[\\u200B-\\u200F\\uFEFF]/g, '').trim();
112
-
113
- if (cleaned.length > 0) {
114
- const dir = detectRTL(cleaned) ? 'rtl' : 'ltr';
115
- if (el.getAttribute('dir') !== dir) {
116
- el.setAttribute('dir', dir);
117
- }
118
- } else {
119
- if (el.hasAttribute('dir')) el.removeAttribute('dir');
120
- }
121
- });
122
-
123
- document.querySelectorAll('.prose > *, [data-testid="chat-message"] > *, .markdown-body > *, .leading-relaxed > *').forEach(el => {
124
- if (el.tagName === 'PRE' || el.tagName === 'CODE') return;
125
-
126
- const text = el.textContent.replace(/[\\u200B-\\u200F\\uFEFF]/g, '').trim();
127
- if (text) {
128
- const dir = detectRTL(text) ? 'rtl' : 'ltr';
129
- if (el.getAttribute('dir') !== dir) {
130
- el.setAttribute('dir', dir);
131
- }
132
- }
133
- });
134
- }
322
+ // Create UI
323
+ const trigger = document.createElement('button');
324
+ trigger.id = 'rtl-trigger';
325
+ trigger.className = rtlEnabled ? 'active rtl-ui' : 'rtl-ui';
326
+ trigger.innerHTML = '';
327
+ trigger.title = 'RTL Settings';
135
328
 
136
- document.body.addEventListener('input', updateDirections, { capture: true });
137
- const observer = new MutationObserver(updateDirections);
138
- observer.observe(document.body, { childList: true, subtree: true });
139
- setInterval(updateDirections, 500);
329
+ const panel = document.createElement('div');
330
+ panel.id = 'rtl-panel';
331
+ panel.className = 'rtl-ui';
332
+ panel.innerHTML = \`
333
+ <div class="rtl-panel-header rtl-ui">
334
+ Antigravity Smart RTL
335
+ </div>
336
+ <div class="rtl-panel-body rtl-ui">
337
+ <div class="rtl-row rtl-ui">
338
+ <span class="rtl-label rtl-ui">RTL Mode</span>
339
+ <div class="rtl-switch \${rtlEnabled ? 'active' : ''} rtl-ui" id="rtl-toggle"></div>
340
+ </div>
341
+ </div>
342
+ <div class="rtl-panel-footer rtl-ui">
343
+ <a href="https://github.com/VaFa1726/antigravity-rtl-patcher" target="_blank" class="rtl-github-btn rtl-ui">
344
+ <svg class="rtl-github-icon rtl-ui" viewBox="0 0 16 16" fill="currentColor">
345
+ <path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/>
346
+ </svg>
347
+ Star on GitHub
348
+ </a>
349
+ </div>
350
+ \`;
140
351
 
141
- document.addEventListener('keydown', (e) => {
142
- if (e.altKey && e.code === 'KeyR') {
143
- e.preventDefault();
144
- toggleRTL();
145
- }
146
- }, { capture: true });
352
+ document.body.appendChild(trigger);
353
+ document.body.appendChild(panel);
147
354
 
148
- const btn = document.createElement('button');
149
- btn.id = 'rtl-toggle-btn';
150
- btn.className = rtlEnabled ? 'active' : '';
151
- btn.innerHTML = '⇄';
152
- btn.title = 'Toggle RTL (Alt+R)';
355
+ // Event handlers
356
+ trigger.addEventListener('click', (e) => {
357
+ e.stopPropagation();
358
+ panelVisible = !panelVisible;
359
+ panel.classList.toggle('visible', panelVisible);
360
+ });
153
361
 
154
- btn.addEventListener('click', toggleRTL);
362
+ document.addEventListener('click', (e) => {
363
+ if (!e.target.classList.contains('rtl-ui')) {
364
+ panelVisible = false;
365
+ panel.classList.remove('visible');
366
+ }
367
+ });
155
368
 
156
- function toggleRTL() {
369
+ document.getElementById('rtl-toggle').addEventListener('click', () => {
157
370
  rtlEnabled = !rtlEnabled;
158
371
 
372
+ const toggle = document.getElementById('rtl-toggle');
373
+ toggle.classList.toggle('active', rtlEnabled);
374
+ trigger.classList.toggle('active', rtlEnabled);
375
+
159
376
  if (rtlEnabled) {
160
- btn.classList.add('active');
161
- if (!document.getElementById('rtl-main-style')) {
162
- document.head.appendChild(styleEl);
163
- }
164
- updateDirections();
377
+ document.body.classList.add('rtl-active');
378
+ applyRTLToContent();
165
379
  } else {
166
- btn.classList.remove('active');
167
- if (styleEl.parentNode) {
168
- styleEl.parentNode.removeChild(styleEl);
169
- }
170
- document.querySelectorAll('[dir]').forEach(el => {
171
- if (!el.closest('#rtl-toggle-btn')) {
172
- el.removeAttribute('dir');
173
- }
380
+ document.body.classList.remove('rtl-active');
381
+ // Remove all dir attributes when disabled
382
+ document.querySelectorAll('[dir="rtl"].rtl-processed').forEach(el => {
383
+ el.removeAttribute('dir');
384
+ el.classList.remove('rtl-processed');
174
385
  });
175
386
  }
176
387
 
177
388
  console.log('RTL_CONFIG_SAVE:' + JSON.stringify({ enabled: rtlEnabled }));
178
- }
179
-
180
- document.body.appendChild(btn);
389
+ });
181
390
 
182
- if (rtlEnabled) {
183
- updateDirections();
184
- }
391
+ // Keyboard shortcut
392
+ document.addEventListener('keydown', (e) => {
393
+ if (e.altKey && e.code === 'KeyR') {
394
+ e.preventDefault();
395
+ document.getElementById('rtl-toggle').click();
396
+ }
397
+ });
185
398
  })();
186
399
  `).catch(err => console.error('[RTL] Injection failed:', err));
187
400