Skip to content

Commit dcb2a44

Browse files
authored
Merge pull request #5 from JosunLP/dev
feat: Implement mobile support with touch gestures and responsive
2 parents 613a60c + ec933c3 commit dcb2a44

6 files changed

Lines changed: 842 additions & 60 deletions

File tree

README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ A modern, production-ready template for building UserScripts using TypeScript an
2020
• 🎨 **DOM Utilities:** Helper functions for element manipulation and waiting
2121
• 🔒 **Error Handling:** Comprehensive error boundary system
2222
• ⚡ **Event System:** Type-safe event emitter for module communication
23+
• 📱 **Mobile Support:** Touch-optimized interface with mobile browser detection
24+
• 🤏 **Touch Gestures:** Built-in touch event handling and gesture recognition
25+
• 📲 **Responsive Design:** Mobile-first CSS with safe area support for notched devices
2326

2427
## Installation
2528

@@ -202,13 +205,68 @@ export class MyModule extends EventEmitter<ModuleEvents> {
202205
}
203206
```
204207

208+
### Mobile Utilities
209+
210+
Mobile-specific functionality for touch-enabled devices:
211+
212+
```typescript
213+
import { MobileUtils } from '@/utils/mobile';
214+
215+
// Detect mobile browser and capabilities
216+
const detection = MobileUtils.detect();
217+
console.log('Is Mobile:', detection.isMobile);
218+
console.log('Has Touch:', detection.hasTouch);
219+
console.log('Browser:', detection.browser);
220+
221+
// Add mobile-optimized styles
222+
if (detection.isMobile) {
223+
MobileUtils.addMobileStyles();
224+
}
225+
226+
// Unified touch/mouse event handling
227+
MobileUtils.addUnifiedEventListener(element, 'start', event => {
228+
const position = MobileUtils.getEventPosition(event);
229+
console.log('Touch/click at:', position);
230+
});
231+
232+
// Create mobile-friendly buttons
233+
const button = mobileModule.createMobileButton('Action', () => {
234+
console.log('Button pressed');
235+
});
236+
237+
// Orientation detection
238+
console.log('Portrait mode:', MobileUtils.isPortrait());
239+
```
240+
205241
## UserScript Compatibility
206242

207243
**Tampermonkey:** Full support with all GM\_\* APIs
208244
**Greasemonkey:** Compatible with standard UserScript APIs
209245
**Violentmonkey:** Full compatibility
210246
**Safari:** Works with userscript managers
211247

248+
### Mobile Browser Support
249+
250+
**Android:**
251+
252+
- **Kiwi Browser:** Full Chrome extension + UserScript support
253+
- **Microsoft Edge Mobile:** Tampermonkey support
254+
- **Firefox Mobile:** Greasemonkey, Tampermonkey, Violentmonkey
255+
- **Yandex Browser:** Chrome extension support
256+
257+
**iOS:**
258+
259+
- **Safari Mobile:** Tampermonkey or Userscripts App
260+
- Limited support due to iOS restrictions
261+
262+
### Mobile Features
263+
264+
**Touch Gestures:** Tap, swipe, and pinch detection
265+
**Responsive Design:** Mobile-first CSS with viewport adaptation
266+
**Safe Area Support:** Automatic handling of notched devices
267+
**Orientation Detection:** Portrait/landscape change handling
268+
**Mobile-Optimized UI:** Touch-friendly buttons and menus
269+
212270
## Contributing
213271

214272
1. Fork the repository

header.config.json

Lines changed: 55 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,58 @@
11
{
2-
"updateUrl": "",
3-
"downloadUrl": "",
4-
"supportUrl": "",
5-
"iconUrl": "./assets/icon.png",
6-
"environments": {
7-
"development": {
8-
"includes": [
9-
"http://localhost:*/*",
10-
"https://localhost:*/*",
11-
"https://*.josunlp.de/*",
12-
"https://josunlp.de/*"
13-
],
14-
"excludes": [],
15-
"grants": [
16-
"GM_setValue",
17-
"GM_getValue",
18-
"GM_deleteValue",
19-
"GM_listValues",
20-
"GM_log",
21-
"GM_notification",
22-
"GM_registerMenuCommand",
23-
"GM_unregisterMenuCommand"
24-
]
25-
},
26-
"production": {
27-
"includes": [
28-
"https://*.josunlp.de/*",
29-
"https://josunlp.de/*"
30-
],
31-
"excludes": [],
32-
"grants": [
33-
"GM_setValue",
34-
"GM_getValue",
35-
"GM_deleteValue",
36-
"GM_listValues",
37-
"GM_registerMenuCommand"
38-
]
39-
}
2+
"updateUrl": "",
3+
"downloadUrl": "",
4+
"supportUrl": "",
5+
"iconUrl": "./assets/icon.png",
6+
"environments": {
7+
"development": {
8+
"includes": [
9+
"http://localhost:*/*",
10+
"https://localhost:*/*",
11+
"https://*.josunlp.de/*",
12+
"https://josunlp.de/*"
13+
],
14+
"excludes": [],
15+
"grants": [
16+
"GM_setValue",
17+
"GM_getValue",
18+
"GM_deleteValue",
19+
"GM_listValues",
20+
"GM_log",
21+
"GM_notification",
22+
"GM_registerMenuCommand",
23+
"GM_unregisterMenuCommand"
24+
]
4025
},
41-
"requires": [],
42-
"resources": [],
43-
"connecters": [],
44-
"matches": [],
45-
"matchAllFrames": false,
46-
"runAt": "document-start",
47-
"antifeatures": [],
48-
"noframes": false,
49-
"unwrap": false
26+
"production": {
27+
"includes": ["https://*.josunlp.de/*", "https://josunlp.de/*"],
28+
"excludes": [],
29+
"grants": [
30+
"GM_setValue",
31+
"GM_getValue",
32+
"GM_deleteValue",
33+
"GM_listValues",
34+
"GM_registerMenuCommand"
35+
]
36+
}
37+
},
38+
"mobile": {
39+
"supportedBrowsers": [
40+
"Kiwi Browser (Android)",
41+
"Microsoft Edge Mobile",
42+
"Firefox Mobile",
43+
"Safari Mobile (iOS)",
44+
"Yandex Browser"
45+
],
46+
"touchOptimized": true,
47+
"responsiveDesign": true
48+
},
49+
"requires": [],
50+
"resources": [],
51+
"connecters": [],
52+
"matches": [],
53+
"matchAllFrames": false,
54+
"runAt": "document-start",
55+
"antifeatures": [],
56+
"noframes": false,
57+
"unwrap": false
5058
}

package.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "userscript-project-template",
33
"version": "1.0.0",
4-
"description": "A modern, production-ready template for building UserScripts using TypeScript and Vite. This template provides a solid foundation with best practices, type safety, and modern development tools for Tampermonkey and Greasemonkey scripts.",
4+
"description": "A modern, production-ready template for building UserScripts using TypeScript and Vite with mobile browser support, touch gestures, and responsive design for Tampermonkey and Greasemonkey scripts.",
55
"main": "index.ts",
66
"module": "node",
77
"scripts": {
@@ -32,7 +32,13 @@
3232
"vite",
3333
"browser-automation",
3434
"web-enhancement",
35-
"browser-scripting"
35+
"browser-scripting",
36+
"mobile-support",
37+
"touch-gestures",
38+
"responsive-design",
39+
"mobile-browser",
40+
"kiwi-browser",
41+
"edge-mobile"
3642
],
3743
"author": "Jonas Pfalzgraf <info@josunlp.de>",
3844
"license": "MIT",

src/index.ts

Lines changed: 80 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { ExampleModule } from '@/modules/example';
22
import { DOMUtils } from '@/utils/dom';
33
import { EventEmitter } from '@/utils/events';
4+
import { MobileUtils } from '@/utils/mobile';
45
import { Storage } from '@/utils/storage';
56

67
/**
@@ -60,6 +61,14 @@ class App extends EventEmitter<AppEvents> {
6061
protected async main(): Promise<void> {
6162
console.log('👋 Hello from UserScript Template!');
6263

64+
// Mobile detection and setup
65+
const mobileInfo = MobileUtils.detect();
66+
if (mobileInfo.isMobile) {
67+
console.log('📱 Mobile browser detected:', mobileInfo.browser);
68+
MobileUtils.addMobileStyles();
69+
MobileUtils.logMobileInfo();
70+
}
71+
6372
// Example: Add some basic functionality
6473
this.addExampleFeatures();
6574

@@ -75,11 +84,27 @@ class App extends EventEmitter<AppEvents> {
7584
// Initialize example module
7685
const exampleModule = new ExampleModule();
7786
await exampleModule.initialize();
78-
79-
// Register the module
8087
this.registerModule('example', exampleModule);
8188

82-
// Listen to module events
89+
// Initialize mobile module if on mobile device
90+
const mobileInfo = MobileUtils.detect();
91+
if (mobileInfo.isMobile || mobileInfo.hasTouch) {
92+
const { MobileModule } = await import('@/modules/mobile');
93+
const mobileModule = new MobileModule();
94+
await mobileModule.initialize();
95+
this.registerModule('mobile', mobileModule);
96+
97+
// Listen to mobile module events
98+
mobileModule.on('gestureDetected', ({ type, position }) => {
99+
console.log(`📱 Gesture detected: ${type} at ${position.x}, ${position.y}`);
100+
});
101+
102+
mobileModule.on('orientationChanged', ({ orientation }) => {
103+
console.log(`📱 Orientation changed to: ${orientation}`);
104+
});
105+
}
106+
107+
// Listen to example module events
83108
exampleModule.on('actionPerformed', ({ action, timestamp }) => {
84109
console.log(
85110
`📡 Module action received: ${action} at ${new Date(timestamp).toLocaleString()}`
@@ -94,28 +119,72 @@ class App extends EventEmitter<AppEvents> {
94119
* Example features to demonstrate the template
95120
*/
96121
private addExampleFeatures(): void {
97-
// Example: Add custom styles
98-
DOMUtils.addStyles(
99-
`
122+
// Add mobile-optimized styles
123+
const mobileInfo = MobileUtils.detect();
124+
const baseCss = `
100125
.userscript-highlight {
101126
background-color: yellow !important;
102127
border: 2px solid red !important;
103128
}
104-
`,
105-
'userscript-styles'
106-
);
129+
`;
130+
131+
// Add mobile-specific styles if on mobile
132+
const mobileCss = mobileInfo.isMobile
133+
? `
134+
.userscript-highlight {
135+
padding: 8px !important;
136+
border-radius: 4px !important;
137+
font-size: 16px !important; /* Prevent zoom on iOS */
138+
}
139+
`
140+
: '';
141+
142+
DOMUtils.addStyles(baseCss + mobileCss, 'userscript-styles');
107143

108144
// Example: Storage usage
109145
const visitCount = (Storage.get<number>('visitCount', 0) || 0) + 1;
110146
Storage.set('visitCount', visitCount);
111147
console.log(`📊 This is visit #${visitCount}`);
112148

