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 +121 -0
- package/README.md +21 -58
- package/bin/cli.js +73 -14
- package/package.json +9 -4
- package/payload/utils-inject.js +191 -0
- package/src/patcher.js +93 -98
- package/src/paths.js +51 -0
- package/payload/preload-inject.js +0 -526
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
|
-
|
|
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
|
-
## ⚡ 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
|
-
|
|
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
|
-
##
|
|
22
|
+
## Usage
|
|
28
23
|
|
|
29
|
-
|
|
24
|
+
After patching, a toggle button appears in the bottom-right corner. Click it to enable/disable RTL support.
|
|
30
25
|
|
|
31
|
-
|
|
32
|
-
npx antigravity-rtl-patcher@latest patch
|
|
33
|
-
```
|
|
26
|
+
Keyboard shortcut: `Alt + R`
|
|
34
27
|
|
|
35
|
-
|
|
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
|
-
|
|
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
|
|
57
|
-
| `agy-rtl status` | Show
|
|
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
|
-
|
|
43
|
+
## How It Works
|
|
67
44
|
|
|
68
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
57
|
+
- Linux: `/opt/Antigravity`, `~/Downloads/Antigravity-x64`
|
|
58
|
+
- macOS: `/Applications/Antigravity.app`
|
|
59
|
+
- Windows: `%LOCALAPPDATA%\Programs\Antigravity`
|
|
97
60
|
|
|
98
|
-
|
|
61
|
+
Use `--path` option for custom locations.
|
|
99
62
|
|
|
100
|
-
##
|
|
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
|
-
|
|
9
|
-
|
|
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('\
|
|
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('\
|
|
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('\
|
|
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": "
|
|
4
|
-
"description": "
|
|
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
|
+
});
|