antigravity-rtl-patcher 3.0.0 → 3.0.2
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 +24 -192
- package/package.json +1 -1
- package/payload/utils-inject.js +96 -588
- package/src/patcher.js +2 -1
package/README.md
CHANGED
|
@@ -1,233 +1,65 @@
|
|
|
1
1
|
# Antigravity RTL Patcher
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
RTL and Persian/Arabic text support for [Antigravity](https://antigravity.dev) desktop app.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/antigravity-rtl-patcher)
|
|
6
6
|
[](https://www.npmjs.com/package/antigravity-rtl-patcher)
|
|
7
|
-
[](LICENSE)
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## ✨ What's New in v3.0
|
|
12
|
-
|
|
13
|
-
- 🎨 **Advanced UI Panel** - Hover widget with comprehensive customization options
|
|
14
|
-
- 🔤 **Custom Font Support** - Set separate fonts for Persian, English, and code
|
|
15
|
-
- 📏 **Typography Controls** - Adjust line height and font size in real-time
|
|
16
|
-
- 💾 **Persistent Config** - Settings saved to `~/.antigravity-rtl-v3.json`
|
|
17
|
-
- ⚡ **Keyboard Shortcuts** - `Alt + R` to toggle RTL, `Shift + 2` for @ symbol
|
|
18
|
-
- 🔧 **Force RTL Mode** - Override auto-detection for consistent RTL layout
|
|
19
|
-
- 🎯 **Enhanced Detection** - Smarter RTL text recognition algorithm
|
|
20
|
-
- 🚀 **DevTools Enabled** - Built-in developer tools for debugging
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## ⚡ Quick Install
|
|
25
|
-
|
|
26
|
-
Always use `@latest` to ensure you get the newest version:
|
|
8
|
+
## Install
|
|
27
9
|
|
|
28
10
|
```bash
|
|
29
11
|
npx antigravity-rtl-patcher@latest patch
|
|
30
12
|
```
|
|
31
13
|
|
|
32
|
-
|
|
14
|
+
Use `sudo` if Antigravity is in a system directory:
|
|
33
15
|
|
|
34
16
|
```bash
|
|
35
17
|
sudo npx antigravity-rtl-patcher@latest patch
|
|
36
18
|
```
|
|
37
19
|
|
|
38
|
-
Restart Antigravity after patching
|
|
20
|
+
Restart Antigravity after patching.
|
|
39
21
|
|
|
40
|
-
|
|
22
|
+
## Usage
|
|
41
23
|
|
|
42
|
-
|
|
24
|
+
After patching, a toggle button appears in the bottom-right corner. Click it to enable/disable RTL support.
|
|
43
25
|
|
|
44
|
-
|
|
26
|
+
Keyboard shortcut: `Alt + R`
|
|
45
27
|
|
|
46
|
-
|
|
47
|
-
npx antigravity-rtl-patcher@latest patch
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Or check for updates manually:
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
npx antigravity-rtl-patcher@latest update
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
The patcher will automatically notify you when a new version is available.
|
|
57
|
-
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
## 🎨 Features
|
|
61
|
-
|
|
62
|
-
### Smart RTL Detection
|
|
63
|
-
- Automatically detects Persian, Arabic, and Hebrew text
|
|
64
|
-
- Applies proper text direction without breaking layout
|
|
65
|
-
- Preserves LTR for code blocks and English text
|
|
66
|
-
|
|
67
|
-
### Rich UI Panel
|
|
68
|
-
Hover over the globe icon in the bottom-right corner to access:
|
|
69
|
-
|
|
70
|
-
- **RTL Toggle** - Enable/disable RTL support on the fly
|
|
71
|
-
- **Force RTL Mode** - Force RTL layout even when text starts with English
|
|
72
|
-
- **Custom Fonts**:
|
|
73
|
-
- Persian/Arabic font (fallback: Vazirmatn)
|
|
74
|
-
- English font (fallback: system font)
|
|
75
|
-
- Code font (fallback: monospace)
|
|
76
|
-
- **Typography Controls**:
|
|
77
|
-
- Line height slider (1.2 - 2.5)
|
|
78
|
-
- Font size slider (11px - 22px)
|
|
79
|
-
- **@ Sign Fix** - Type `@` with `Shift+2` on Persian keyboard
|
|
80
|
-
- **Keyboard Shortcut** - `Alt + R` to toggle RTL
|
|
81
|
-
|
|
82
|
-
### Persistent Configuration
|
|
83
|
-
All your settings are automatically saved to `~/.antigravity-rtl-v3.json` and restored on restart.
|
|
84
|
-
|
|
85
|
-
---
|
|
86
|
-
|
|
87
|
-
## 🗑️ Uninstall
|
|
88
|
-
|
|
89
|
-
Remove the RTL patch and restore original Antigravity:
|
|
28
|
+
## Uninstall
|
|
90
29
|
|
|
91
30
|
```bash
|
|
92
31
|
npx antigravity-rtl-patcher restore
|
|
93
32
|
```
|
|
94
33
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
```bash
|
|
98
|
-
sudo npx antigravity-rtl-patcher restore
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
## 📋 Commands
|
|
34
|
+
## Commands
|
|
104
35
|
|
|
105
36
|
| Command | Description |
|
|
106
37
|
|---------|-------------|
|
|
107
|
-
| `agy-rtl patch` | Apply RTL patch
|
|
108
|
-
| `agy-rtl restore` | Remove patch
|
|
109
|
-
| `agy-rtl status` | Show
|
|
110
|
-
| `agy-rtl update` | Check for
|
|
111
|
-
| `agy-rtl patch --path /custom/path` | Patch custom installation |
|
|
112
|
-
| `agy-rtl patch --skip-update-check` | Skip update check during patching |
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
|
|
116
|
-
## 🔧 How It Works
|
|
38
|
+
| `agy-rtl patch` | Apply RTL patch |
|
|
39
|
+
| `agy-rtl restore` | Remove patch |
|
|
40
|
+
| `agy-rtl status` | Show patch status |
|
|
41
|
+
| `agy-rtl update` | Check for updates |
|
|
117
42
|
|
|
118
|
-
|
|
43
|
+
## How It Works
|
|
119
44
|
|
|
120
|
-
|
|
121
|
-
2. **Locates** `dist/utils.js` (window creation module)
|
|
122
|
-
3. **Injects** RTL engine at the window lifecycle hook
|
|
123
|
-
4. **Repacks** the modified application
|
|
45
|
+
The patcher modifies Antigravity's `app.asar` to inject RTL detection logic. It automatically detects Persian, Arabic, and Hebrew text and applies proper text direction.
|
|
124
46
|
|
|
125
|
-
|
|
126
|
-
- `MutationObserver` for real-time DOM monitoring
|
|
127
|
-
- Unicode range analysis for RTL detection
|
|
128
|
-
- Dynamic CSS generation for typography control
|
|
129
|
-
- Electron IPC for config persistence
|
|
47
|
+
## After Antigravity Updates
|
|
130
48
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
---
|
|
134
|
-
|
|
135
|
-
## 🔄 After Antigravity Updates
|
|
136
|
-
|
|
137
|
-
Antigravity updates may overwrite the patch. Simply run:
|
|
49
|
+
Run the patch command again after updating Antigravity:
|
|
138
50
|
|
|
139
51
|
```bash
|
|
140
52
|
npx antigravity-rtl-patcher@latest patch
|
|
141
53
|
```
|
|
142
54
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
---
|
|
146
|
-
|
|
147
|
-
## 💻 Supported Platforms
|
|
148
|
-
|
|
149
|
-
| Platform | Typical Install Locations |
|
|
150
|
-
|----------|---------------------------|
|
|
151
|
-
| **Linux** | `/opt/Antigravity`<br>`~/Downloads/Antigravity-x64`<br>`~/.local/share/antigravity` |
|
|
152
|
-
| **macOS** | `/Applications/Antigravity.app`<br>`~/Applications/Antigravity.app` |
|
|
153
|
-
| **Windows** | `%LOCALAPPDATA%\Programs\Antigravity`<br>`%PROGRAMFILES%\Antigravity` |
|
|
154
|
-
|
|
155
|
-
Custom paths are supported via `--path` option.
|
|
156
|
-
|
|
157
|
-
---
|
|
158
|
-
|
|
159
|
-
## ⌨️ Keyboard Shortcuts
|
|
160
|
-
|
|
161
|
-
- **Alt + R** - Toggle RTL support on/off
|
|
162
|
-
- **Shift + 2** - Type `@` symbol (when @ fix is enabled)
|
|
163
|
-
|
|
164
|
-
---
|
|
165
|
-
|
|
166
|
-
## 🎯 Configuration File
|
|
167
|
-
|
|
168
|
-
Settings are stored in `~/.antigravity-rtl-v3.json`:
|
|
169
|
-
|
|
170
|
-
```json
|
|
171
|
-
{
|
|
172
|
-
"faFont": "",
|
|
173
|
-
"enFont": "",
|
|
174
|
-
"codeFont": "",
|
|
175
|
-
"lineHeight": "1.6",
|
|
176
|
-
"fontSize": "16",
|
|
177
|
-
"rtlEnabled": true,
|
|
178
|
-
"forceRTL": false,
|
|
179
|
-
"fixAtSign": true
|
|
180
|
-
}
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
You can manually edit this file or use the UI panel.
|
|
184
|
-
|
|
185
|
-
---
|
|
186
|
-
|
|
187
|
-
## 🐛 Troubleshooting
|
|
188
|
-
|
|
189
|
-
### Patch not working?
|
|
190
|
-
1. Make sure you restarted Antigravity after patching
|
|
191
|
-
2. Check patch status: `agy-rtl status`
|
|
192
|
-
3. Try restoring and re-patching:
|
|
193
|
-
```bash
|
|
194
|
-
npx antigravity-rtl-patcher restore
|
|
195
|
-
npx antigravity-rtl-patcher@latest patch
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
### Widget not appearing?
|
|
199
|
-
1. Open DevTools (now enabled by default)
|
|
200
|
-
2. Check console for any RTL engine errors
|
|
201
|
-
3. Make sure RTL is enabled in the widget
|
|
202
|
-
|
|
203
|
-
### Permission denied?
|
|
204
|
-
- **Linux/macOS**: Use `sudo` for system-wide installations
|
|
205
|
-
- **Windows**: Run terminal as Administrator
|
|
206
|
-
|
|
207
|
-
---
|
|
208
|
-
|
|
209
|
-
## 🤝 Contributing
|
|
210
|
-
|
|
211
|
-
Issues and pull requests are welcome at [github.com/VaFa1726/antigravity-rtl-patcher](https://github.com/VaFa1726/antigravity-rtl-patcher).
|
|
212
|
-
|
|
213
|
-
---
|
|
214
|
-
|
|
215
|
-
## 📄 License
|
|
216
|
-
|
|
217
|
-
MIT © VaFa1726
|
|
218
|
-
|
|
219
|
-
---
|
|
220
|
-
|
|
221
|
-
## 🙏 Credits
|
|
55
|
+
## Supported Platforms
|
|
222
56
|
|
|
223
|
-
-
|
|
224
|
-
-
|
|
225
|
-
-
|
|
57
|
+
- Linux: `/opt/Antigravity`, `~/Downloads/Antigravity-x64`
|
|
58
|
+
- macOS: `/Applications/Antigravity.app`
|
|
59
|
+
- Windows: `%LOCALAPPDATA%\Programs\Antigravity`
|
|
226
60
|
|
|
227
|
-
|
|
61
|
+
Use `--path` option for custom locations.
|
|
228
62
|
|
|
229
|
-
##
|
|
63
|
+
## License
|
|
230
64
|
|
|
231
|
-
|
|
232
|
-
- [NPM Package](https://www.npmjs.com/package/antigravity-rtl-patcher)
|
|
233
|
-
- [Report Issues](https://github.com/VaFa1726/antigravity-rtl-patcher/issues)
|
|
65
|
+
MIT
|
package/package.json
CHANGED
package/payload/utils-inject.js
CHANGED
|
@@ -1,19 +1,5 @@
|
|
|
1
|
-
/* ═══════════════════════════════════════════════════════════════
|
|
2
|
-
* ANTIGRAVITY RTL PATCH v3.0
|
|
3
|
-
* Advanced RTL & Typography Control for Antigravity
|
|
4
|
-
*
|
|
5
|
-
* This code is injected into dist/utils.js at the window creation
|
|
6
|
-
* hook point to enable comprehensive RTL support with a rich UI.
|
|
7
|
-
* ═══════════════════════════════════════════════════════════════ */
|
|
8
|
-
|
|
9
|
-
// ─────────────────────────────────────────────────────────────────
|
|
10
|
-
// PATCH MARKER: DO NOT REMOVE
|
|
11
|
-
// ─────────────────────────────────────────────────────────────────
|
|
12
1
|
/* ANTIGRAVITY_RTL_PATCH_v3 */
|
|
13
2
|
|
|
14
|
-
// ─────────────────────────────────────────────────────────────────
|
|
15
|
-
// Hook into console-message for config persistence
|
|
16
|
-
// ─────────────────────────────────────────────────────────────────
|
|
17
3
|
win.webContents.on('console-message', (event, ...args) => {
|
|
18
4
|
let message = '';
|
|
19
5
|
if (args.length === 1 && typeof args[0] === 'object' && args[0] !== null) {
|
|
@@ -25,659 +11,181 @@ win.webContents.on('console-message', (event, ...args) => {
|
|
|
25
11
|
if (typeof message === 'string' && message.startsWith('RTL_CONFIG_SAVE:')) {
|
|
26
12
|
try {
|
|
27
13
|
const configData = message.substring(16);
|
|
28
|
-
const configPath = require('path').join(require('os').homedir(), '.antigravity-rtl
|
|
14
|
+
const configPath = require('path').join(require('os').homedir(), '.antigravity-rtl.json');
|
|
29
15
|
require('fs').writeFileSync(configPath, configData, 'utf8');
|
|
30
16
|
} catch (err) {
|
|
31
|
-
console.error('[RTL]
|
|
17
|
+
console.error('[RTL] Config save failed:', err);
|
|
32
18
|
}
|
|
33
19
|
}
|
|
34
20
|
});
|
|
35
21
|
|
|
36
|
-
// ─────────────────────────────────────────────────────────────────
|
|
37
|
-
// Original loadURL call - DO NOT MODIFY THIS LINE
|
|
38
|
-
// ─────────────────────────────────────────────────────────────────
|
|
39
22
|
void win.loadURL(url);
|
|
40
23
|
|
|
41
|
-
// ─────────────────────────────────────────────────────────────────
|
|
42
|
-
// RTL Engine Injection on DOM Ready
|
|
43
|
-
// ─────────────────────────────────────────────────────────────────
|
|
44
24
|
win.webContents.on('dom-ready', () => {
|
|
45
25
|
try {
|
|
46
|
-
|
|
47
|
-
const fontPath = require('path').join(__dirname, 'Vazirmatn-Variable.woff2');
|
|
48
|
-
const fontBase64 = require('fs').readFileSync(fontPath).toString('base64');
|
|
49
|
-
|
|
50
|
-
// Load persisted configuration
|
|
51
|
-
const defaultConfig = {
|
|
52
|
-
faFont: '',
|
|
53
|
-
enFont: '',
|
|
54
|
-
codeFont: '',
|
|
55
|
-
lineHeight: '1.6',
|
|
56
|
-
fontSize: '16',
|
|
57
|
-
rtlEnabled: true,
|
|
58
|
-
forceRTL: false,
|
|
59
|
-
fixAtSign: true
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
let userConfig = { ...defaultConfig };
|
|
26
|
+
let rtlConfig = { enabled: true };
|
|
63
27
|
try {
|
|
64
|
-
const configPath = require('path').join(require('os').homedir(), '.antigravity-rtl
|
|
28
|
+
const configPath = require('path').join(require('os').homedir(), '.antigravity-rtl.json');
|
|
65
29
|
if (require('fs').existsSync(configPath)) {
|
|
66
|
-
const
|
|
67
|
-
|
|
30
|
+
const cfg = JSON.parse(require('fs').readFileSync(configPath, 'utf8'));
|
|
31
|
+
rtlConfig = { ...rtlConfig, ...cfg };
|
|
68
32
|
}
|
|
69
|
-
} catch (err) {
|
|
70
|
-
console.warn('[RTL] Could not load config, using defaults:', err);
|
|
71
|
-
}
|
|
33
|
+
} catch (err) {}
|
|
72
34
|
|
|
73
|
-
// ═══════════════════════════════════════════════════════════
|
|
74
|
-
// INJECT THE COMPLETE RTL ENGINE INTO RENDERER
|
|
75
|
-
// ═══════════════════════════════════════════════════════════
|
|
76
35
|
win.webContents.executeJavaScript(`
|
|
77
|
-
(function
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
// Prevent double initialization
|
|
81
|
-
if (window.__ANTIGRAVITY_RTL_LOADED__) return;
|
|
82
|
-
window.__ANTIGRAVITY_RTL_LOADED__ = true;
|
|
83
|
-
|
|
84
|
-
console.log('[RTL Engine] Initializing v3.0...');
|
|
85
|
-
|
|
86
|
-
// ═══════════════════════════════════════════════════
|
|
87
|
-
// Configuration & State
|
|
88
|
-
// ═══════════════════════════════════════════════════
|
|
89
|
-
const FONT_BASE64 = '${fontBase64}';
|
|
90
|
-
const CONFIG = ${JSON.stringify(userConfig)};
|
|
36
|
+
(function initRTL() {
|
|
37
|
+
if (window.__RTL_LOADED__) return;
|
|
38
|
+
window.__RTL_LOADED__ = true;
|
|
91
39
|
|
|
92
|
-
let rtlEnabled =
|
|
93
|
-
let forceRTL = CONFIG.forceRTL;
|
|
94
|
-
let fixAtSign = CONFIG.fixAtSign;
|
|
40
|
+
let rtlEnabled = ${rtlConfig.enabled};
|
|
95
41
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
42
|
+
const CSS = \`
|
|
43
|
+
p, h1, h2, h3, h4, h5, h6, ul, ol, li, div, span {
|
|
44
|
+
unicode-bidi: plaintext;
|
|
45
|
+
text-align: start;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
[dir="rtl"] ul, [dir="rtl"] ol {
|
|
49
|
+
padding-left: 0 !important;
|
|
50
|
+
padding-right: 1.5rem !important;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
pre, code, pre *, code * {
|
|
54
|
+
unicode-bidi: isolate !important;
|
|
55
|
+
direction: ltr !important;
|
|
56
|
+
text-align: left !important;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
#rtl-toggle-btn {
|
|
60
|
+
position: fixed;
|
|
61
|
+
bottom: 20px;
|
|
62
|
+
right: 20px;
|
|
63
|
+
z-index: 999999;
|
|
64
|
+
width: 50px;
|
|
65
|
+
height: 50px;
|
|
66
|
+
border-radius: 50%;
|
|
67
|
+
background: rgba(60, 60, 60, 0.9);
|
|
68
|
+
border: 2px solid rgba(100, 100, 100, 0.5);
|
|
69
|
+
color: white;
|
|
70
|
+
cursor: pointer;
|
|
71
|
+
display: flex;
|
|
72
|
+
align-items: center;
|
|
73
|
+
justify-content: center;
|
|
74
|
+
font-size: 24px;
|
|
75
|
+
transition: all 0.3s;
|
|
76
|
+
box-shadow: 0 2px 10px rgba(0,0,0,0.3);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
#rtl-toggle-btn:hover {
|
|
80
|
+
background: rgba(80, 80, 80, 0.95);
|
|
81
|
+
transform: scale(1.1);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
#rtl-toggle-btn.active {
|
|
85
|
+
background: rgba(70, 130, 180, 0.9);
|
|
86
|
+
border-color: rgba(70, 130, 180, 0.8);
|
|
87
|
+
}
|
|
88
|
+
\`;
|
|
99
89
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
codeFont: document.getElementById('rtl-code-font')?.value.trim() || '',
|
|
105
|
-
lineHeight: document.getElementById('rtl-lh-slider')?.value || '1.6',
|
|
106
|
-
fontSize: document.getElementById('rtl-fs-slider')?.value || '16',
|
|
107
|
-
rtlEnabled: rtlEnabled,
|
|
108
|
-
forceRTL: forceRTL,
|
|
109
|
-
fixAtSign: fixAtSign
|
|
110
|
-
};
|
|
111
|
-
console.log('RTL_CONFIG_SAVE:' + JSON.stringify(config));
|
|
112
|
-
}
|
|
90
|
+
const styleEl = document.createElement('style');
|
|
91
|
+
styleEl.id = 'rtl-main-style';
|
|
92
|
+
styleEl.textContent = CSS;
|
|
93
|
+
document.head.appendChild(styleEl);
|
|
113
94
|
|
|
114
95
|
function detectRTL(text) {
|
|
115
96
|
if (!text || text.trim().length === 0) return false;
|
|
116
97
|
const cleaned = text.replace(/[\\u200B-\\u200F\\uFEFF]/g, '').trim();
|
|
117
98
|
if (cleaned.length === 0) return false;
|
|
118
99
|
|
|
119
|
-
// Check first meaningful character
|
|
120
100
|
const firstChar = cleaned.match(/[A-Za-z\\u0600-\\u06FF\\u0750-\\u077F\\u08A0-\\u08FF\\uFB50-\\uFDFF\\uFE70-\\uFEFF]/);
|
|
121
101
|
if (!firstChar) return false;
|
|
122
102
|
|
|
123
|
-
|
|
124
|
-
return isPersianArabic;
|
|
103
|
+
return /[\\u0600-\\u06FF\\u0750-\\u077F\\u08A0-\\u08FF\\uFB50-\\uFDFF\\uFE70-\\uFEFF]/.test(firstChar[0]);
|
|
125
104
|
}
|
|
126
105
|
|
|
127
|
-
// ═══════════════════════════════════════════════════
|
|
128
|
-
// Dynamic CSS Generator
|
|
129
|
-
// ═══════════════════════════════════════════════════
|
|
130
|
-
|
|
131
|
-
function generateCSS(faFont, enFont, codeFont, lh, fs) {
|
|
132
|
-
let faFontFamily = "'VazirmatnFallback'";
|
|
133
|
-
let faFontRule = '';
|
|
134
|
-
|
|
135
|
-
if (faFont) {
|
|
136
|
-
faFontFamily = "'CustomPersianFont', 'VazirmatnFallback'";
|
|
137
|
-
const baseName = faFont.replace(/[-\\s]?Regular$/i, '');
|
|
138
|
-
faFontRule = \`
|
|
139
|
-
@font-face {
|
|
140
|
-
font-family: 'CustomPersianFont';
|
|
141
|
-
src: local('\${faFont}'), local('\${baseName}');
|
|
142
|
-
font-weight: 400;
|
|
143
|
-
unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
|
|
144
|
-
}
|
|
145
|
-
@font-face {
|
|
146
|
-
font-family: 'CustomPersianFont';
|
|
147
|
-
src: local('\${baseName} Bold'), local('\${baseName}-Bold'), local('\${baseName}Bold');
|
|
148
|
-
font-weight: 700;
|
|
149
|
-
unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
|
|
150
|
-
}
|
|
151
|
-
\`;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const enFontStr = enFont ? \`'\${enFont}', ui-sans-serif, system-ui, sans-serif\` : 'ui-sans-serif, system-ui, sans-serif';
|
|
155
|
-
const codeFontStr = codeFont ? \`'\${codeFont}', ui-monospace, 'Courier New', monospace\` : 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace';
|
|
156
|
-
|
|
157
|
-
const forceRTLStyles = forceRTL ? \`
|
|
158
|
-
.prose > *:not(pre):not(code),
|
|
159
|
-
[data-testid="chat-message"] > *:not(pre):not(code),
|
|
160
|
-
.markdown-body > *:not(pre):not(code),
|
|
161
|
-
.leading-relaxed > *:not(pre):not(code),
|
|
162
|
-
[data-testid="user-input-step"],
|
|
163
|
-
[data-testid="user-input-step"] > *:not(pre):not(code),
|
|
164
|
-
div:has(> [role="radiogroup"]),
|
|
165
|
-
label[for^="ask-opt-"] {
|
|
166
|
-
direction: rtl !important;
|
|
167
|
-
text-align: right !important;
|
|
168
|
-
unicode-bidi: isolate !important;
|
|
169
|
-
}
|
|
170
|
-
\` : '';
|
|
171
|
-
|
|
172
|
-
return \`
|
|
173
|
-
\${faFontRule}
|
|
174
|
-
|
|
175
|
-
@font-face {
|
|
176
|
-
font-family: 'VazirmatnFallback';
|
|
177
|
-
src: url('data:font/woff2;base64,\${FONT_BASE64}') format('woff2');
|
|
178
|
-
font-weight: 100 900;
|
|
179
|
-
unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
:root, :host, html, body {
|
|
183
|
-
font-family: \${faFontFamily}, \${enFontStr}, "Apple Color Emoji", "Segoe UI Emoji" !important;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
.prose, [data-testid="chat-message"], .markdown-body,
|
|
187
|
-
.leading-relaxed, [contenteditable="true"], [contenteditable="true"] p {
|
|
188
|
-
font-size: \${fs}px !important;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
p, h1, h2, h3, h4, h5, h6, ul, ol {
|
|
192
|
-
unicode-bidi: plaintext;
|
|
193
|
-
text-align: start;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
.prose > *, [data-testid="chat-message"] > *, .markdown-body > * {
|
|
197
|
-
unicode-bidi: plaintext;
|
|
198
|
-
text-align: start;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
label[for^="ask-opt-"] {
|
|
202
|
-
unicode-bidi: plaintext;
|
|
203
|
-
text-align: start;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
label[for^="ask-opt-"][dir="rtl"] {
|
|
207
|
-
direction: rtl;
|
|
208
|
-
text-align: right;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
textarea[data-testid="ask-question-writein"] {
|
|
212
|
-
unicode-bidi: plaintext;
|
|
213
|
-
text-align: start;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
\${forceRTLStyles}
|
|
217
|
-
|
|
218
|
-
/* RTL List Padding */
|
|
219
|
-
ul:not(#_)[dir="rtl"], ol:not(#_)[dir="rtl"],
|
|
220
|
-
[dir="rtl"] ul:not(#_), [dir="rtl"] ol:not(#_) {
|
|
221
|
-
padding-left: 0 !important;
|
|
222
|
-
padding-right: 1.25rem !important;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
[dir="rtl"] ul:not(#_) ul:not(#_), [dir="rtl"] ul:not(#_) ol:not(#_),
|
|
226
|
-
[dir="rtl"] ol:not(#_) ul:not(#_), [dir="rtl"] ol:not(#_) ol:not(#_) {
|
|
227
|
-
padding-left: 0 !important;
|
|
228
|
-
padding-right: 2.5rem !important;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/* Keep thinking blocks LTR */
|
|
232
|
-
.cursor-edit.text-secondary-foreground,
|
|
233
|
-
.cursor-edit.text-secondary-foreground * {
|
|
234
|
-
direction: ltr !important;
|
|
235
|
-
text-align: left !important;
|
|
236
|
-
unicode-bidi: isolate !important;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/* Code blocks always LTR */
|
|
240
|
-
pre, code, pre *, code * {
|
|
241
|
-
unicode-bidi: isolate !important;
|
|
242
|
-
direction: ltr !important;
|
|
243
|
-
text-align: left !important;
|
|
244
|
-
font-family: \${codeFontStr} !important;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/* Line height control */
|
|
248
|
-
.leading-relaxed {
|
|
249
|
-
line-height: \${lh} !important;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
[contenteditable="true"], [contenteditable="true"] * {
|
|
253
|
-
unicode-bidi: isolate !important;
|
|
254
|
-
text-align: start !important;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/* Smart auto-direction */
|
|
258
|
-
[role="navigation"][aria-label="Sidebar"] *, .truncate {
|
|
259
|
-
unicode-bidi: plaintext !important;
|
|
260
|
-
text-align: start !important;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/* Apply line height to chat */
|
|
264
|
-
.prose p, .prose li, .markdown-body p,
|
|
265
|
-
[data-testid="chat-message"] p,
|
|
266
|
-
[data-testid="chat-message"] .leading-relaxed,
|
|
267
|
-
.leading-relaxed, [data-testid="user-input-step"],
|
|
268
|
-
[data-testid="user-input-step"] div,
|
|
269
|
-
[data-lexical-text="true"],
|
|
270
|
-
[contenteditable="true"], [contenteditable="true"] p,
|
|
271
|
-
label[for^="ask-opt-"] {
|
|
272
|
-
line-height: \${lh} !important;
|
|
273
|
-
}
|
|
274
|
-
\`;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// ═══════════════════════════════════════════════════
|
|
278
|
-
// Style Injection
|
|
279
|
-
// ═══════════════════════════════════════════════════
|
|
280
|
-
|
|
281
|
-
const mainStyleEl = document.createElement('style');
|
|
282
|
-
mainStyleEl.id = 'antigravity-rtl-main-style';
|
|
283
|
-
document.head.appendChild(mainStyleEl);
|
|
284
|
-
|
|
285
|
-
function updateCSS() {
|
|
286
|
-
const faFont = document.getElementById('rtl-fa-font')?.value.trim() || '';
|
|
287
|
-
const enFont = document.getElementById('rtl-en-font')?.value.trim() || '';
|
|
288
|
-
const codeFont = document.getElementById('rtl-code-font')?.value.trim() || '';
|
|
289
|
-
const lh = document.getElementById('rtl-lh-slider')?.value || CONFIG.lineHeight;
|
|
290
|
-
const fs = document.getElementById('rtl-fs-slider')?.value || CONFIG.fontSize;
|
|
291
|
-
|
|
292
|
-
mainStyleEl.textContent = generateCSS(faFont, enFont, codeFont, lh, fs);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// Initial CSS
|
|
296
|
-
updateCSS();
|
|
297
|
-
|
|
298
|
-
// ═══════════════════════════════════════════════════
|
|
299
|
-
// Direction Observer
|
|
300
|
-
// ═══════════════════════════════════════════════════
|
|
301
|
-
|
|
302
106
|
function updateDirections() {
|
|
303
107
|
if (!rtlEnabled) return;
|
|
304
108
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
const
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
if (el.getAttribute('dir') !== newDir) {
|
|
314
|
-
el.setAttribute('dir', newDir);
|
|
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);
|
|
315
117
|
}
|
|
316
118
|
} else {
|
|
317
119
|
if (el.hasAttribute('dir')) el.removeAttribute('dir');
|
|
318
120
|
}
|
|
319
121
|
});
|
|
320
122
|
|
|
321
|
-
|
|
322
|
-
document.querySelectorAll(\`
|
|
323
|
-
.prose > *,
|
|
324
|
-
[data-testid="chat-message"] > *,
|
|
325
|
-
.markdown-body > *,
|
|
326
|
-
.leading-relaxed > *,
|
|
327
|
-
[data-testid="user-input-step"],
|
|
328
|
-
[data-testid="user-input-step"] > *,
|
|
329
|
-
div:has(> [role="radiogroup"]),
|
|
330
|
-
label[for^="ask-opt-"]
|
|
331
|
-
\`).forEach(el => {
|
|
123
|
+
document.querySelectorAll('.prose > *, [data-testid="chat-message"] > *, .markdown-body > *, .leading-relaxed > *').forEach(el => {
|
|
332
124
|
if (el.tagName === 'PRE' || el.tagName === 'CODE') return;
|
|
333
125
|
|
|
334
126
|
const text = el.textContent.replace(/[\\u200B-\\u200F\\uFEFF]/g, '').trim();
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
dir = detectRTL(text) ? 'rtl' : 'ltr';
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
if (el.getAttribute('dir') !== dir) {
|
|
344
|
-
el.setAttribute('dir', dir);
|
|
127
|
+
if (text) {
|
|
128
|
+
const dir = detectRTL(text) ? 'rtl' : 'ltr';
|
|
129
|
+
if (el.getAttribute('dir') !== dir) {
|
|
130
|
+
el.setAttribute('dir', dir);
|
|
131
|
+
}
|
|
345
132
|
}
|
|
346
133
|
});
|
|
347
134
|
}
|
|
348
135
|
|
|
349
|
-
// Set up observers
|
|
350
136
|
document.body.addEventListener('input', updateDirections, { capture: true });
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
const mutationObserver = new MutationObserver(updateDirections);
|
|
354
|
-
mutationObserver.observe(document.body, { childList: true, subtree: true });
|
|
355
|
-
|
|
137
|
+
const observer = new MutationObserver(updateDirections);
|
|
138
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
356
139
|
setInterval(updateDirections, 500);
|
|
357
140
|
|
|
358
|
-
// ═══════════════════════════════════════════════════
|
|
359
|
-
// Keyboard Shortcuts & Fixes
|
|
360
|
-
// ═══════════════════════════════════════════════════
|
|
361
|
-
|
|
362
141
|
document.addEventListener('keydown', (e) => {
|
|
363
|
-
// Alt + R to toggle RTL
|
|
364
142
|
if (e.altKey && e.code === 'KeyR') {
|
|
365
143
|
e.preventDefault();
|
|
366
144
|
toggleRTL();
|
|
367
145
|
}
|
|
368
|
-
|
|
369
|
-
// Fix @ sign on Persian keyboard
|
|
370
|
-
if (fixAtSign && e.code === 'Digit2' && e.shiftKey) {
|
|
371
|
-
if (e.key === '٬' || e.key === '،') {
|
|
372
|
-
e.preventDefault();
|
|
373
|
-
document.execCommand('insertText', false, '@');
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
146
|
}, { capture: true });
|
|
377
147
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
widgetStyles.id = 'rtl-widget-styles';
|
|
384
|
-
widgetStyles.textContent = \`
|
|
385
|
-
.rtl-tooltip {
|
|
386
|
-
visibility: hidden;
|
|
387
|
-
opacity: 0;
|
|
388
|
-
transition: opacity 0.2s;
|
|
389
|
-
pointer-events: none;
|
|
390
|
-
}
|
|
391
|
-
.rtl-info-icon:hover .rtl-tooltip {
|
|
392
|
-
visibility: visible;
|
|
393
|
-
opacity: 1;
|
|
394
|
-
}
|
|
395
|
-
.rtl-widget-panel {
|
|
396
|
-
transform: scale(0);
|
|
397
|
-
opacity: 0;
|
|
398
|
-
pointer-events: none;
|
|
399
|
-
transition: all 0.3s;
|
|
400
|
-
transform-origin: bottom right;
|
|
401
|
-
}
|
|
402
|
-
.rtl-widget-container:hover .rtl-widget-trigger {
|
|
403
|
-
opacity: 0 !important;
|
|
404
|
-
transform: scale(0.5) !important;
|
|
405
|
-
pointer-events: none !important;
|
|
406
|
-
}
|
|
407
|
-
.rtl-widget-container:hover .rtl-widget-panel {
|
|
408
|
-
transform: scale(1) !important;
|
|
409
|
-
opacity: 1 !important;
|
|
410
|
-
pointer-events: auto !important;
|
|
411
|
-
}
|
|
412
|
-
:root {
|
|
413
|
-
--rtl-bg: #ffffff;
|
|
414
|
-
--rtl-text: #111827;
|
|
415
|
-
--rtl-border: #e5e7eb;
|
|
416
|
-
--rtl-input-bg: #f3f4f6;
|
|
417
|
-
}
|
|
418
|
-
:root.dark, .dark {
|
|
419
|
-
--rtl-bg: #1e293b;
|
|
420
|
-
--rtl-text: #f3f4f6;
|
|
421
|
-
--rtl-border: #334155;
|
|
422
|
-
--rtl-input-bg: #334155;
|
|
423
|
-
}
|
|
424
|
-
@media (prefers-color-scheme: dark) {
|
|
425
|
-
:root:not(.light) {
|
|
426
|
-
--rtl-bg: #1e293b;
|
|
427
|
-
--rtl-text: #f3f4f6;
|
|
428
|
-
--rtl-border: #334155;
|
|
429
|
-
--rtl-input-bg: #334155;
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
.rtl-theme-panel {
|
|
433
|
-
background-color: var(--rtl-bg) !important;
|
|
434
|
-
color: var(--rtl-text) !important;
|
|
435
|
-
border: 1px solid var(--rtl-border) !important;
|
|
436
|
-
}
|
|
437
|
-
.rtl-theme-input {
|
|
438
|
-
background-color: var(--rtl-input-bg) !important;
|
|
439
|
-
color: var(--rtl-text) !important;
|
|
440
|
-
border: 1px solid var(--rtl-border) !important;
|
|
441
|
-
}
|
|
442
|
-
.w-11 { width: 44px !important; }
|
|
443
|
-
.h-6 { height: 24px !important; }
|
|
444
|
-
.w-4 { width: 16px !important; }
|
|
445
|
-
.h-4 { height: 16px !important; }
|
|
446
|
-
.translate-x-6 { transform: translateX(24px) !important; }
|
|
447
|
-
.translate-x-1 { transform: translateX(4px) !important; }
|
|
448
|
-
.bg-accent { background-color: #4f46e5 !important; }
|
|
449
|
-
.rtl-toggle-reset {
|
|
450
|
-
padding: 0 !important;
|
|
451
|
-
border: none !important;
|
|
452
|
-
box-sizing: border-box !important;
|
|
453
|
-
min-width: 44px !important;
|
|
454
|
-
outline: none !important;
|
|
455
|
-
display: inline-flex !important;
|
|
456
|
-
align-items: center !important;
|
|
457
|
-
}
|
|
458
|
-
.rtl-gh-link {
|
|
459
|
-
transition: all 0.1s !important;
|
|
460
|
-
}
|
|
461
|
-
.rtl-gh-link:hover {
|
|
462
|
-
color: #eab308 !important;
|
|
463
|
-
opacity: 1 !important;
|
|
464
|
-
}
|
|
465
|
-
\`;
|
|
466
|
-
document.head.appendChild(widgetStyles);
|
|
467
|
-
|
|
468
|
-
// ═══════════════════════════════════════════════════
|
|
469
|
-
// Widget UI HTML
|
|
470
|
-
// ═══════════════════════════════════════════════════
|
|
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)';
|
|
471
153
|
|
|
472
|
-
|
|
473
|
-
<div class="rtl-widget-container group fixed bottom-4 right-4 w-10 h-10" style="direction: ltr; z-index: 999999;">
|
|
474
|
-
<div class="rtl-widget-trigger relative w-10 h-10 flex items-center justify-center rounded-full bg-secondary text-secondary-foreground hover:text-foreground cursor-pointer opacity-80 transition-all duration-300">
|
|
475
|
-
<svg height="20" width="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
|
|
476
|
-
</div>
|
|
477
|
-
<div class="rtl-widget-panel rtl-theme-panel absolute bottom-0 right-0 flex flex-col p-px rounded-2xl text-sm w-60">
|
|
478
|
-
<div class="flex flex-col gap-2 p-3 rounded-[15px]">
|
|
479
|
-
<div class="text-center px-1 pb-2 mb-1 border-b border-border border-opacity-50">
|
|
480
|
-
<span class="text-base font-semibold">Antigravity Smart RTL</span>
|
|
481
|
-
</div>
|
|
482
|
-
<div class="flex items-center justify-between gap-4 px-1">
|
|
483
|
-
<div class="flex items-center">
|
|
484
|
-
<span id="rtl-status-text" class="font-medium text-xs opacity-80">\${rtlEnabled ? 'Enabled' : 'Disabled'}</span>
|
|
485
|
-
<div class="relative flex items-center rtl-info-icon ml-1">
|
|
486
|
-
<span class="cursor-pointer inline-flex items-center text-muted-foreground hover:text-foreground">
|
|
487
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 -960 960 960" fill="currentColor" class="w-3.5 h-3.5"><path d="M450-290h60V-520H450v230Zm52.92-307.75q9.38-9.29 9.38-23.02t-9.29-23.02T480-653.07t-23.02,9.29t-9.29,23.02t9.38,23.02T480-588.46t22.92-9.29ZM480.07-100q-78.84,0-148.2-29.92T211.18-211.13T129.93-331.76T100-479.93t29.92-148.2t81.21-120.68t120.63-81.25T479.93-860t148.2,29.92t120.68,81.21t81.25,120.63T860-480.07t-29.92,148.2T748.87-211.18T628.24-129.93T480.07-100ZM480-160q134,0 227-93t93-227T707-707T480-800T253-707T160-480t93,227t227,93Zm0-320Z"/></svg>
|
|
488
|
-
</span>
|
|
489
|
-
<div class="rtl-tooltip absolute bottom-full left-1/2 -translate-x-1/2 mb-2 w-32 p-1.5 rounded shadow-md z-50 text-center bg-muted border border-border text-foreground text-[11px]">
|
|
490
|
-
Shortcut: Alt + R
|
|
491
|
-
<div class="absolute top-full left-1/2 -translate-x-1/2 w-0 h-0" style="border-left: 6px solid transparent; border-right: 6px solid transparent; border-top: 6px solid var(--border);"></div>
|
|
492
|
-
</div>
|
|
493
|
-
</div>
|
|
494
|
-
</div>
|
|
495
|
-
<button id="rtl-main-toggle" type="button" class="rtl-toggle-reset relative rounded-full transition-colors h-6 w-11 \${rtlEnabled ? 'bg-accent' : 'bg-gray-400 bg-opacity-40'} cursor-pointer">
|
|
496
|
-
<span class="inline-block rounded-full bg-white transition-transform shadow-sm h-4 w-4" style="transform: translateX(\${rtlEnabled ? '24px' : '4px'});"></span>
|
|
497
|
-
</button>
|
|
498
|
-
</div>
|
|
499
|
-
<div id="rtl-settings-area" class="flex flex-col gap-2 transition-all \${rtlEnabled ? '' : 'opacity-40 pointer-events-none'}">
|
|
500
|
-
<div class="flex items-center justify-between gap-2 px-1 mt-1">
|
|
501
|
-
<span class="font-medium text-xs opacity-80">Force RTL</span>
|
|
502
|
-
<button id="rtl-force-toggle" type="button" class="rtl-toggle-reset relative rounded-full transition-colors h-6 w-11 \${forceRTL ? 'bg-accent' : 'bg-gray-400 bg-opacity-40'} cursor-pointer">
|
|
503
|
-
<span class="inline-block rounded-full bg-white transition-transform shadow-sm h-4 w-4" style="transform: translateX(\${forceRTL ? '24px' : '4px'});"></span>
|
|
504
|
-
</button>
|
|
505
|
-
</div>
|
|
506
|
-
<div class="h-px bg-border border-opacity-30 w-full my-1"></div>
|
|
507
|
-
<div class="flex items-center justify-between gap-2 px-1">
|
|
508
|
-
<span class="font-medium text-xs opacity-80">FA/AR Font</span>
|
|
509
|
-
<input id="rtl-fa-font" type="text" placeholder="Vazirmatn" value="\${CONFIG.faFont}" class="rtl-theme-input text-[11px] px-2 py-1 rounded-md w-28 focus:outline-none">
|
|
510
|
-
</div>
|
|
511
|
-
<div class="flex items-center justify-between gap-2 px-1 mt-1">
|
|
512
|
-
<span class="font-medium text-xs opacity-80">EN Font</span>
|
|
513
|
-
<input id="rtl-en-font" type="text" placeholder="System" value="\${CONFIG.enFont}" class="rtl-theme-input text-[11px] px-2 py-1 rounded-md w-28 focus:outline-none">
|
|
514
|
-
</div>
|
|
515
|
-
<div class="flex items-center justify-between gap-2 px-1 mt-1">
|
|
516
|
-
<span class="font-medium text-xs opacity-80">Code Font</span>
|
|
517
|
-
<input id="rtl-code-font" type="text" placeholder="System" value="\${CONFIG.codeFont}" class="rtl-theme-input text-[11px] px-2 py-1 rounded-md w-28 focus:outline-none">
|
|
518
|
-
</div>
|
|
519
|
-
<div class="flex items-center justify-between gap-2 px-1 mt-1">
|
|
520
|
-
<span class="font-medium text-xs opacity-80">Line Height</span>
|
|
521
|
-
<div class="flex items-center gap-2">
|
|
522
|
-
<input id="rtl-lh-slider" type="range" min="1.2" max="2.5" step="0.1" value="\${CONFIG.lineHeight}" class="h-1 w-20 cursor-pointer">
|
|
523
|
-
<button id="rtl-lh-reset" type="button" class="opacity-50 hover:opacity-100 transition-opacity cursor-pointer" title="Reset">
|
|
524
|
-
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
|
|
525
|
-
</button>
|
|
526
|
-
</div>
|
|
527
|
-
</div>
|
|
528
|
-
<div class="flex items-center justify-between gap-2 px-1 mt-1 mb-1">
|
|
529
|
-
<span class="font-medium text-xs opacity-80">Font Size</span>
|
|
530
|
-
<div class="flex items-center gap-2">
|
|
531
|
-
<input id="rtl-fs-slider" type="range" min="11" max="22" step="1" value="\${CONFIG.fontSize}" class="h-1 w-20 cursor-pointer">
|
|
532
|
-
<button id="rtl-fs-reset" type="button" class="opacity-50 hover:opacity-100 transition-opacity cursor-pointer" title="Reset">
|
|
533
|
-
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
|
|
534
|
-
</button>
|
|
535
|
-
</div>
|
|
536
|
-
</div>
|
|
537
|
-
<div class="h-px bg-border border-opacity-30 w-full my-1"></div>
|
|
538
|
-
<div class="flex items-center justify-between gap-2 px-1 mb-1">
|
|
539
|
-
<span class="font-medium text-xs opacity-80">Type @ with Shift+2</span>
|
|
540
|
-
<button id="rtl-at-toggle" type="button" class="rtl-toggle-reset relative rounded-full transition-colors h-6 w-11 \${fixAtSign ? 'bg-accent' : 'bg-gray-400 bg-opacity-40'} cursor-pointer">
|
|
541
|
-
<span class="inline-block rounded-full bg-white transition-transform shadow-sm h-4 w-4" style="transform: translateX(\${fixAtSign ? '24px' : '4px'});"></span>
|
|
542
|
-
</button>
|
|
543
|
-
</div>
|
|
544
|
-
</div>
|
|
545
|
-
<div class="h-px bg-border w-full"></div>
|
|
546
|
-
<a href="https://github.com/VaFa1726/antigravity-rtl-patcher" target="_blank" class="rtl-gh-link flex items-center justify-center gap-2 text-xs font-semibold opacity-70 no-underline pt-1 pb-0.5">
|
|
547
|
-
<svg height="14" width="14" viewBox="0 0 16 16" fill="currentColor"><path d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z"/></svg>
|
|
548
|
-
Star on GitHub
|
|
549
|
-
</a>
|
|
550
|
-
</div>
|
|
551
|
-
</div>
|
|
552
|
-
</div>
|
|
553
|
-
\`;
|
|
554
|
-
|
|
555
|
-
// Insert widget
|
|
556
|
-
const widgetWrapper = document.createElement('div');
|
|
557
|
-
widgetWrapper.innerHTML = widgetHTML;
|
|
558
|
-
document.body.appendChild(widgetWrapper.firstElementChild);
|
|
559
|
-
|
|
560
|
-
// ═══════════════════════════════════════════════════
|
|
561
|
-
// Event Handlers
|
|
562
|
-
// ═══════════════════════════════════════════════════
|
|
154
|
+
btn.addEventListener('click', toggleRTL);
|
|
563
155
|
|
|
564
156
|
function toggleRTL() {
|
|
565
157
|
rtlEnabled = !rtlEnabled;
|
|
566
|
-
const statusText = document.getElementById('rtl-status-text');
|
|
567
|
-
const mainToggle = document.getElementById('rtl-main-toggle');
|
|
568
|
-
const settingsArea = document.getElementById('rtl-settings-area');
|
|
569
|
-
|
|
570
|
-
statusText.textContent = rtlEnabled ? 'Enabled' : 'Disabled';
|
|
571
158
|
|
|
572
159
|
if (rtlEnabled) {
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
settingsArea.classList.remove('opacity-40', 'pointer-events-none');
|
|
577
|
-
if (!document.getElementById('antigravity-rtl-main-style')) {
|
|
578
|
-
document.head.appendChild(mainStyleEl);
|
|
160
|
+
btn.classList.add('active');
|
|
161
|
+
if (!document.getElementById('rtl-main-style')) {
|
|
162
|
+
document.head.appendChild(styleEl);
|
|
579
163
|
}
|
|
580
|
-
updateCSS();
|
|
581
164
|
updateDirections();
|
|
582
165
|
} else {
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
settingsArea.classList.add('opacity-40', 'pointer-events-none');
|
|
587
|
-
if (mainStyleEl.parentNode) {
|
|
588
|
-
mainStyleEl.parentNode.removeChild(mainStyleEl);
|
|
166
|
+
btn.classList.remove('active');
|
|
167
|
+
if (styleEl.parentNode) {
|
|
168
|
+
styleEl.parentNode.removeChild(styleEl);
|
|
589
169
|
}
|
|
590
170
|
document.querySelectorAll('[dir]').forEach(el => {
|
|
591
|
-
if (!el.closest('
|
|
171
|
+
if (!el.closest('#rtl-toggle-btn')) {
|
|
592
172
|
el.removeAttribute('dir');
|
|
593
173
|
}
|
|
594
174
|
});
|
|
595
175
|
}
|
|
596
176
|
|
|
597
|
-
|
|
177
|
+
console.log('RTL_CONFIG_SAVE:' + JSON.stringify({ enabled: rtlEnabled }));
|
|
598
178
|
}
|
|
599
179
|
|
|
600
|
-
document.
|
|
601
|
-
|
|
602
|
-
document.getElementById('rtl-force-toggle').addEventListener('click', () => {
|
|
603
|
-
forceRTL = !forceRTL;
|
|
604
|
-
const btn = document.getElementById('rtl-force-toggle');
|
|
605
|
-
if (forceRTL) {
|
|
606
|
-
btn.classList.add('bg-accent');
|
|
607
|
-
btn.classList.remove('bg-gray-400', 'bg-opacity-40');
|
|
608
|
-
btn.querySelector('span').style.transform = 'translateX(24px)';
|
|
609
|
-
} else {
|
|
610
|
-
btn.classList.remove('bg-accent');
|
|
611
|
-
btn.classList.add('bg-gray-400', 'bg-opacity-40');
|
|
612
|
-
btn.querySelector('span').style.transform = 'translateX(4px)';
|
|
613
|
-
}
|
|
614
|
-
updateCSS();
|
|
615
|
-
updateDirections();
|
|
616
|
-
saveConfig();
|
|
617
|
-
});
|
|
618
|
-
|
|
619
|
-
document.getElementById('rtl-at-toggle').addEventListener('click', () => {
|
|
620
|
-
fixAtSign = !fixAtSign;
|
|
621
|
-
const btn = document.getElementById('rtl-at-toggle');
|
|
622
|
-
if (fixAtSign) {
|
|
623
|
-
btn.classList.add('bg-accent');
|
|
624
|
-
btn.classList.remove('bg-gray-400', 'bg-opacity-40');
|
|
625
|
-
btn.querySelector('span').style.transform = 'translateX(24px)';
|
|
626
|
-
} else {
|
|
627
|
-
btn.classList.remove('bg-accent');
|
|
628
|
-
btn.classList.add('bg-gray-400', 'bg-opacity-40');
|
|
629
|
-
btn.querySelector('span').style.transform = 'translateX(4px)';
|
|
630
|
-
}
|
|
631
|
-
saveConfig();
|
|
632
|
-
});
|
|
633
|
-
|
|
634
|
-
// Font inputs
|
|
635
|
-
['rtl-fa-font', 'rtl-en-font', 'rtl-code-font'].forEach(id => {
|
|
636
|
-
document.getElementById(id).addEventListener('input', () => {
|
|
637
|
-
updateCSS();
|
|
638
|
-
saveConfig();
|
|
639
|
-
});
|
|
640
|
-
});
|
|
641
|
-
|
|
642
|
-
// Sliders
|
|
643
|
-
document.getElementById('rtl-lh-slider').addEventListener('input', () => {
|
|
644
|
-
updateCSS();
|
|
645
|
-
saveConfig();
|
|
646
|
-
});
|
|
647
|
-
|
|
648
|
-
document.getElementById('rtl-fs-slider').addEventListener('input', () => {
|
|
649
|
-
updateCSS();
|
|
650
|
-
saveConfig();
|
|
651
|
-
});
|
|
652
|
-
|
|
653
|
-
// Reset buttons
|
|
654
|
-
document.getElementById('rtl-lh-reset').addEventListener('click', () => {
|
|
655
|
-
document.getElementById('rtl-lh-slider').value = '1.6';
|
|
656
|
-
updateCSS();
|
|
657
|
-
saveConfig();
|
|
658
|
-
});
|
|
659
|
-
|
|
660
|
-
document.getElementById('rtl-fs-reset').addEventListener('click', () => {
|
|
661
|
-
document.getElementById('rtl-fs-slider').value = '16';
|
|
662
|
-
updateCSS();
|
|
663
|
-
saveConfig();
|
|
664
|
-
});
|
|
665
|
-
|
|
666
|
-
// ═══════════════════════════════════════════════════
|
|
667
|
-
// Initialization Complete
|
|
668
|
-
// ═══════════════════════════════════════════════════
|
|
180
|
+
document.body.appendChild(btn);
|
|
669
181
|
|
|
670
182
|
if (rtlEnabled) {
|
|
671
183
|
updateDirections();
|
|
672
184
|
}
|
|
673
|
-
|
|
674
|
-
console.log('[RTL Engine] Initialization complete ✓');
|
|
675
185
|
})();
|
|
676
|
-
`).catch(err =>
|
|
677
|
-
console.error('[RTL] Failed to inject engine:', err);
|
|
678
|
-
});
|
|
186
|
+
`).catch(err => console.error('[RTL] Injection failed:', err));
|
|
679
187
|
|
|
680
188
|
} catch (error) {
|
|
681
|
-
console.error('[RTL]
|
|
189
|
+
console.error('[RTL] Init error:', error);
|
|
682
190
|
}
|
|
683
191
|
});
|
package/src/patcher.js
CHANGED