113-
// Example: Add menu command
149+
// Example: Add menu command (with mobile detection)
114150
if (typeof GM_registerMenuCommand !== 'undefined') {
115151
GM_registerMenuCommand('Show Visit Count', () => {
116152
const count = Storage.get<number>('visitCount', 0);
117-
alert(`You have visited this page ${count} times!`);
153+
154+
if (mobileInfo.isMobile) {
155+
// Mobile-friendly notification
156+
if (typeof GM_notification !== 'undefined') {
157+
GM_notification(`Visit Count: ${count}`, 'UserScript Info', undefined, () => {
158+
console.log('Notification clicked');
159+
});
160+
} else {
161+
alert(`You have visited this page ${count} times!`);
162+
}
163+
} else {
164+
// Desktop alert
165+
alert(`You have visited this page ${count} times!`);
166+
}
118167
});
168+
169+
// Add mobile-specific menu command
170+
if (mobileInfo.isMobile) {
171+
GM_registerMenuCommand('Mobile Info', () => {
172+
MobileUtils.logMobileInfo();
173+
174+
const info = `
175+
Device: ${mobileInfo.isAndroid ? 'Android' : mobileInfo.isIOS ? 'iOS' : 'Other'}
176+
Touch Support: ${mobileInfo.hasTouch ? 'Yes' : 'No'}
177+
UserScript Support: ${MobileUtils.supportsUserScripts() ? 'Yes' : 'No'}
178+
Recommended Manager: ${MobileUtils.getRecommendedUserScriptManager()}
179+
`;
180+
181+
if (typeof GM_notification !== 'undefined') {
182+
GM_notification(info, 'Mobile Device Info');
183+
} else {
184+
alert(info);
185+
}
186+
});
187+
}
119188
}
120189
}
121190

0 commit comments

Comments
 (0)