@signalk/app-dock 1.1.0-beta.1 → 1.1.0
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 +34 -9
- package/package.json +1 -1
- package/public/app-icon-180.png +0 -0
- package/public/app-icon-maskable.svg +24 -0
- package/public/index.html +9 -0
- package/public/manifest.webmanifest +31 -0
- package/test/plugin.test.js +18 -0
package/README.md
CHANGED
|
@@ -13,6 +13,8 @@ A macOS-style app dock for switching between Signal K webapps on touch screens.
|
|
|
13
13
|
- **Autostart** -- optionally load a default app immediately on open
|
|
14
14
|
- **keep-alive or destroy** iframe lifecycle
|
|
15
15
|
- **Night/day mode toggle** -- optional sun/moon button that flips `environment.mode` via a PUT handler
|
|
16
|
+
- **Fullscreen toggle** -- optional button that hides browser chrome via the Fullscreen API; feature-detected, so hidden on devices without API support (notably iPadOS Safari -- use Add to Home Screen there)
|
|
17
|
+
- **Installable as an app** -- ships a web app manifest and apple-touch-icon so iOS, Android, and desktop browsers can install the dock to the home screen and launch it in standalone mode (no browser chrome). Works over plain HTTP -- no SSL required
|
|
16
18
|
- **Active dot indicator**, label tooltip, haptic feedback
|
|
17
19
|
- **Embedded config panel** in the admin UI with webapp discovery, drag-to-reorder, and live preview
|
|
18
20
|
|
|
@@ -35,6 +37,18 @@ Tip: double-tapping a clickable element in the underlying webapp will activate t
|
|
|
35
37
|
|
|
36
38
|
Config changes made in **Plugin Config** apply automatically within ~5 seconds: structural changes (position, icon size, etc.) reload the dock page; changes to the app list hot-update in place.
|
|
37
39
|
|
|
40
|
+
## Install as an app
|
|
41
|
+
|
|
42
|
+
The dock ships a web app manifest, so iOS and Android can install it to the home screen and launch it like a native app -- no Safari/Chrome chrome, no URL bar.
|
|
43
|
+
|
|
44
|
+
- **iPad / iPhone (Safari)**: open the dock URL, tap the Share icon, choose **Add to Home Screen**.
|
|
45
|
+
- **Android (Chrome)**: open the dock URL, tap the ⋮ menu, choose **Install app** (or **Add to Home Screen**).
|
|
46
|
+
- **Desktop (Chrome, Edge)**: an install icon appears in the address bar; click it.
|
|
47
|
+
|
|
48
|
+
HTTPS is **not required** for Add-to-Home-Screen -- the dock installs cleanly over plain `http://your-sk-server:3000/`. It works equally over HTTPS with a self-signed or local-CA cert, provided the device has been configured to trust that CA (the usual iPad profile flow: Settings > General > VPN & Device Management > trust the profile > Settings > General > About > Certificate Trust Settings > enable full trust).
|
|
49
|
+
|
|
50
|
+
If the installed dock ever displays a blank screen after a long idle period (rare; only if the server's caching layer ignores the dock's `no-cache` directives), remove the home-screen icon and re-add it from Safari.
|
|
51
|
+
|
|
38
52
|
## Configuration
|
|
39
53
|
|
|
40
54
|
Open **Plugin Config > App Dock** in the admin UI. The embedded configurator provides:
|
|
@@ -47,15 +61,16 @@ Open **Plugin Config > App Dock** in the admin UI. The embedded configurator pro
|
|
|
47
61
|
|
|
48
62
|
### Settings
|
|
49
63
|
|
|
50
|
-
| Setting
|
|
51
|
-
|
|
|
52
|
-
| `position`
|
|
53
|
-
| `iframeMode`
|
|
54
|
-
| `iconSize`
|
|
55
|
-
| `magnification`
|
|
56
|
-
| `magnificationScale`
|
|
57
|
-
| `showNightModeButton`
|
|
58
|
-
| `
|
|
64
|
+
| Setting | Default | Description |
|
|
65
|
+
| ---------------------- | ------------ | ------------------------------------------------------------------------------------------------ |
|
|
66
|
+
| `position` | `bottom` | Dock edge: `bottom`, `top`, `left`, `right` |
|
|
67
|
+
| `iframeMode` | `keep-alive` | `keep-alive` loads each app once and hides/shows (faster, more RAM); `destroy` reloads each time |
|
|
68
|
+
| `iconSize` | `56` | Base icon size in px |
|
|
69
|
+
| `magnification` | `true` | Enable macOS-style magnification effect |
|
|
70
|
+
| `magnificationScale` | `1.7` | Max icon scale (1.0-2.5) |
|
|
71
|
+
| `showNightModeButton` | `true` | Show sun/moon button in dock; PUT-writes `environment.mode` |
|
|
72
|
+
| `showFullscreenButton` | `false` | Show fullscreen toggle in dock; hidden automatically where the Fullscreen API is unavailable |
|
|
73
|
+
| `showExitButton` | `false` | Show X button that returns to the Signal K admin UI |
|
|
59
74
|
|
|
60
75
|
## Development
|
|
61
76
|
|
|
@@ -87,6 +102,16 @@ The repo ships three cooperating surfaces:
|
|
|
87
102
|
| `npm run lint` | ESLint check |
|
|
88
103
|
| `npm run build:config` | Rebuild the admin UI config panel (required after `src/` changes) |
|
|
89
104
|
|
|
105
|
+
### Icon assets
|
|
106
|
+
|
|
107
|
+
If `public/app-icon.svg` changes, regenerate the 180-px apple-touch-icon:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
rsvg-convert -w 180 -h 180 public/app-icon.svg -o public/app-icon-180.png
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`public/app-icon-maskable.svg` is a hand-authored wrapper that places the artwork inside Android's 80% safe zone; if the main icon's layout changes meaningfully, update it by hand to match.
|
|
114
|
+
|
|
90
115
|
## License
|
|
91
116
|
|
|
92
117
|
Apache-2.0
|
package/package.json
CHANGED
|
Binary file
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="bg" x1="0" y1="0" x2="0" y2="1">
|
|
4
|
+
<stop offset="0%" stop-color="#60a5fa"/>
|
|
5
|
+
<stop offset="100%" stop-color="#2563eb"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
</defs>
|
|
8
|
+
<rect width="100" height="100" fill="url(#bg)"/>
|
|
9
|
+
<g transform="translate(14 14)">
|
|
10
|
+
<rect x="8" y="48" width="56" height="16" rx="8" fill="#ffffff" fill-opacity="0.25" stroke="#ffffff" stroke-opacity="0.4" stroke-width="0.5"/>
|
|
11
|
+
<rect x="14" y="51" width="10" height="10" rx="2.5" fill="#3b82f6" opacity="0.9"/>
|
|
12
|
+
<rect x="31" y="51" width="10" height="10" rx="2.5" fill="#10b981" opacity="0.9"/>
|
|
13
|
+
<rect x="48" y="51" width="10" height="10" rx="2.5" fill="#f59e0b" opacity="0.9"/>
|
|
14
|
+
<rect x="28" y="34" width="16" height="16" rx="3.5" fill="#10b981" opacity="0.95"/>
|
|
15
|
+
<circle cx="36" cy="66" r="1.5" fill="#ffffff" fill-opacity="0.8"/>
|
|
16
|
+
<circle cx="36" cy="22" r="10" fill="none" stroke="#ffffff" stroke-opacity="0.15" stroke-width="1"/>
|
|
17
|
+
<line x1="36" y1="14" x2="36" y2="18" stroke="#ffffff" stroke-opacity="0.3" stroke-width="1" stroke-linecap="round"/>
|
|
18
|
+
<line x1="36" y1="26" x2="36" y2="30" stroke="#ffffff" stroke-opacity="0.15" stroke-width="1" stroke-linecap="round"/>
|
|
19
|
+
<line x1="28" y1="22" x2="32" y2="22" stroke="#ffffff" stroke-opacity="0.15" stroke-width="1" stroke-linecap="round"/>
|
|
20
|
+
<line x1="40" y1="22" x2="44" y2="22" stroke="#ffffff" stroke-opacity="0.15" stroke-width="1" stroke-linecap="round"/>
|
|
21
|
+
<polygon points="36,15 34,22 36,20 38,22" fill="#ef4444" fill-opacity="0.7"/>
|
|
22
|
+
<polygon points="36,29 34,22 36,24 38,22" fill="#ffffff" fill-opacity="0.25"/>
|
|
23
|
+
</g>
|
|
24
|
+
</svg>
|
package/public/index.html
CHANGED
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover" />
|
|
6
6
|
<meta name="mobile-web-app-capable" content="yes" />
|
|
7
|
+
<link rel="manifest" href="manifest.webmanifest" />
|
|
8
|
+
<link rel="icon" type="image/svg+xml" href="app-icon.svg" />
|
|
9
|
+
<link rel="apple-touch-icon" href="app-icon-180.png" />
|
|
10
|
+
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
11
|
+
<meta name="apple-mobile-web-app-title" content="App Dock" />
|
|
12
|
+
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
13
|
+
<meta name="theme-color" content="#000000" />
|
|
14
|
+
<meta http-equiv="Cache-Control" content="no-cache, must-revalidate" />
|
|
15
|
+
<meta http-equiv="Pragma" content="no-cache" />
|
|
7
16
|
<title>SK Dock</title>
|
|
8
17
|
<link rel="stylesheet" href="dock.css" />
|
|
9
18
|
</head>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Signal K App Dock",
|
|
3
|
+
"short_name": "App Dock",
|
|
4
|
+
"description": "macOS-style dock to switch between Signal K webapps",
|
|
5
|
+
"start_url": "/@signalk/app-dock/",
|
|
6
|
+
"scope": "/",
|
|
7
|
+
"display": "standalone",
|
|
8
|
+
"orientation": "any",
|
|
9
|
+
"background_color": "#000000",
|
|
10
|
+
"theme_color": "#000000",
|
|
11
|
+
"icons": [
|
|
12
|
+
{
|
|
13
|
+
"src": "app-icon.svg",
|
|
14
|
+
"sizes": "any",
|
|
15
|
+
"type": "image/svg+xml",
|
|
16
|
+
"purpose": "any"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"src": "app-icon-180.png",
|
|
20
|
+
"sizes": "180x180",
|
|
21
|
+
"type": "image/png",
|
|
22
|
+
"purpose": "any"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"src": "app-icon-maskable.svg",
|
|
26
|
+
"sizes": "any",
|
|
27
|
+
"type": "image/svg+xml",
|
|
28
|
+
"purpose": "maskable"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
package/test/plugin.test.js
CHANGED
|
@@ -521,4 +521,22 @@ describe('public files', () => {
|
|
|
521
521
|
it('icon-settings.svg exists', () => {
|
|
522
522
|
assert.ok(fs.existsSync(path.join(publicDir, 'icon-settings.svg')))
|
|
523
523
|
})
|
|
524
|
+
|
|
525
|
+
it('manifest.webmanifest exists and is valid JSON with required PWA fields', () => {
|
|
526
|
+
const manifestPath = path.join(publicDir, 'manifest.webmanifest')
|
|
527
|
+
assert.ok(fs.existsSync(manifestPath))
|
|
528
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'))
|
|
529
|
+
assert.equal(typeof manifest.name, 'string')
|
|
530
|
+
assert.equal(typeof manifest.start_url, 'string')
|
|
531
|
+
assert.equal(manifest.display, 'standalone')
|
|
532
|
+
assert.ok(Array.isArray(manifest.icons) && manifest.icons.length > 0)
|
|
533
|
+
})
|
|
534
|
+
|
|
535
|
+
it('app-icon-180.png exists (apple-touch-icon)', () => {
|
|
536
|
+
assert.ok(fs.existsSync(path.join(publicDir, 'app-icon-180.png')))
|
|
537
|
+
})
|
|
538
|
+
|
|
539
|
+
it('app-icon-maskable.svg exists', () => {
|
|
540
|
+
assert.ok(fs.existsSync(path.join(publicDir, 'app-icon-maskable.svg')))
|
|
541
|
+
})
|
|
524
542
|
})
|