antigravity-rtl-patcher 2.3.4 → 3.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/CHANGELOG.md ADDED
@@ -0,0 +1,121 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [3.0.0] - 2024-09-06
6
+
7
+ ### 🎉 Major Rewrite - Utils.js Injection Approach
8
+
9
+ This is a **breaking change** that completely rewrites the injection strategy for better control and features.
10
+
11
+ ### ✨ Added
12
+
13
+ - **Advanced UI Panel** - Rich hover-activated widget with comprehensive customization
14
+ - **Custom Font Support** - Set separate fonts for Persian/Arabic, English, and code
15
+ - **Typography Controls** - Real-time line height (1.2-2.5) and font size (11-22px) adjustment
16
+ - **Persistent Configuration** - Settings saved to `~/.antigravity-rtl-v3.json`
17
+ - **Force RTL Mode** - Override auto-detection for consistent RTL layout
18
+ - **Enhanced Keyboard Shortcuts** - `Alt + R` to toggle RTL
19
+ - **@ Sign Fix** - Type `@` with `Shift+2` on Persian keyboard
20
+ - **DevTools Enabled** - Automatically enable DevTools for debugging
21
+ - **Colorful CLI Banner** - Beautiful gradient ASCII art banner
22
+ - **Update Command** - `agy-rtl update` to check for new versions
23
+
24
+ ### 🔧 Changed
25
+
26
+ - **Injection Point**: Changed from `preload.js` to `dist/utils.js` for better lifecycle control
27
+ - **Config Storage**: Moved from localStorage to filesystem (`~/.antigravity-rtl-v3.json`)
28
+ - **Detection Algorithm**: Improved RTL text detection with smarter first-character analysis
29
+ - **UI Architecture**: Complete redesign with Tailwind-inspired styling
30
+ - **Dependencies**: Added `figlet`, `picocolors`, and `prompts` for better CLI experience
31
+
32
+ ### 🗑️ Removed
33
+
34
+ - Old `preload-inject.js` payload (replaced with `utils-inject.js`)
35
+ - localStorage-based configuration (replaced with file-based config)
36
+
37
+ ### 🐛 Fixed
38
+
39
+ - Better handling of mixed RTL/LTR content
40
+ - Improved code block preservation in RTL contexts
41
+ - More reliable font loading mechanism
42
+ - Enhanced list padding in RTL mode
43
+
44
+ ### 📚 Documentation
45
+
46
+ - Completely rewritten README with v3.0 features
47
+ - Added troubleshooting section
48
+ - Added keyboard shortcuts reference
49
+ - Added configuration file documentation
50
+
51
+ ---
52
+
53
+ ## [2.3.4] - 2024-09-06
54
+
55
+ ### ✨ Added
56
+
57
+ - Auto-update checker before patching
58
+ - `update` command to manually check for updates
59
+ - Update notification system
60
+
61
+ ### 📚 Documentation
62
+
63
+ - Added update instructions to README
64
+ - Emphasized `@latest` usage in documentation
65
+
66
+ ---
67
+
68
+ ## [2.3.3] - 2024-09-06
69
+
70
+ ### 🐛 Fixed
71
+
72
+ - Improved RTL text detection logic
73
+ - Better layout rendering for mixed content
74
+
75
+ ---
76
+
77
+ ## [2.3.1] - 2024-09-06
78
+
79
+ ### 🐛 Fixed
80
+
81
+ - Bug fixes for layout issues
82
+ - Added IDE detection to skip patching IDE versions
83
+
84
+ ---
85
+
86
+ ## Earlier Versions
87
+
88
+ See [GitHub Releases](https://github.com/VaFa1726/antigravity-rtl-patcher/releases) for details on versions before 2.3.1.
89
+
90
+ ---
91
+
92
+ ## Migration Guide: v2.x → v3.0
93
+
94
+ ### What Changed
95
+
96
+ 1. **Configuration Location**: Your old settings in localStorage will not carry over. You'll need to reconfigure the RTL settings using the new UI panel.
97
+
98
+ 2. **UI Location**: The old status icon is replaced with a hover-activated globe icon in the bottom-right corner.
99
+
100
+ 3. **New Features**: Take advantage of custom fonts, typography controls, and Force RTL mode.
101
+
102
+ ### How to Upgrade
103
+
104
+ ```bash
105
+ # Restore old version
106
+ npx antigravity-rtl-patcher restore
107
+
108
+ # Install new version
109
+ npx antigravity-rtl-patcher@latest patch
110
+
111
+ # Restart Antigravity
112
+ ```
113
+
114
+ Your old backup will work fine. The new patch is completely independent.
115
+
116
+ ---
117
+
118
+ [3.0.0]: https://github.com/VaFa1726/antigravity-rtl-patcher/releases/tag/v3.0.0
119
+ [2.3.4]: https://github.com/VaFa1726/antigravity-rtl-patcher/releases/tag/v2.3.4
120
+ [2.3.3]: https://github.com/VaFa1726/antigravity-rtl-patcher/releases/tag/v2.3.3
121
+ [2.3.1]: https://github.com/VaFa1726/antigravity-rtl-patcher/releases/tag/v2.3.1
package/README.md CHANGED
@@ -1,22 +1,17 @@
1
1
  # Antigravity RTL Patcher
2
2
 
3
- Smart RTL and Persian/Arabic typography support for the [Antigravity](https://antigravity.dev) desktop app. Patches the Electron runtime to detect right-to-left text and apply proper styling automatically.
3
+ RTL and Persian/Arabic text support for [Antigravity](https://antigravity.dev) desktop app.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/antigravity-rtl-patcher)](https://www.npmjs.com/package/antigravity-rtl-patcher)
6
6
  [![npm downloads](https://img.shields.io/npm/dt/antigravity-rtl-patcher)](https://www.npmjs.com/package/antigravity-rtl-patcher)
7
- [![license](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
8
7
 
9
- ---
10
-
11
- ## ⚡ Quick Install
12
-
13
- Always use `@latest` to ensure you get the newest version:
8
+ ## Install
14
9
 
15
10
  ```bash
16
11
  npx antigravity-rtl-patcher@latest patch
17
12
  ```
18
13
 
19
- If Antigravity is installed in a system directory, use `sudo`:
14
+ Use `sudo` if Antigravity is in a system directory:
20
15
 
21
16
  ```bash
22
17
  sudo npx antigravity-rtl-patcher@latest patch
@@ -24,79 +19,47 @@ sudo npx antigravity-rtl-patcher@latest patch
24
19
 
25
20
  Restart Antigravity after patching.
26
21
 
27
- ## 🔄 Update to Latest Version
22
+ ## Usage
28
23
 
29
- To ensure you're always using the latest version, run:
24
+ After patching, a toggle button appears in the bottom-right corner. Click it to enable/disable RTL support.
30
25
 
31
- ```bash
32
- npx antigravity-rtl-patcher@latest patch
33
- ```
26
+ Keyboard shortcut: `Alt + R`
34
27
 
35
- Or check for updates manually:
36
-
37
- ```bash
38
- npx antigravity-rtl-patcher@latest update
39
- ```
40
-
41
- The patcher will automatically notify you when a new version is available.
42
-
43
- ## 🗑️ Uninstall
28
+ ## Uninstall
44
29
 
45
30
  ```bash
46
31
  npx antigravity-rtl-patcher restore
47
32
  ```
48
33
 
49
- This restores the original `app.asar` from the backup created during patching.
50
-
51
- ## 📋 Commands
34
+ ## Commands
52
35
 
53
36
  | Command | Description |
54
- |---|---|
37
+ |---------|-------------|
55
38
  | `agy-rtl patch` | Apply RTL patch |
56
- | `agy-rtl restore` | Remove patch, restore original |
57
- | `agy-rtl status` | Show current patch status |
39
+ | `agy-rtl restore` | Remove patch |
40
+ | `agy-rtl status` | Show patch status |
58
41
  | `agy-rtl update` | Check for updates |
59
- | `agy-rtl patch --path /custom/path` | Patch a custom installation |
60
- | `agy-rtl patch --skip-update-check` | Skip update check during patching |
61
-
62
- ## 🔧 How it works
63
-
64
- Antigravity is an Electron app. The patcher extracts `app.asar`, appends an RTL engine to the preload script, and repacks the archive. The engine uses a `MutationObserver` to detect Persian, Arabic, and Hebrew text in real-time and applies `direction: rtl` where needed.
65
42
 
66
- After patching, an RTL icon appears at the bottom of the Antigravity window. Click it to open a settings panel where you can enable or disable RTL support. The setting persists across restarts via `localStorage`.
43
+ ## How It Works
67
44
 
68
- ### What the engine does
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.
69
46
 
70
- - Detects RTL text using Unicode range analysis with ratio-based scoring
71
- - Applies directional styling only to elements that contain RTL text
72
- - Injects the Vazirmatn font for improved Persian/Arabic readability
73
- - Preserves LTR direction for code blocks inside RTL text
74
- - Provides a toggle UI to enable/disable at any time
47
+ ## After Antigravity Updates
75
48
 
76
- ## 🔄 After Antigravity updates
77
-
78
- Updates may overwrite the patch. Run the patch command again:
49
+ Run the patch command again after updating Antigravity:
79
50
 
80
51
  ```bash
81
52
  npx antigravity-rtl-patcher@latest patch
82
53
  ```
83
54
 
84
- **Pro tip:** Always use `@latest` flag to ensure you're patching with the newest version of the patcher.
85
-
86
- ## 💻 Supported platforms
87
-
88
- | Platform | Typical install locations |
89
- |---|---|
90
- | Linux | `/opt/antigravity`, `~/Downloads/Antigravity-x64` |
91
- | macOS | `/Applications/Antigravity.app` |
92
- | Windows | `%LOCALAPPDATA%\Programs\Antigravity` |
93
-
94
- Custom paths are supported via `--path`.
55
+ ## Supported Platforms
95
56
 
96
- ## 🤝 Contributing
57
+ - Linux: `/opt/Antigravity`, `~/Downloads/Antigravity-x64`
58
+ - macOS: `/Applications/Antigravity.app`
59
+ - Windows: `%LOCALAPPDATA%\Programs\Antigravity`
97
60
 
98
- Issues and pull requests are welcome at [github.com/VaFa1726/antigravity-rtl-patcher](https://github.com/VaFa1726/antigravity-rtl-patcher).
61
+ Use `--path` option for custom locations.
99
62
 
100
- ## 📄 License
63
+ ## License
101
64
 
102
65
  MIT
package/bin/cli.js CHANGED
@@ -2,43 +2,105 @@
2
2
 
3
3
  const { program } = require('commander');
4
4
  const chalk = require('chalk');
5
+ const figlet = require('figlet');
5
6
  const { patch, restore, status } = require('../src/patcher');
6
7
  const { checkForUpdates, showUpdateInstructions, currentVersion } = require('../src/version-checker');
7
8
 
8
- const BANNER = `
9
- ${chalk.cyan('Antigravity Smart RTL Patcher')} ${chalk.gray('v' + currentVersion)}
10
- `;
9
+ /**
10
+ * Display colorful banner with gradient effect
11
+ */
12
+ function showBanner() {
13
+ try {
14
+ const bannerText = figlet.textSync('Antigravity RTL', {
15
+ font: 'Standard',
16
+ horizontalLayout: 'default',
17
+ verticalLayout: 'default'
18
+ });
11
19
 
20
+ // Gradient colors
21
+ const colors = [
22
+ { r: 51, g: 135, b: 255 }, // Blue
23
+ { r: 242, g: 80, b: 65 }, // Red
24
+ { r: 223, g: 172, b: 42 }, // Yellow
25
+ { r: 145, g: 196, b: 91 } // Green
26
+ ];
27
+
28
+ const lines = bannerText.split('\n');
29
+ console.log('');
30
+
31
+ lines.forEach((line, lineIndex) => {
32
+ if (!line.trim()) return;
33
+
34
+ let coloredLine = '';
35
+ const chars = line.split('');
36
+ const totalChars = chars.filter(c => c !== ' ').length;
37
+ let charIndex = 0;
38
+
39
+ chars.forEach(char => {
40
+ if (char === ' ') {
41
+ coloredLine += ' ';
42
+ } else {
43
+ const progress = totalChars > 1 ? charIndex / (totalChars - 1) : 0;
44
+ const segmentCount = colors.length - 1;
45
+ const segmentFloat = progress * segmentCount;
46
+ const segmentIndex = Math.min(Math.floor(segmentFloat), segmentCount - 1);
47
+ const segmentProgress = segmentFloat - segmentIndex;
48
+
49
+ const c1 = colors[segmentIndex];
50
+ const c2 = colors[segmentIndex + 1];
51
+
52
+ const r = Math.round(c1.r + segmentProgress * (c2.r - c1.r));
53
+ const g = Math.round(c1.g + segmentProgress * (c2.g - c1.g));
54
+ const b = Math.round(c1.b + segmentProgress * (c2.b - c1.b));
55
+
56
+ coloredLine += `\x1b[38;2;${r};${g};${b}m${char}\x1b[0m`;
57
+ charIndex++;
58
+ }
59
+ });
60
+
61
+ console.log(coloredLine);
62
+ });
63
+
64
+ console.log('');
65
+ console.log(chalk.gray(` Advanced RTL & Typography Control | v${currentVersion}\n`));
66
+ } catch (err) {
67
+ // Fallback banner
68
+ console.log(chalk.cyan.bold(`\n✨ Antigravity Smart RTL Patcher v${currentVersion}\n`));
69
+ }
70
+ }
71
+
72
+ // Show banner
73
+ showBanner();
74
+
75
+ // CLI setup
12
76
  program
13
77
  .name('agy-rtl')
14
- .description('RTL patcher for Antigravity')
78
+ .description('Advanced RTL patcher for Antigravity')
15
79
  .version(currentVersion);
16
80
 
17
81
  program
18
82
  .command('patch')
19
- .description('Inject RTL support into Antigravity')
83
+ .description('Inject advanced RTL support into Antigravity')
20
84
  .option('-p, --path <path>', 'Custom path to Antigravity installation')
21
85
  .option('--skip-update-check', 'Skip checking for updates')
22
86
  .action(async (options) => {
23
- console.log(BANNER);
24
87
  try {
25
88
  await patch(options.path, options.skipUpdateCheck);
26
89
  } catch (err) {
27
- console.error(chalk.red('\nPatch failed:'), err.message);
90
+ console.error(chalk.red('\n✖ Patch failed:'), err.message);
28
91
  process.exit(1);
29
92
  }
30
93
  });
31
94
 
32
95
  program
33
96
  .command('restore')
34
- .description('Remove RTL patch and restore Antigravity')
97
+ .description('Remove RTL patch and restore original Antigravity')
35
98
  .option('-p, --path <path>', 'Custom path to Antigravity installation')
36
99
  .action(async (options) => {
37
- console.log(BANNER);
38
100
  try {
39
101
  await restore(options.path);
40
102
  } catch (err) {
41
- console.error(chalk.red('\nRestore failed:'), err.message);
103
+ console.error(chalk.red('\n✖ Restore failed:'), err.message);
42
104
  process.exit(1);
43
105
  }
44
106
  });
@@ -48,11 +110,10 @@ program
48
110
  .description('Check current patch status')
49
111
  .option('-p, --path <path>', 'Custom path to Antigravity installation')
50
112
  .action(async (options) => {
51
- console.log(BANNER);
52
113
  try {
53
114
  await status(options.path);
54
115
  } catch (err) {
55
- console.error(chalk.red('\nStatus check failed:'), err.message);
116
+ console.error(chalk.red('\n✖ Status check failed:'), err.message);
56
117
  process.exit(1);
57
118
  }
58
119
  });
@@ -61,7 +122,6 @@ program
61
122
  .command('update')
62
123
  .description('Check for updates and show installation instructions')
63
124
  .action(async () => {
64
- console.log(BANNER);
65
125
  console.log(chalk.cyan('Checking for updates...\n'));
66
126
  const hasUpdate = await checkForUpdates(false);
67
127
  if (!hasUpdate) {
@@ -70,4 +130,3 @@ program
70
130
  });
71
131
 
72
132
  program.parse(process.argv);
73
-
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "antigravity-rtl-patcher",
3
- "version": "2.3.4",
4
- "description": "Smart RTL and Persian/Arabic typography patcher for Antigravity",
3
+ "version": "3.0.1",
4
+ "description": "Advanced RTL and Persian/Arabic typography patcher for Antigravity with customizable UI",
5
5
  "main": "src/patcher.js",
6
6
  "bin": {
7
7
  "antigravity-rtl-patcher": "./bin/cli.js",
@@ -23,7 +23,9 @@
23
23
  "electron",
24
24
  "asar",
25
25
  "right-to-left",
26
- "bidirectional"
26
+ "bidirectional",
27
+ "ui-customization",
28
+ "font-control"
27
29
  ],
28
30
  "author": "VaFa1726",
29
31
  "license": "MIT",
@@ -42,7 +44,10 @@
42
44
  "@electron/asar": "^3.2.14",
43
45
  "chalk": "^4.1.2",
44
46
  "commander": "^11.1.0",
47
+ "figlet": "^1.7.0",
45
48
  "fs-extra": "^11.2.0",
46
- "ora": "^5.4.1"
49
+ "ora": "^5.4.1",
50
+ "picocolors": "^1.0.0",
51
+ "prompts": "^2.4.2"
47
52
  }
48
53
  }
@@ -0,0 +1,191 @@
1
+ /* ANTIGRAVITY_RTL_PATCH_v3 */
2
+
3
+ win.webContents.on('console-message', (event, ...args) => {
4
+ let message = '';
5
+ if (args.length === 1 && typeof args[0] === 'object' && args[0] !== null) {
6
+ message = args[0].message;
7
+ } else {
8
+ message = args[1];
9
+ }
10
+
11
+ if (typeof message === 'string' && message.startsWith('RTL_CONFIG_SAVE:')) {
12
+ try {
13
+ const configData = message.substring(16);
14
+ const configPath = require('path').join(require('os').homedir(), '.antigravity-rtl.json');
15
+ require('fs').writeFileSync(configPath, configData, 'utf8');
16
+ } catch (err) {
17
+ console.error('[RTL] Config save failed:', err);
18
+ }
19
+ }
20
+ });
21
+
22
+ void win.loadURL(url);
23
+
24
+ win.webContents.on('dom-ready', () => {
25
+ try {
26
+ let rtlConfig = { enabled: true };
27
+ try {
28
+ const configPath = require('path').join(require('os').homedir(), '.antigravity-rtl.json');
29
+ if (require('fs').existsSync(configPath)) {
30
+ const cfg = JSON.parse(require('fs').readFileSync(configPath, 'utf8'));
31
+ rtlConfig = { ...rtlConfig, ...cfg };
32
+ }
33
+ } catch (err) {}
34
+
35
+ win.webContents.executeJavaScript(`
36
+ (function initRTL() {
37
+ if (window.__RTL_LOADED__) return;
38
+ window.__RTL_LOADED__ = true;
39
+
40
+ let rtlEnabled = ${rtlConfig.enabled};
41
+
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
+ \`;
89
+
90
+ const styleEl = document.createElement('style');
91
+ styleEl.id = 'rtl-main-style';
92
+ styleEl.textContent = CSS;
93
+ document.head.appendChild(styleEl);
94
+
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]);
104
+ }
105
+
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
+ }
135
+
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);
140
+
141
+ document.addEventListener('keydown', (e) => {
142
+ if (e.altKey && e.code === 'KeyR') {
143
+ e.preventDefault();
144
+ toggleRTL();
145
+ }
146
+ }, { capture: true });
147
+
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)';
153
+
154
+ btn.addEventListener('click', toggleRTL);
155
+
156
+ function toggleRTL() {
157
+ rtlEnabled = !rtlEnabled;
158
+
159
+ if (rtlEnabled) {
160
+ btn.classList.add('active');
161
+ if (!document.getElementById('rtl-main-style')) {
162
+ document.head.appendChild(styleEl);
163
+ }
164
+ updateDirections();
165
+ } 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
+ }
174
+ });
175
+ }
176
+
177
+ console.log('RTL_CONFIG_SAVE:' + JSON.stringify({ enabled: rtlEnabled }));
178
+ }
179
+
180
+ document.body.appendChild(btn);
181
+
182
+ if (rtlEnabled) {
183
+ updateDirections();
184
+ }
185
+ })();
186
+ `).catch(err => console.error('[RTL] Injection failed:', err));
187
+
188
+ } catch (error) {
189
+ console.error('[RTL] Init error:', error);
190
+ }
191
+ });