Skip to content

Commit a163d7f

Browse files
committed
Dev improvements
1 parent 0e0541c commit a163d7f

File tree

13 files changed

+379
-140
lines changed

13 files changed

+379
-140
lines changed

FEEDBACK.md

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,75 @@
1-
1. useStorage should be exported for plugin authors
1+
1. Plugins can't register their own UI
22

3-
The recordings plugin has ~20 lines of boilerplate for storageKey(), loadStorage(), saveStorage() — reimplementing
4-
the navigator*{namespace}*{instanceId} convention that useStorage already handles internally. If useStorage were
5-
exported (like useUI and getMapInstance), the plugin shrinks significantly and the key convention stays
6-
consistent.
3+
This is the biggest one. The Recordings feature requires three separate wiring points in the consumer's create()
4+
call:
75

8-
2. Export a useMap() composable
6+
Navigator.create({
7+
buttons: [{ id: 'record', component: RecordButton, panel: { component: RecordingsPanel } }],
8+
plugins: [RecordingsPlugin],
9+
})
910

10-
Components currently need two steps: inject('navigatorId') → getMapInstance(id). A useMap() composable that
11-
resolves both internally would be more Vue-idiomatic and less error-prone. The internal composable already exists
12-
— it just needs an external-facing export.
11+
The plugin manages all state, persistence, and map layers — but it can't declare its own button or panel. A
12+
self-contained plugin API would let you distribute a feature as a single import:
1313

14-
3. Document the @vitejs/plugin-vue prerequisite
14+
// Hypothetical: plugin registers everything itself
15+
plugins: [RecordingsPlugin]
1516

16-
The feature example shows .vue SFC files but doesn't mention that consumers need @vitejs/plugin-vue in their Vite
17-
config. This was a build-breaking blocker with no clear error message. A note in the extending docs (or a Vite
18-
plugin preset) would prevent this.
17+
The install() context could expose something like addButton() / addPanel() so a plugin can register its own UI
18+
components without the consumer manually wiring buttons config.
1919

20-
4. Document available SVG sprite icons
20+
---
2121

22-
RecordButton.vue uses <use href="#record-btn-fill" /> — but there's no list of available icon names anywhere.
23-
Plugin authors are guessing. A simple icon reference (even just a list) in the docs would help.
22+
2. useUI docs contradict the actual API
2423

25-
5. Add once to the plugin context
24+
The internal docs (4.ui.md) describe openPanel(id, component) and togglePanel(id, component) — taking an id and
25+
component as parameters. But the actual exported useUI has:
2626

27-
NavigatorInstance exposes once(), but the plugin install context only gets on/off/emit. Plugins that need one-time
28-
setup (like map:ready) would benefit from once too.
27+
- openPanel() — no parameters, just opens the panel
28+
- setActivePanel(id) — separate function to set which tab is active
2929

30-
6. Add a plugin cleanup lifecycle
30+
The extending docs (8.extending.md) correctly show setActivePanel + openPanel as separate calls. The 4.ui.md docs
31+
should be updated to match.
3132

32-
There's no destroy/teardown hook for plugins. If the instance is unmounted, plugins can't clean up timers,
33-
geolocation watches, or map layers. A on('destroy', fn) event or a return-value convention (install returns a
34-
cleanup function) would prevent leaks.
33+
---
3534

36-
7. Minimum version annotations in docs
35+
3. app.provide() boilerplate in plugins
3736

38-
useUI was added in 1.0.20, but the feature docs referenced it while the package was at 1.0.19. Adding @since
39-
annotations to the API tables would save debugging time.
37+
Every plugin that shares state with Vue components must manually call app.provide('key', ...) and every component
38+
must inject('key'). The plugin context could offer a shorthand:
39+
40+
// Current — manual provide
41+
install({ app }) {
42+
app.provide('recordings', { state, start, pause, ... });
43+
}
44+
45+
// Possible — context.provide() shorthand
46+
install({ provide }) {
47+
provide('recordings', { state, start, pause, ... });
48+
}
49+
50+
Minor, but it reinforces the pattern and makes plugins feel less like they're reaching into Vue internals.
51+
52+
---
53+
54+
4. Per-instance plugins don't receive options
55+
56+
Navigator.use(plugin, options) passes options as the second argument to install(), but per-instance plugins in the
57+
plugins array don't:
58+
59+
// Global — options work
60+
Navigator.use(RecordingsPlugin, { maxDuration: 3600 });
61+
62+
// Per-instance — no options mechanism
63+
plugins: [RecordingsPlugin] // install() gets context only
64+
65+
Supporting plugins: [{ plugin: RecordingsPlugin, options: { ... } }] (or a tuple syntax) would make per-instance
66+
plugins configurable without needing factory functions.
67+
68+
---
69+
70+
5. @vitejs/plugin-vue is a hidden prerequisite
71+
72+
The docs recommend Vue SFCs as the "preferred" approach for buttons and panels, but @vitejs/plugin-vue isn't
73+
mentioned until the very bottom of the extending docs. A consumer following the example will get an opaque Vite
74+
transform error. Options: surface this earlier in the docs, or detect the missing plugin at build time with a
75+
helpful error message.
-130 Bytes
Loading
-24 Bytes
Loading

