docs(aio): add NOTES
This commit is contained in:
parent
93c0ab7131
commit
c2e672cd1c
|
@ -0,0 +1,159 @@
|
||||||
|
# Design Notes
|
||||||
|
|
||||||
|
## Application State
|
||||||
|
|
||||||
|
Apart from loading up the navigation and search data, there is only one significant state in the app, which is the document being viewed.
|
||||||
|
Other state, such as highlighting the current navigation items and bread crumbs can be derived from that state.
|
||||||
|
The simplest indication of this state is the current `Location#path`, which acts as the single point of truth in the application.
|
||||||
|
|
||||||
|
* The document to display is computed from the `path`.
|
||||||
|
* Navigation to display different documents is achieved by updating the `path`.
|
||||||
|
* Whether a navigation item should be highlighted as active is computed from the `path`
|
||||||
|
|
||||||
|
Navigation between documents can be achieved through changes to the `Location`.
|
||||||
|
|
||||||
|
## Concepts
|
||||||
|
|
||||||
|
There are three main concepts in the application: documents, navigation and search.
|
||||||
|
|
||||||
|
* The document data includes the contents of the document for rendering.
|
||||||
|
* The search data includes keywords used for building the search index.
|
||||||
|
* The navigation data contains information about the visual trees that can be rendered in the app to navigate to the documents.
|
||||||
|
|
||||||
|
### Documents
|
||||||
|
|
||||||
|
Information about documents to be displayed are provided as data that can be fetched from the server.
|
||||||
|
There are two parts to the data for each document: `DocumentContents`.
|
||||||
|
|
||||||
|
* `DocumentContents` contains the actual document that will be rendered. This can be loaded (and then cached) lazily only when the document is to be viewed.
|
||||||
|
|
||||||
|
Each document is uniquely identified by the `path` that is also used to fetch its `DocumentContents`.
|
||||||
|
The `DocumentContents` are stored in JSON files on the server. They are loaded lazily on demand and then cached.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface DocumentContents {
|
||||||
|
title: string;
|
||||||
|
contents: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type DocumentContentsJSONFile = Array<DocumentContents>;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Navigation
|
||||||
|
|
||||||
|
Within an application there can be multiple navigational views for displaying links to documents.
|
||||||
|
For example, there might be views for the top level `Toolbar` and for the more detailed `SideBar` navigation.
|
||||||
|
|
||||||
|
Each view is represented as a tree of `NavigationNode`s. Each `NavigationNode` may, optionally, have a `url`, a `path` and `children`.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface NavigationNode {
|
||||||
|
title: string;
|
||||||
|
url?: string;
|
||||||
|
path?: string;
|
||||||
|
tooltip?: string;
|
||||||
|
target?: string;
|
||||||
|
children?: NavigationNode[];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `url` property represents a link to an external url outside of the app.
|
||||||
|
The `path` property identifies the document to display for this navigation `url`. It is used both as the URL segment in the browser and in the request to fetch the document contents.
|
||||||
|
It is not valid to have both `url` and `path` properties on a single node.
|
||||||
|
If neither `url` nor `path` properties are then the node is a pure container, in which case it ought to have
|
||||||
|
|
||||||
|
The `NavigationNode` data is stored in a JSON file that is fetched from the server at startup
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface NavigationViews {
|
||||||
|
[name: string]: NavigationNode;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The mapping of a URL back to `NavigationNode` is computed by inverting all the `NavigationNode` structures to produce a `NavigationMap` of URL to node.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface NavigationMap {
|
||||||
|
[url: string]: NavigationMapItem
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Each `NavigationMapItem` contains information for updating the current navigation views and also caches the `DocumentContents` once it has been loaded.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface NavigationMapItem {
|
||||||
|
node: NavigationNode;
|
||||||
|
parents: NavigationNode[];
|
||||||
|
document?: DocumentContents;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Search
|
||||||
|
|
||||||
|
The `SearchTerms` are stored in a single JSON file that is loaded by the search WebWorker at startup and used to generate the search index.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface SearchTerms {
|
||||||
|
url: string;
|
||||||
|
title: string;
|
||||||
|
body: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type SearchTermsJSONFile = Array<SearchTerms>;
|
||||||
|
```
|
||||||
|
|
||||||
|
## LocationService
|
||||||
|
|
||||||
|
Since the core Angular `Location` service does not expose a subject, nor emits events when the location is changed programmatically,
|
||||||
|
we have our own `LocationService` that does this for us.
|
||||||
|
|
||||||
|
```
|
||||||
|
export class LocationService {
|
||||||
|
currentUrl: Observable<string>;
|
||||||
|
go(url: string): void
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can subscribe to the `currentUrl` to be updated when location changes occur.
|
||||||
|
You should navigate to new documents by calling `go`.
|
||||||
|
|
||||||
|
## DocumentService
|
||||||
|
|
||||||
|
The `DocumentService` is responsible for monitoring the `LocationService.currentUrl` and updating the `currentDocument`.
|
||||||
|
When the `currentUrl` changes, the `DocumentService` will fetch the `DocumentContents` from the server if necessary and cache it for the future.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export class DocumentService {
|
||||||
|
currentDocument: Observable<DocumentContents>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The mapping of URL path to the path to fetch the document contents is simply:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
private computePath(url) {
|
||||||
|
url = url.startsWith('/') ? url : '/' + url;
|
||||||
|
return 'content/docs' + url + '.json';
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## NavigationService
|
||||||
|
|
||||||
|
The `NavigationService` is responsible for:
|
||||||
|
|
||||||
|
* fetching and exposing the `NavigationViews` for use in displaying navigation UI.
|
||||||
|
* building the `NavigationMap` from the `NavigationNode` data.
|
||||||
|
* updating observables for the currently active `NavigationNode`s that can be used to render the navigation UI
|
||||||
|
when the `LocationService.currentUrl` changes.
|
||||||
|
|
||||||
|
|
||||||
|
```ts
|
||||||
|
class NavigationService {
|
||||||
|
navigationViews: Observable<NavigationViews>;
|
||||||
|
currentNode: Observable<NavigationNode>;
|
||||||
|
activeNodes: Observable<NavigationNode[]>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
Loading…
Reference in New Issue