@signalk/app-dock 1.3.1 → 1.3.3-beta.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/README.md CHANGED
@@ -102,6 +102,8 @@ Open **Plugin Config > App Dock** in the admin UI. The embedded configurator pro
102
102
  | `showFullscreenButton` | `false` | Show fullscreen toggle in dock; hidden automatically where the Fullscreen API is unavailable |
103
103
  | `showExitButton` | `false` | Show X button that returns to the Signal K admin UI |
104
104
 
105
+ In either `iframeMode`, the server's admin UI (an app whose URL is under `/admin/`, such as the Settings tile) opens fresh every time, at the URL its tile points to. A webapp or page opened from inside the admin UI does not come back the next time Settings is tapped.
106
+
105
107
  ## Access
106
108
 
107
109
  With security enabled, what the dock offers depends on the visitor:
@@ -148,13 +150,15 @@ The repo ships three cooperating surfaces:
148
150
 
149
151
  ### Icon assets
150
152
 
151
- If `public/app-icon.svg` changes, regenerate the 180-px apple-touch-icon:
153
+ `public/app-icon.svg` has a transparent background: the artwork sits straight on whatever page shows it, so its colours have to read on light and dark backgrounds alike. Check a change on both before committing.
154
+
155
+ The 180-px apple-touch-icon needs an opaque background, because iOS fills transparency with black, and room for the corners iOS rounds off. Regenerate it from the SVG whenever that changes:
152
156
 
153
157
  ```bash
154
- rsvg-convert -w 180 -h 180 public/app-icon.svg -o public/app-icon-180.png
158
+ rsvg-convert -w 132 -h 132 public/app-icon.svg | magick - -background '#0f172a' -gravity center -extent 180x180 -alpha remove -alpha off PNG24:public/app-icon-180.png
155
159
  ```
156
160
 