docs/dev/1.config.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,12 +332,16 @@ See [Extending — Custom Panels](./8.extending.md#custom-panels) for more detai
332332

333333
**Type:** `array` **Default:** `[]`
334334

335-
Installs per-instance plugins. Each plugin is an object with an `install` method:
335+
Installs per-instance plugins. Each entry can be a plugin object, a `[plugin, options]` tuple, or a `{ plugin, options }` object:
336336

337337
```js
338338
Navigator.create({
339339
id: "my-map",
340-
plugins: [MyPlugin],
340+
plugins: [
341+
MyPlugin, // no options
342+
[RecordingsPlugin, { maxDuration: 3600 }], // tuple syntax
343+
{ plugin: AnalyticsPlugin, options: { id: 'X' } }, // object syntax
344+
],
341345
}).mount();
342346
```
343347

docs/dev/4.ui.md

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Call `useUI()` from any component's `setup` to access state and actions. State i
1515
```js
1616
import { useUI } from '@/composables/useUI';
1717

18-
const { isDesktop, isPanelVisible, openPanel, togglePanel } = useUI();
18+
const { isDesktop, isPanelVisible, setActivePanel, openPanel } = useUI();
1919
```
2020

2121
### Responsive breakpoints
@@ -34,33 +34,41 @@ On resize, `isNavVisible` is automatically managed: it is forced `true` on deskt
3434

3535
### Panel
3636

37-
The side panel displays a single active Vue component at a time. Features open the panel by passing their panel component to `openPanel` or `togglePanel`.
37+
The side panel displays a single active tab at a time. Use `setActivePanel(id)` to switch tabs and `openPanel()` to show the panel.
3838

39-
#### `openPanel(id, component)`
39+
#### `setActivePanel(id)`
4040

41-
Opens the panel with the given component. Closes the mobile nav if open.
41+
Switches the active panel tab and emits a `panel:change` event.
4242

4343
```js
44-
import MyPanel from '@/components/panels/my-feature.vue';
44+
setActivePanel('settings');
45+
```
46+
47+
#### `openPanel()`
4548

46-
openPanel('my-feature', MyPanel);
49+
Opens the panel. Closes the mobile nav if open.
50+
51+
```js
52+
// Switch to a specific tab and open the panel
53+
setActivePanel('my-feature');
54+
openPanel();
4755
```
4856

49-
#### `togglePanel(id, component)`
57+
#### `togglePanel()`
5058

51-
Toggles the panel for the given id:
52-
- If the panel is already open with the same id, it is closed.
53-
- If a different id is provided, the panel switches to the new component.
59+
Toggles the panel open/closed:
60+
- If the panel is open, it is closed.
61+
- If the panel is closed, it opens.
5462
- On mobile, always opens (never toggles closed).
5563

5664
```js
5765
// Typically called from a top-bar button
58-
togglePanel('my-feature', MyPanel);
66+
togglePanel();
5967
```
6068

6169
#### `closePanel()`
6270

63-
Closes the panel without changing the active component.
71+
Closes the panel without changing the active tab.
6472

6573
![Desktop panel open on returning visit](../../assets/screenshots/docs/ui/panel.png)
6674

@@ -75,9 +83,9 @@ Closes the panel without changing the active component.
7583
| `isNavExpanded` | `boolean` | Whether the nav is in expanded mode |
7684
| `isPanelVisible` | `boolean` | Whether the side panel is open |
7785
| `isPanelExpanded` | `boolean` | Whether the panel is in expanded mode |
78-
| `activePanelId` | `string \| null` | The id of the currently active panel |
79-
| `activePanelComponent` | `Component \| null` | The Vue component rendered in the panel |
80-
| `activeMenuSub` | `string` | The active sub-panel within the menu (`'location'`, `'settings'`, `'about'`, `'privacy'`) |
86+
| `activePanel` | `string` | The id of the currently active panel tab (default: `'view'`) |
87+
| `isFirstLoad` | `boolean` | Whether this is the user's first visit (no persisted view) |
88+
| `showAboutModal` | `boolean` | Whether the About modal is visible |
8189

8290
#### Computed
8391

@@ -91,15 +99,18 @@ Closes the panel without changing the active component.
9199

92100
| Name | Signature | Description |
93101
|------|-----------|-------------|
94-
| `openPanel` | `(id, component)` | Open panel with given component |
95-
| `togglePanel` | `(id, component)` | Toggle panel open/closed or switch component |
102+
| `setActivePanel` | `(id)` | Switch active panel tab, emits `panel:change` |
103+
| `openPanel` | `()` | Open panel, close mobile nav |
104+
| `togglePanel` | `()` | Toggle panel open/closed |
96105
| `closePanel` | `()` | Close the panel |
97106
| `togglePanelExpanded` | `()` | Toggle panel expanded state |
98107
| `setPanelExpanded` | `(value)` | Set panel expanded state directly |
99-
| `setMenuSub` | `(id)` | Switch the active menu sub-panel (`'location'`, `'settings'`, `'about'`, `'privacy'`) |
100108
| `toggleNav` | `()` | Toggle navigation sidebar |
101109
| `closeNav` | `()` | Close navigation sidebar |
102110
| `setNavExpanded` | `(value)` | Set nav expanded state directly |
111+
| `setFirstLoadComplete` | `()` | Mark first load as done |
112+
| `openAboutModal` | `()` | Show the About modal |
113+
| `closeAboutModal` | `()` | Hide the About modal (also completes first load) |
103114

104115
---
105116

0 commit comments

Comments
 (0)