157
- `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.
161
+ `public/app-icon-maskable.svg` is hand-authored: the same artwork on the same dark slate, scaled into Android's 80% safe zone. Update it by hand when the artwork changes.
158
162
 
159
163
  ## License
160
164
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signalk/app-dock",
3
- "version": "1.3.1",
3
+ "version": "1.3.3-beta.1",
4
4
  "description": "macOS-style configurable app dock for switching between SignalK webapps on touch screens",
5
5
  "repository": {
6
6
  "url": "https://github.com/SignalK/app-dock"
Binary file
@@ -1,24 +1,17 @@
1
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"/>
2
+ <rect width="100" height="100" fill="#0f172a"/>
3
+ <g transform="translate(22 22) scale(0.7778)">
4
+ <circle cx="36" cy="16" r="11" fill="none" stroke="#3b82f6" stroke-opacity="0.7" stroke-width="1.5"/>
5
+ <line x1="36" y1="3" x2="36" y2="7" stroke="#3b82f6" stroke-width="1.5" stroke-linecap="round"/>
6
+ <line x1="23" y1="16" x2="27" y2="16" stroke="#3b82f6" stroke-opacity="0.7" stroke-width="1.5" stroke-linecap="round"/>
7
+ <line x1="45" y1="16" x2="49" y2="16" stroke="#3b82f6" stroke-opacity="0.7" stroke-width="1.5" stroke-linecap="round"/>
8
+ <polygon points="36,8 33,16 36,14 39,16" fill="#ef4444"/>
9
+ <polygon points="36,24 33,16 36,18 39,16" fill="#64748b"/>
10
+ <rect x="3" y="44" width="66" height="22" rx="11" fill="#3b82f6" fill-opacity="0.15" stroke="#3b82f6" stroke-width="1.5"/>
11
+ <rect x="9" y="49" width="12" height="12" rx="3" fill="#3b82f6"/>
12
+ <rect x="30" y="49" width="12" height="12" rx="3" fill="#10b981"/>
13
+ <rect x="51" y="49" width="12" height="12" rx="3" fill="#f59e0b"/>
14
+ <rect x="27" y="29" width="18" height="18" rx="4.5" fill="#10b981"/>
15
+ <circle cx="36" cy="69.5" r="2" fill="#3b82f6"/>
23
16
  </g>
24
17
  </svg>
@@ -1,29 +1,21 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72 72" width="72" height="72">
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
- <!-- Background, full bleed: whatever displays the icon rounds the corners -->
9
- <rect width="72" height="72" fill="url(#bg)"/>
2
+ <!-- Transparent background: the artwork is drawn straight on the canvas in
3
+ mid-tone colours that read on light and dark pages alike -->
4
+ <!-- Compass rose -->
5
+ <circle cx="36" cy="16" r="11" fill="none" stroke="#3b82f6" stroke-opacity="0.7" stroke-width="1.5"/>
6
+ <line x1="36" y1="3" x2="36" y2="7" stroke="#3b82f6" stroke-width="1.5" stroke-linecap="round"/>
7
+ <line x1="23" y1="16" x2="27" y2="16" stroke="#3b82f6" stroke-opacity="0.7" stroke-width="1.5" stroke-linecap="round"/>
8
+ <line x1="45" y1="16" x2="49" y2="16" stroke="#3b82f6" stroke-opacity="0.7" stroke-width="1.5" stroke-linecap="round"/>
9
+ <polygon points="36,8 33,16 36,14 39,16" fill="#ef4444"/>
10
+ <polygon points="36,24 33,16 36,18 39,16" fill="#64748b"/>
10
11
  <!-- Dock pill -->
11
- <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"/>
12
+ <rect x="3" y="44" width="66" height="22" rx="11" fill="#3b82f6" fill-opacity="0.15" stroke="#3b82f6" stroke-width="1.5"/>
12
13
  <!-- Dock icons - 3 squares in the pill -->
13
- <rect x="14" y="51" width="10" height="10" rx="2.5" fill="#3b82f6" opacity="0.9"/>
14
- <rect x="31" y="51" width="10" height="10" rx="2.5" fill="#10b981" opacity="0.9"/>
15
- <rect x="48" y="51" width="10" height="10" rx="2.5" fill="#f59e0b" opacity="0.9"/>
14
+ <rect x="9" y="49" width="12" height="12" rx="3" fill="#3b82f6"/>
15
+ <rect x="30" y="49" width="12" height="12" rx="3" fill="#10b981"/>
16
+ <rect x="51" y="49" width="12" height="12" rx="3" fill="#f59e0b"/>
16
17
  <!-- Middle icon magnified (popping up) -->
17
- <rect x="28" y="34" width="16" height="16" rx="3.5" fill="#10b981" opacity="0.95"/>
18
+ <rect x="27" y="29" width="18" height="18" rx="4.5" fill="#10b981"/>
18
19
  <!-- Active dot under middle icon -->
19
- <circle cx="36" cy="66" r="1.5" fill="#ffffff" fill-opacity="0.8"/>
20
- <!-- Compass rose hint -->
21
- <circle cx="36" cy="22" r="10" fill="none" stroke="#ffffff" stroke-opacity="0.15" stroke-width="1"/>
22
- <line x1="36" y1="14" x2="36" y2="18" stroke="#ffffff" stroke-opacity="0.3" stroke-width="1" stroke-linecap="round"/>
23
- <line x1="36" y1="26" x2="36" y2="30" stroke="#ffffff" stroke-opacity="0.15" stroke-width="1" stroke-linecap="round"/>
24
- <line x1="28" y1="22" x2="32" y2="22" stroke="#ffffff" stroke-opacity="0.15" stroke-width="1" stroke-linecap="round"/>
25
- <line x1="40" y1="22" x2="44" y2="22" stroke="#ffffff" stroke-opacity="0.15" stroke-width="1" stroke-linecap="round"/>
26
- <!-- Compass needle -->
27
- <polygon points="36,15 34,22 36,20 38,22" fill="#ef4444" fill-opacity="0.7"/>
28
- <polygon points="36,29 34,22 36,24 38,22" fill="#ffffff" fill-opacity="0.25"/>
20
+ <circle cx="36" cy="69.5" r="2" fill="#3b82f6"/>
29
21
  </svg>
package/public/dock.js CHANGED
@@ -614,6 +614,18 @@
614
614
  }
615
615
 
616
616
  // ─── Switch to app ────────────────────────────────────────────────────────────
617
+ // The server's admin UI leads anywhere: into a webapp, a plugin's page or
618
+ // another of its own screens. Its tile opens it fresh every time, at the
619
+ // URL the tile points to, so it never resumes wherever it was left.
620
+ function opensFresh(app) {
621
+ try {
622
+ const url = new URL(app.url, window.location.href)
623
+ return url.origin === window.location.origin && /^\/admin(\/|$)/.test(url.pathname)
624
+ } catch {
625
+ return false
626
+ }
627
+ }
628
+
617
629
  function switchToApp(index) {
618
630
  const app = cfg.apps[index]
619
631
  if (!app) return
@@ -626,7 +638,8 @@
626
638
  el.classList.toggle('active', el.dataset.index === String(index))
627
639
  })
628
640
 
629
- const alreadyLoaded = !!iframes[app.url]
641
+ const fresh = opensFresh(app)
642
+ const alreadyLoaded = !fresh && !!iframes[app.url]
630
643
 
631
644
  if (cfg.iframeMode === 'destroy') {
632
645
  $iframeContainer.innerHTML = ''
@@ -635,6 +648,11 @@
635
648
  Object.values(iframes).forEach((f) => f.classList.remove('active'))
636
649
  }
637
650
 
651
+ if (fresh && iframes[app.url]) {
652
+ iframes[app.url].remove()
653
+ delete iframes[app.url]
654
+ }
655
+
638
656
  if (!iframes[app.url]) {
639
657
  if (!alreadyLoaded) showLoading(app.label)
640
658