react-cheminfo 0.18.0 → 0.20.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.
Files changed (108) hide show
  1. package/lib/about/core/about.d.ts +15 -4
  2. package/lib/about/core/about.d.ts.map +1 -1
  3. package/lib/about/core/about.js +8 -1
  4. package/lib/about/core/about.js.map +1 -1
  5. package/lib/about/core/index.d.ts +1 -0
  6. package/lib/about/core/index.d.ts.map +1 -1
  7. package/lib/about/core/index.js +1 -0
  8. package/lib/about/core/index.js.map +1 -1
  9. package/lib/about/core/repository.d.ts +14 -0
  10. package/lib/about/core/repository.d.ts.map +1 -0
  11. package/lib/about/core/repository.js +21 -0
  12. package/lib/about/core/repository.js.map +1 -0
  13. package/lib/about/ui/AboutBuild.d.ts +5 -4
  14. package/lib/about/ui/AboutBuild.d.ts.map +1 -1
  15. package/lib/about/ui/AboutBuild.js +10 -10
  16. package/lib/about/ui/AboutBuild.js.map +1 -1
  17. package/lib/about/ui/AboutPage.d.ts.map +1 -1
  18. package/lib/about/ui/AboutPage.js +7 -8
  19. package/lib/about/ui/AboutPage.js.map +1 -1
  20. package/lib/about/ui/AboutVersion.d.ts +26 -0
  21. package/lib/about/ui/AboutVersion.d.ts.map +1 -0
  22. package/lib/about/ui/AboutVersion.js +54 -0
  23. package/lib/about/ui/AboutVersion.js.map +1 -0
  24. package/lib/about/ui/index.d.ts +2 -0
  25. package/lib/about/ui/index.d.ts.map +1 -1
  26. package/lib/about/ui/index.js +1 -0
  27. package/lib/about/ui/index.js.map +1 -1
  28. package/lib/build/core/buildInfo.d.ts +44 -0
  29. package/lib/build/core/buildInfo.d.ts.map +1 -1
  30. package/lib/build/core/buildInfo.js +63 -0
  31. package/lib/build/core/buildInfo.js.map +1 -1
  32. package/lib/build/core/index.d.ts +1 -1
  33. package/lib/build/core/index.d.ts.map +1 -1
  34. package/lib/build/core/index.js +1 -1
  35. package/lib/build/core/index.js.map +1 -1
  36. package/lib/build/vite/buildInfo.d.ts.map +1 -1
  37. package/lib/build/vite/buildInfo.js +2 -2
  38. package/lib/build/vite/buildInfo.js.map +1 -1
  39. package/lib/ecosystem/core/sites.d.ts.map +1 -1
  40. package/lib/ecosystem/core/sites.js +12 -0
  41. package/lib/ecosystem/core/sites.js.map +1 -1
  42. package/lib/ecosystem/core/types.d.ts +8 -0
  43. package/lib/ecosystem/core/types.d.ts.map +1 -1
  44. package/lib/molecule3d/core/camera.d.ts +89 -0
  45. package/lib/molecule3d/core/camera.d.ts.map +1 -0
  46. package/lib/molecule3d/core/camera.js +172 -0
  47. package/lib/molecule3d/core/camera.js.map +1 -0
  48. package/lib/molecule3d/core/index.d.ts +2 -0
  49. package/lib/molecule3d/core/index.d.ts.map +1 -1
  50. package/lib/molecule3d/core/index.js +1 -0
  51. package/lib/molecule3d/core/index.js.map +1 -1
  52. package/lib/molecule3d/ui/MoleculeCanvas3D.d.ts.map +1 -1
  53. package/lib/molecule3d/ui/MoleculeCanvas3D.js +14 -37
  54. package/lib/molecule3d/ui/MoleculeCanvas3D.js.map +1 -1
  55. package/lib/molecule3d/ui/camera.d.ts +35 -2
  56. package/lib/molecule3d/ui/camera.d.ts.map +1 -1
  57. package/lib/molecule3d/ui/camera.js +113 -4
  58. package/lib/molecule3d/ui/camera.js.map +1 -1
  59. package/lib/molecule3d/ui/captureScene.d.ts +14 -0
  60. package/lib/molecule3d/ui/captureScene.d.ts.map +1 -0
  61. package/lib/molecule3d/ui/captureScene.js +24 -0
  62. package/lib/molecule3d/ui/captureScene.js.map +1 -0
  63. package/lib/molecule3d/ui/createViewer.d.ts +18 -0
  64. package/lib/molecule3d/ui/createViewer.d.ts.map +1 -0
  65. package/lib/molecule3d/ui/createViewer.js +19 -0
  66. package/lib/molecule3d/ui/createViewer.js.map +1 -0
  67. package/lib/molecule3d/ui/moleculeViewer3DProps.d.ts +21 -0
  68. package/lib/molecule3d/ui/moleculeViewer3DProps.d.ts.map +1 -1
  69. package/lib/molecule3d/ui/useMoleculeScene.d.ts +47 -0
  70. package/lib/molecule3d/ui/useMoleculeScene.d.ts.map +1 -0
  71. package/lib/molecule3d/ui/useMoleculeScene.js +82 -0
  72. package/lib/molecule3d/ui/useMoleculeScene.js.map +1 -0
  73. package/lib/molecule3d/ui/useSharedCamera.d.ts +52 -0
  74. package/lib/molecule3d/ui/useSharedCamera.d.ts.map +1 -0
  75. package/lib/molecule3d/ui/useSharedCamera.js +82 -0
  76. package/lib/molecule3d/ui/useSharedCamera.js.map +1 -0
  77. package/lib/molecule3d/ui/viewer.d.ts +21 -15
  78. package/lib/molecule3d/ui/viewer.d.ts.map +1 -1
  79. package/lib/molecule3d/ui/viewer.js +41 -47
  80. package/lib/molecule3d/ui/viewer.js.map +1 -1
  81. package/lib/molecule3d/ui/viewerSpec.d.ts +17 -0
  82. package/lib/molecule3d/ui/viewerSpec.d.ts.map +1 -0
  83. package/lib/molecule3d/ui/viewerSpec.js +34 -0
  84. package/lib/molecule3d/ui/viewerSpec.js.map +1 -0
  85. package/package.json +1 -1
  86. package/src/about/core/about.ts +25 -5
  87. package/src/about/core/index.ts +1 -0
  88. package/src/about/core/repository.ts +22 -0
  89. package/src/about/ui/AboutBuild.tsx +13 -20
  90. package/src/about/ui/AboutPage.tsx +42 -28
  91. package/src/about/ui/AboutVersion.tsx +95 -0
  92. package/src/about/ui/index.ts +2 -0
  93. package/src/build/core/buildInfo.ts +67 -0
  94. package/src/build/core/index.ts +9 -1
  95. package/src/build/vite/buildInfo.ts +2 -2
  96. package/src/ecosystem/core/sites.ts +12 -0
  97. package/src/ecosystem/core/types.ts +8 -0
  98. package/src/molecule3d/core/camera.ts +212 -0
  99. package/src/molecule3d/core/index.ts +14 -0
  100. package/src/molecule3d/ui/MoleculeCanvas3D.tsx +14 -43
  101. package/src/molecule3d/ui/camera.ts +128 -7
  102. package/src/molecule3d/ui/captureScene.ts +31 -0
  103. package/src/molecule3d/ui/createViewer.ts +24 -0
  104. package/src/molecule3d/ui/moleculeViewer3DProps.ts +21 -0
  105. package/src/molecule3d/ui/useMoleculeScene.ts +141 -0
  106. package/src/molecule3d/ui/useSharedCamera.ts +121 -0
  107. package/src/molecule3d/ui/viewer.ts +45 -50
  108. package/src/molecule3d/ui/viewerSpec.ts +38 -0
@@ -1,25 +1,17 @@
1
1
  /**
2
- * Lifecycle of one molstar molecule viewer.
2
+ * Lifecycle of one molstar molecule viewer: `createMolecule3DViewer` builds
3
+ * one, and every operation a component performs on it is a method here.
3
4
  *
4
- * `createMolecule3DViewer` is **synchronous** on purpose. React 19 runs an
5
- * effect, its cleanup and the effect again on every mount in development, so an
6
- * awaited constructor hands the cleanup nothing to dispose and leaks a WebGL
7
- * context per mount. Returning the handle immediately means `dispose()` can
8
- * always be called; the work is queued behind `ready`.
9
- *
10
- * molstar's own UI is not mounted: every control is the component's.
5
+ * The constructor returns before the canvas exists — see `createViewer.ts` —
6
+ * so every method queues its work behind `ready` and resolves to nothing once
7
+ * the viewer has been disposed. molstar's own UI is not mounted: every control
8
+ * is the component's.
11
9
  */
10
+ import type { Molecule3DCamera } from '../core/camera.ts';
12
11
  import type { ImageSize } from '../core/exportImage.ts';
13
12
  import type { Measurement, MeasurementKind } from '../core/measurement.ts';
14
13
  import type { Molecule3DFile } from '../core/settings.ts';
15
14
  import type { Molecule3DViewerOptions, MoleculeStyle, SurfaceStyle } from './viewerTypes.ts';
16
- /**
17
- * Create a viewer inside `container` and start initialising it.
18
- * @param container - A positioned element; molstar inserts its canvas into it.
19
- * @param options - See {@link Molecule3DViewerOptions}.
20
- * @returns A handle that is safe to dispose immediately.
21
- */
22
- export declare function createMolecule3DViewer(container: HTMLElement, options?: Molecule3DViewerOptions): Molecule3DViewer;
23
15
  /**
24
16
  * One molstar canvas, and every operation the component performs on it. Every
25
17
  * method resolves to nothing once `dispose` has been called.
@@ -85,6 +77,20 @@ export declare class Molecule3DViewer {
85
77
  * @returns Nothing; resolves once the move has been ordered.
86
78
  */
87
79
  resetCamera(durationMilliseconds?: number, fromFront?: boolean): Promise<void>;
80
+ /**
81
+ * Put the camera where a link says it stood.
82
+ * @param camera - Where to stand.
83
+ * @param durationMilliseconds - Transition length; 0 jumps.
84
+ * @returns Nothing; resolves once the move has been ordered.
85
+ */
86
+ setCamera(camera: Molecule3DCamera, durationMilliseconds?: number): Promise<void>;
87
+ /**
88
+ * Follow the camera, however it moves.
89
+ * @param listener - Called after every move.
90
+ * @returns A function that stops calling the listener; safe to call before
91
+ * the canvas exists.
92
+ */
93
+ watchCamera(listener: (camera: Molecule3DCamera | null) => void): () => void;
88
94
  /**
89
95
  * Turn the automatic spin on or off.
90
96
  * @param spinning - Whether the scene should keep turning.
@@ -1 +1 @@
1
- {"version":3,"file":"viewer.d.ts","sourceRoot":"","sources":["../../../src/molecule3d/ui/viewer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAe1D,OAAO,KAAK,EACV,uBAAuB,EACvB,aAAa,EACb,YAAY,EACb,MAAM,kBAAkB,CAAC;AAE1B;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,WAAW,EACtB,OAAO,GAAE,uBAA4B,GACpC,gBAAgB,CAElB;AAED;;;GAGG;AACH,qBAAa,gBAAgB;;IAK3B,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9B;;;;OAIG;gBACS,SAAS,EAAE,WAAW,EAAE,OAAO,GAAE,uBAA4B;IAyBzE;;;;;;OAMG;IACH,YAAY,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAO3E;;;OAGG;IACH,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAO7B;;;;OAIG;IACH,WAAW,CAAC,KAAK,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhD;;;OAGG;IACH,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;;;OAIG;IACH,gBAAgB,CAAC,YAAY,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrE;;;;OAIG;IACH,cAAc,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAM3D;;;;;;OAMG;IACH,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAgB1D;;;;;OAKG;IACH,WAAW,CACT,oBAAoB,SAA0B,EAC9C,SAAS,UAAQ,GAChB,OAAO,CAAC,IAAI,CAAC;IAMhB;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,SAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAMrE,kEAAkE;IAClE,YAAY,IAAI,IAAI;IAKpB,sEAAsE;IACtE,OAAO,IAAI,IAAI;CAwBhB"}
1
+ {"version":3,"file":"viewer.d.ts","sourceRoot":"","sources":["../../../src/molecule3d/ui/viewer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAmB1D,OAAO,KAAK,EACV,uBAAuB,EACvB,aAAa,EACb,YAAY,EACb,MAAM,kBAAkB,CAAC;AAE1B;;;GAGG;AACH,qBAAa,gBAAgB;;IAK3B,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9B;;;;OAIG;gBACS,SAAS,EAAE,WAAW,EAAE,OAAO,GAAE,uBAA4B;IAczE;;;;;;OAMG;IACH,YAAY,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAO3E;;;OAGG;IACH,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAO7B;;;;OAIG;IACH,WAAW,CAAC,KAAK,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhD;;;OAGG;IACH,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;;;OAIG;IACH,gBAAgB,CAAC,YAAY,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrE;;;;OAIG;IACH,cAAc,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAM3D;;;;;;OAMG;IACH,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAI1D;;;;;OAKG;IACH,WAAW,CACT,oBAAoB,SAA0B,EAC9C,SAAS,UAAQ,GAChB,OAAO,CAAC,IAAI,CAAC;IAMhB;;;;;OAKG;IACH,SAAS,CAAC,MAAM,EAAE,gBAAgB,EAAE,oBAAoB,SAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAM5E;;;;;OAKG;IACH,WAAW,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,KAAK,IAAI,GAAG,MAAM,IAAI;IAa5E;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,SAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAMrE,kEAAkE;IAClE,YAAY,IAAI,IAAI;IAKpB,sEAAsE;IACtE,OAAO,IAAI,IAAI;CAwBhB"}
@@ -1,31 +1,18 @@
1
1
  /**
2
- * Lifecycle of one molstar molecule viewer.
2
+ * Lifecycle of one molstar molecule viewer: `createMolecule3DViewer` builds
3
+ * one, and every operation a component performs on it is a method here.
3
4
  *
4
- * `createMolecule3DViewer` is **synchronous** on purpose. React 19 runs an
5
- * effect, its cleanup and the effect again on every mount in development, so an
6
- * awaited constructor hands the cleanup nothing to dispose and leaks a WebGL
7
- * context per mount. Returning the handle immediately means `dispose()` can
8
- * always be called; the work is queued behind `ready`.
9
- *
10
- * molstar's own UI is not mounted: every control is the component's.
5
+ * The constructor returns before the canvas exists — see `createViewer.ts` —
6
+ * so every method queues its work behind `ready` and resolves to nothing once
7
+ * the viewer has been disposed. molstar's own UI is not mounted: every control
8
+ * is the component's.
11
9
  */
12
- import { PluginViewModel } from 'molstar/lib/extensions/plugin/view-model.js';
13
- // Lowercased on import: it is a factory, not a constructor.
14
- import { DefaultPluginSpec as defaultPluginSpec } from 'molstar/lib/mol-plugin/spec.js';
15
- import { Color } from 'molstar/lib/mol-util/color/color.js';
16
- import { DEFAULT_CAMERA_DURATION, DEFAULT_SPIN_SPEED, resetCamera, setSpin, } from "./camera.js";
10
+ import { DEFAULT_CAMERA_DURATION, DEFAULT_SPIN_SPEED, applyCamera, resetCamera, setSpin, watchCamera, } from "./camera.js";
11
+ import { captureScene } from "./captureScene.js";
17
12
  import { MeasurementPicker, clearMeasurements, renderMeasurements, } from "./measurements.js";
18
13
  import { clearMolecule, renderMolecule } from "./renderMolecule.js";
19
14
  import { clearSurface, renderSurface } from "./renderSurface.js";
20
- /**
21
- * Create a viewer inside `container` and start initialising it.
22
- * @param container - A positioned element; molstar inserts its canvas into it.
23
- * @param options - See {@link Molecule3DViewerOptions}.
24
- * @returns A handle that is safe to dispose immediately.
25
- */
26
- export function createMolecule3DViewer(container, options = {}) {
27
- return new Molecule3DViewer(container, options);
28
- }
15
+ import { mountMolecule3DPlugin } from "./viewerSpec.js";
29
16
  /**
30
17
  * One molstar canvas, and every operation the component performs on it. Every
31
18
  * method resolves to nothing once `dispose` has been called.
@@ -44,18 +31,7 @@ export class Molecule3DViewer {
44
31
  constructor(container, options = {}) {
45
32
  const { background = '#ffffff', // tokens-ok: a WebGL clear colour
46
33
  onMeasure = ignore, } = options;
47
- const spec = defaultPluginSpec();
48
- this.#model = new PluginViewModel({
49
- spec: {
50
- ...spec,
51
- canvas3d: {
52
- ...spec.canvas3d,
53
- renderer: { backgroundColor: Color.fromHexStyle(background) },
54
- camera: { helper: { axes: { name: 'off', params: {} } } },
55
- },
56
- },
57
- });
58
- this.#model.mount(container);
34
+ this.#model = mountMolecule3DPlugin(container, background);
59
35
  this.ready = this.#model.initialized;
60
36
  // Registered before any `#run`, so the picker exists by the time one runs.
61
37
  this.ready.then(() => {
@@ -128,19 +104,7 @@ export class Molecule3DViewer {
128
104
  * @throws {Error} When the plugin has no screenshot helper.
129
105
  */
130
106
  captureImage(size) {
131
- return this.#run(async (plugin) => {
132
- const helper = plugin.helpers.viewportScreenshot;
133
- if (helper === undefined) {
134
- throw new Error('This viewer cannot take a picture of its scene.');
135
- }
136
- helper.behaviors.values.next({
137
- ...helper.values,
138
- resolution: { name: 'custom', params: size },
139
- axes: { name: 'off', params: {} },
140
- transparent: false,
141
- });
142
- return helper.getImageDataUri();
143
- });
107
+ return this.#run((plugin) => captureScene(plugin, size));
144
108
  }
145
109
  /**
146
110
  * Frame everything on screen.
@@ -153,6 +117,36 @@ export class Molecule3DViewer {
153
117
  resetCamera(plugin, durationMilliseconds, fromFront);
154
118
  });
155
119
  }
120
+ /**
121
+ * Put the camera where a link says it stood.
122
+ * @param camera - Where to stand.
123
+ * @param durationMilliseconds - Transition length; 0 jumps.
124
+ * @returns Nothing; resolves once the move has been ordered.
125
+ */
126
+ setCamera(camera, durationMilliseconds = 0) {
127
+ return this.#run((plugin) => {
128
+ applyCamera(plugin, camera, durationMilliseconds);
129
+ });
130
+ }
131
+ /**
132
+ * Follow the camera, however it moves.
133
+ * @param listener - Called after every move.
134
+ * @returns A function that stops calling the listener; safe to call before
135
+ * the canvas exists.
136
+ */
137
+ watchCamera(listener) {
138
+ let stop = null;
139
+ let cancelled = false;
140
+ void this.#run((plugin) => {
141
+ if (!cancelled)
142
+ stop = watchCamera(plugin, listener);
143
+ });
144
+ return () => {
145
+ cancelled = true;
146
+ stop?.();
147
+ stop = null;
148
+ };
149
+ }
156
150
  /**
157
151
  * Turn the automatic spin on or off.
158
152
  * @param spinning - Whether the scene should keep turning.
@@ -1 +1 @@
1
- {"version":3,"file":"viewer.js","sourceRoot":"","sources":["../../../src/molecule3d/ui/viewer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"viewer.js","sourceRoot":"","sources":["../../../src/molecule3d/ui/viewer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAUH,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,WAAW,EACX,WAAW,EACX,OAAO,EACP,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAOxD;;;GAGG;AACH,MAAM,OAAO,gBAAgB;IAClB,MAAM,CAAkB;IACjC,OAAO,CAAgC;IACvC,SAAS,GAAG,KAAK,CAAC;IAElB,0EAA0E;IACjE,KAAK,CAAgB;IAE9B;;;;OAIG;IACH,YAAY,SAAsB,EAAE,UAAmC,EAAE;QACvE,MAAM,EACJ,UAAU,GAAG,SAAS,EAAE,kCAAkC;QAC1D,SAAS,GAAG,MAAM,GACnB,GAAG,OAAO,CAAC;QACZ,IAAI,CAAC,MAAM,GAAG,qBAAqB,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QAC3D,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QACrC,2EAA2E;QAC3E,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE;YACnB,IAAI,IAAI,CAAC,SAAS;gBAAE,OAAO;YAC3B,IAAI,CAAC,OAAO,GAAG,IAAI,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACtE,CAAC,EAAE,MAAM,CAAC,CAAC;IACb,CAAC;IAED;;;;;;OAMG;IACH,YAAY,CAAC,OAAuB,EAAE,KAAqB;QACzD,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YAChC,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;YAChC,MAAM,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YAChC,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;YAChC,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,WAAW,CAAC,KAAoB;QAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED;;;OAGG;IACH,WAAW;QACT,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;IACrD,CAAC;IAED;;;;OAIG;IACH,gBAAgB,CAAC,YAAoC;QACnD,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,kBAAkB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IACzE,CAAC;IAED;;;;OAIG;IACH,cAAc,CAAC,IAA4B;QACzC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;YACpB,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACH,YAAY,CAAC,IAAe;QAC1B,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED;;;;;OAKG;IACH,WAAW,CACT,oBAAoB,GAAG,uBAAuB,EAC9C,SAAS,GAAG,KAAK;QAEjB,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YAC1B,WAAW,CAAC,MAAM,EAAE,oBAAoB,EAAE,SAAS,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACH,SAAS,CAAC,MAAwB,EAAE,oBAAoB,GAAG,CAAC;QAC1D,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YAC1B,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,oBAAoB,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACH,WAAW,CAAC,QAAmD;QAC7D,IAAI,IAAI,GAAwB,IAAI,CAAC;QACrC,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACxB,IAAI,CAAC,SAAS;gBAAE,IAAI,GAAG,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;QACH,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;YACjB,IAAI,EAAE,EAAE,CAAC;YACT,IAAI,GAAG,IAAI,CAAC;QACd,CAAC,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,OAAO,CAAC,QAAiB,EAAE,KAAK,GAAG,kBAAkB;QACnD,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YAC1B,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,kEAAkE;IAClE,YAAY;QACV,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO;QAC3B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;IACpC,CAAC;IAED,sEAAsE;IACtE,OAAO;QACL,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO;QAC3B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC;QACxB,KAAK,IAAI,CAAC,KAAK;aACZ,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC;aACtB,IAAI,CAAC,GAAG,EAAE;YACT,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAC/B,CAAC,CAAC,CAAC;IACP,CAAC;IAED,KAAK,CAAC,IAAI,CACR,MAA2D;QAE3D,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO,SAAS,CAAC;QACrC,MAAM,IAAI,CAAC,KAAK,CAAC;QACjB,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO,SAAS,CAAC;QACrC,IAAI,CAAC;YACH,OAAO,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,IAAI,CAAC,SAAS;gBAAE,OAAO,SAAS,CAAC;YACrC,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF;AAED,SAAS,MAAM;IACb,iBAAiB;AACnB,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * How the molecule viewer configures molstar: the plugin spec it mounts with.
3
+ *
4
+ * molstar's own UI is not mounted — every control is the component's — and the
5
+ * axes helper is off, since a molecule is read from its own shape rather than
6
+ * from the world axes.
7
+ */
8
+ import { PluginViewModel } from 'molstar/lib/extensions/plugin/view-model.js';
9
+ /**
10
+ * Build a view model for one canvas and mount it.
11
+ * @param container - A positioned element; molstar inserts its canvas into it.
12
+ * @param background - Scene background as `#rrggbb`; a WebGL clear colour, so
13
+ * it cannot be a CSS custom property.
14
+ * @returns The mounted view model, still initialising.
15
+ */
16
+ export declare function mountMolecule3DPlugin(container: HTMLElement, background: string): PluginViewModel;
17
+ //# sourceMappingURL=viewerSpec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewerSpec.d.ts","sourceRoot":"","sources":["../../../src/molecule3d/ui/viewerSpec.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AAK9E;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,WAAW,EACtB,UAAU,EAAE,MAAM,GACjB,eAAe,CAcjB"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * How the molecule viewer configures molstar: the plugin spec it mounts with.
3
+ *
4
+ * molstar's own UI is not mounted — every control is the component's — and the
5
+ * axes helper is off, since a molecule is read from its own shape rather than
6
+ * from the world axes.
7
+ */
8
+ import { PluginViewModel } from 'molstar/lib/extensions/plugin/view-model.js';
9
+ // Lowercased on import: it is a factory, not a constructor.
10
+ import { DefaultPluginSpec as defaultPluginSpec } from 'molstar/lib/mol-plugin/spec.js';
11
+ import { Color } from 'molstar/lib/mol-util/color/color.js';
12
+ /**
13
+ * Build a view model for one canvas and mount it.
14
+ * @param container - A positioned element; molstar inserts its canvas into it.
15
+ * @param background - Scene background as `#rrggbb`; a WebGL clear colour, so
16
+ * it cannot be a CSS custom property.
17
+ * @returns The mounted view model, still initialising.
18
+ */
19
+ export function mountMolecule3DPlugin(container, background) {
20
+ const spec = defaultPluginSpec();
21
+ const model = new PluginViewModel({
22
+ spec: {
23
+ ...spec,
24
+ canvas3d: {
25
+ ...spec.canvas3d,
26
+ renderer: { backgroundColor: Color.fromHexStyle(background) },
27
+ camera: { helper: { axes: { name: 'off', params: {} } } },
28
+ },
29
+ },
30
+ });
31
+ model.mount(container);
32
+ return model;
33
+ }
34
+ //# sourceMappingURL=viewerSpec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewerSpec.js","sourceRoot":"","sources":["../../../src/molecule3d/ui/viewerSpec.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AAC9E,4DAA4D;AAC5D,OAAO,EAAE,iBAAiB,IAAI,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACxF,OAAO,EAAE,KAAK,EAAE,MAAM,qCAAqC,CAAC;AAE5D;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CACnC,SAAsB,EACtB,UAAkB;IAElB,MAAM,IAAI,GAAG,iBAAiB,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC;QAChC,IAAI,EAAE;YACJ,GAAG,IAAI;YACP,QAAQ,EAAE;gBACR,GAAG,IAAI,CAAC,QAAQ;gBAChB,QAAQ,EAAE,EAAE,eAAe,EAAE,KAAK,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE;gBAC7D,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE;aAC1D;SACF;KACF,CAAC,CAAC;IACH,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACvB,OAAO,KAAK,CAAC;AACf,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-cheminfo",
3
- "version": "0.18.0",
3
+ "version": "0.20.0",
4
4
  "license": "MIT",
5
5
  "description": "React components, hooks and framework-free helpers shared by the cheminfo sites: site chrome, citations, sharing, routing, pedagogy, charts, and the structure, orbital and 3D molecule viewers",
6
6
  "author": "Luc Patiny",
@@ -64,14 +64,22 @@ export interface AboutContent {
64
64
  */
65
65
  repository?: string;
66
66
  /**
67
- * Which build is running, from `virtual:cheminfo-build-info` — never written
67
+ * Whether a visitor can open that repository. A site naming a repository of
68
+ * its own says so here too, since the family's record then describes another
69
+ * one.
70
+ * @default the `publicRepository` of the ECOSYSTEM_SITES record
71
+ */
72
+ publicRepository?: boolean;
73
+ /**
74
+ * Which build is running, from `react-cheminfo/build-info` — never written
68
75
  * by hand, which is what keeps it true after the next release.
69
76
  * @default undefined — the site's build does not publish one
70
77
  */
71
78
  build?: BuildInfo;
72
79
  /**
73
- * Where a problem is reported.
74
- * @default the repository's /issues
80
+ * Where a problem is reported: an address a visitor can actually open, so a
81
+ * site whose sources are private names one of its own or says nothing.
82
+ * @default the repository's /issues, and none at all when it is private
75
83
  */
76
84
  issues?: string;
77
85
  }
@@ -108,9 +116,12 @@ export interface ResolvedAbout {
108
116
  providedBy: ProviderEntry[];
109
117
  license: string;
110
118
  repository: string;
119
+ /** Whether a visitor can open the repository, and so whether it is named. */
120
+ publicRepository: boolean;
111
121
  /** Which build is running, or `undefined` when the site does not say. */
112
122
  build: BuildInfo | undefined;
113
- issues: string;
123
+ /** Where a problem is reported, or `undefined` when there is nowhere open. */
124
+ issues: string | undefined;
114
125
  }
115
126
 
116
127
  /**
@@ -127,6 +138,8 @@ export function resolveAbout(content: AboutContent): ResolvedAbout {
127
138
  ? siteById(content.siteId)
128
139
  : content.siteId;
129
140
  const repository = content.repository ?? site.repository;
141
+ const publicRepository =
142
+ content.publicRepository ?? site.publicRepository ?? false;
130
143
 
131
144
  return {
132
145
  site,
@@ -139,8 +152,15 @@ export function resolveAbout(content: AboutContent): ResolvedAbout {
139
152
  providedBy: providers(content.providedBy ?? []),
140
153
  license: content.license ?? DEFAULT_LICENSE,
141
154
  repository,
155
+ publicRepository,
142
156
  build: content.build,
143
- issues: content.issues ?? `${withoutTrailingSlash(repository)}/issues`,
157
+ // A tracker behind a private repository answers 404 to every visitor, so
158
+ // a site that names none of its own asks for a report nowhere.
159
+ issues:
160
+ content.issues ??
161
+ (publicRepository
162
+ ? `${withoutTrailingSlash(repository)}/issues`
163
+ : undefined),
144
164
  };
145
165
  }
146
166
 
@@ -1,3 +1,4 @@
1
+ export { githubSources } from './repository.ts';
1
2
  export type { AboutContent, AboutPerson, ResolvedAbout } from './about.ts';
2
3
  export { aboutProblems, resolveAbout } from './about.ts';
3
4
  export type { ProviderEntry, ProviderId } from './providers.ts';
@@ -0,0 +1,22 @@
1
+ /**
2
+ * What can be linked to inside a repository, and when.
3
+ *
4
+ * Only GitHub has the addresses the About page builds — a release tag, a
5
+ * commit — and only a repository a visitor can open is worth pointing them at.
6
+ */
7
+
8
+ /** Where our repositories live, and the only host whose paths we know. */
9
+ const GITHUB = 'https://github.com/';
10
+
11
+ /**
12
+ * The sources as a base a release or a commit can be appended to.
13
+ * @param repository - Where the sources live.
14
+ * @returns The address without its trailing slash, or `undefined` when it is
15
+ * not a GitHub repository and nothing inside it can be addressed.
16
+ */
17
+ export function githubSources(repository: string): string | undefined {
18
+ const sources = repository.endsWith('/')
19
+ ? repository.slice(0, -1)
20
+ : repository;
21
+ return sources.startsWith(GITHUB) ? sources : undefined;
22
+ }
@@ -2,6 +2,7 @@ import type { CSSProperties, ReactElement, ReactNode } from 'react';
2
2
 
3
3
  import type { BuildInfo } from '../../build/core/buildInfo.ts';
4
4
  import { formatBuiltAt, shortCommit } from '../../build/core/buildInfo.ts';
5
+ import { githubSources } from '../core/repository.ts';
5
6
 
6
7
  export interface AboutBuildProps {
7
8
  /** What the build published about itself. */
@@ -11,38 +12,32 @@ export interface AboutBuildProps {
11
12
  }
12
13
 
13
14
  /**
14
- * The one line that says which build of the site a visitor has open.
15
+ * The one line that says when the build a visitor has open was made.
15
16
  *
16
17
  * A report of something going wrong is worth answering only when we know what
17
- * was running, and a visitor cannot read that off the page otherwise. The
18
- * version and the commit link into the repository, so the change that caused a
19
- * problem is one click from the page that shows it.
18
+ * was running. The version itself is in the hero, where a reader is asked to
19
+ * quote it from; this line carries the rest, and the commit links into the
20
+ * repository, so the change that caused a problem is one click from the page
21
+ * that shows it.
20
22
  * @param props - See {@link AboutBuildProps}.
21
23
  * @returns The line.
22
24
  */
23
25
  export function AboutBuild(props: AboutBuildProps): ReactElement {
24
26
  const { build, repository } = props;
25
- const sources = repository.endsWith('/')
26
- ? repository.slice(0, -1)
27
- : repository;
28
- const onGitHub = sources.startsWith(GITHUB);
27
+ const sources = githubSources(repository);
29
28
 
30
29
  return (
31
30
  <p style={PARAGRAPH_STYLE}>
32
- Running version{' '}
33
- <Reference
34
- href={
35
- onGitHub ? `${sources}/releases/tag/v${build.version}` : undefined
36
- }
37
- >
38
- {build.version}
39
- </Reference>
40
- , built {formatBuiltAt(build.builtAt)}
31
+ Built {formatBuiltAt(build.builtAt)}
41
32
  {build.commit === undefined ? null : (
42
33
  <>
43
34
  {' from commit '}
44
35
  <Reference
45
- href={onGitHub ? `${sources}/commit/${build.commit}` : undefined}
36
+ href={
37
+ sources === undefined
38
+ ? undefined
39
+ : `${sources}/commit/${build.commit}`
40
+ }
46
41
  >
47
42
  {shortCommit(build.commit)}
48
43
  </Reference>
@@ -67,8 +62,6 @@ function Reference(props: {
67
62
  );
68
63
  }
69
64
 
70
- const GITHUB = 'https://github.com/';
71
-
72
65
  const PARAGRAPH_STYLE = {
73
66
  margin: '8px 0 0',
74
67
  color: 'var(--text-muted)',
@@ -10,6 +10,7 @@ import { AboutBuild } from './AboutBuild.tsx';
10
10
  import { AboutCitations } from './AboutCitations.tsx';
11
11
  import { AboutProvidedBy } from './AboutProvidedBy.tsx';
12
12
  import { AboutSection } from './AboutSection.tsx';
13
+ import { AboutVersion } from './AboutVersion.tsx';
13
14
 
14
15
  export interface AboutPageProps {
15
16
  /** What the site says about itself. */
@@ -67,20 +68,22 @@ export function AboutPage(props: AboutPageProps): ReactElement {
67
68
  }
68
69
  style={PAGE_STYLE}
69
70
  >
70
- <header
71
- className="about-hero"
72
- style={logo === undefined ? HERO_STYLE : LOGO_HERO_STYLE}
73
- >
71
+ <header className="about-hero" style={HERO_STYLE}>
74
72
  {logo === undefined
75
73
  ? (mark ?? <SiteMark site={site} size={56} />)
76
74
  : null}
77
- <div>
75
+ <div style={HERO_BODY_STYLE}>
78
76
  <h1 style={logo === undefined ? NAME_STYLE : LOGO_NAME_STYLE}>
79
77
  {logo ?? <Wordmark site={site} size={26} />}
80
78
  </h1>
81
79
  <p style={TAGLINE_STYLE}>{site.tagline}</p>
82
80
  <p style={WHAT_STYLE}>{about.what}</p>
83
81
  </div>
82
+ <AboutVersion
83
+ build={about.build}
84
+ repository={about.repository}
85
+ publicRepository={about.publicRepository}
86
+ />
84
87
  </header>
85
88
 
86
89
  {about.people.length === 0 && about.providedBy.length === 0 ? null : (
@@ -122,23 +125,36 @@ export function AboutPage(props: AboutPageProps): ReactElement {
122
125
  </AboutSection>
123
126
  )}
124
127
 
125
- <AboutSection title="Licence and source" className="about-licence">
126
- <p style={FIRST_PARAGRAPH_STYLE}>
127
- {about.license}, © cheminfo. Use it in a course, fork it, or lift a
128
- piece of it into something else. The sources are at{' '}
129
- <ExternalLink href={about.repository} />.
130
- </p>
131
- {about.build === undefined ? null : (
132
- <AboutBuild build={about.build} repository={about.repository} />
133
- )}
134
- </AboutSection>
128
+ {/*
129
+ A repository nobody outside can open is named nowhere: a licence a
130
+ reader cannot act on and a link that answers 404 say less than silence.
131
+ The version stays in the hero, unlinked, so a report still names a build.
132
+ */}
133
+ {!about.publicRepository ? null : (
134
+ <AboutSection title="Licence and source" className="about-licence">
135
+ <p style={FIRST_PARAGRAPH_STYLE}>
136
+ {about.license}, © cheminfo. Use it in a course, fork it, or lift a
137
+ piece of it into something else. The sources are at{' '}
138
+ <ExternalLink href={about.repository} />.
139
+ </p>
140
+ {about.build === undefined ? null : (
141
+ <AboutBuild build={about.build} repository={about.repository} />
142
+ )}
143
+ </AboutSection>
144
+ )}
135
145
 
136
- <AboutSection title="Found a problem?" className="about-issues">
137
- <p style={FIRST_PARAGRAPH_STYLE}>
138
- Tell us: a report naming what you typed and what came back is the
139
- fastest fix there is. <ExternalLink href={about.issues} />.
140
- </p>
141
- </AboutSection>
146
+ {/*
147
+ Asking for a report is worth nothing without somewhere to send it, and
148
+ the tracker of a private repository answers 404 to every visitor.
149
+ */}
150
+ {about.issues === undefined ? null : (
151
+ <AboutSection title="Found a problem?" className="about-issues">
152
+ <p style={FIRST_PARAGRAPH_STYLE}>
153
+ Tell us: a report naming what you typed and what came back is the
154
+ fastest fix there is. <ExternalLink href={about.issues} />.
155
+ </p>
156
+ </AboutSection>
157
+ )}
142
158
  </div>
143
159
  );
144
160
  }
@@ -162,6 +178,11 @@ const PAGE_STYLE = {
162
178
  gap: 10,
163
179
  } as const satisfies CSSProperties;
164
180
 
181
+ const HERO_BODY_STYLE = {
182
+ flex: '1 1 auto',
183
+ minWidth: 0,
184
+ } as const satisfies CSSProperties;
185
+
165
186
  const HERO_STYLE = {
166
187
  display: 'flex',
167
188
  alignItems: 'flex-start',
@@ -179,13 +200,6 @@ const NAME_STYLE = {
179
200
  fontWeight: 700,
180
201
  } as const satisfies CSSProperties;
181
202
 
182
- // A drawn lockup already carries the mark and the name at its own proportions,
183
- // so the hero gives it the full width rather than a column beside a mark.
184
- const LOGO_HERO_STYLE = {
185
- ...HERO_STYLE,
186
- display: 'block',
187
- } as const satisfies CSSProperties;
188
-
189
203
  const LOGO_NAME_STYLE = {
190
204
  margin: '0 0 4px',
191
205
  } as const satisfies CSSProperties;
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Which build of a site a visitor has open, in the corner of its hero.
3
+ *
4
+ * A report of something going wrong is worth answering only when we know what
5
+ * was running, and that is the one thing an About page cannot say from a
6
+ * hand-written record. It sits at the top of the page rather than at the
7
+ * bottom because it is the one line a reader is asked to quote back.
8
+ */
9
+
10
+ import type { CSSProperties, ReactElement } from 'react';
11
+
12
+ import type { BuildInfo } from '../../build/core/buildInfo.ts';
13
+ import {
14
+ buildLabel,
15
+ buildStamp,
16
+ buildSummary,
17
+ releasedVersion,
18
+ } from '../../build/core/buildInfo.ts';
19
+ import { githubSources } from '../core/repository.ts';
20
+
21
+ export interface AboutVersionProps {
22
+ /** What the build published about itself, or `undefined` when it published none. */
23
+ build: BuildInfo | undefined;
24
+ /** Where the sources live, which is what the badge links into. */
25
+ repository: string;
26
+ /** Whether a visitor can open that repository, and so whether it is linked. */
27
+ publicRepository: boolean;
28
+ }
29
+
30
+ /**
31
+ * The build badge: the release a site is serving, or the commit it was built
32
+ * from while it has no release yet, and when it was made.
33
+ * @param props - See {@link AboutVersionProps}.
34
+ * @returns The badge, or `null` when the build says nothing worth showing.
35
+ */
36
+ export function AboutVersion(props: AboutVersionProps): ReactElement | null {
37
+ const { build, repository, publicRepository } = props;
38
+ const label = buildLabel(build);
39
+ if (build === undefined || label === undefined) return null;
40
+ const href = publicRepository ? addressOf(build, repository) : undefined;
41
+ const summary = buildSummary(build);
42
+ // The instant belongs on the badge rather than in its hover: a version
43
+ // nobody can date says nothing about how old the page they read is.
44
+ const badge = `${label} · ${buildStamp(build.builtAt)}`;
45
+ if (href === undefined) {
46
+ return (
47
+ <span style={BADGE_STYLE} className="about-version" title={summary}>
48
+ {badge}
49
+ </span>
50
+ );
51
+ }
52
+
53
+ return (
54
+ <a
55
+ className="about-version"
56
+ href={href}
57
+ title={summary}
58
+ target="_blank"
59
+ rel="noopener noreferrer"
60
+ style={LINK_BADGE_STYLE}
61
+ >
62
+ {badge}
63
+ </a>
64
+ );
65
+ }
66
+
67
+ /**
68
+ * What the badge opens: the release it names, or the commit it was built from.
69
+ * @param build - What the build published about itself.
70
+ * @param repository - Where the sources live.
71
+ * @returns The address, or `undefined` when nothing inside the repository can
72
+ * be addressed.
73
+ */
74
+ function addressOf(build: BuildInfo, repository: string): string | undefined {
75
+ const sources = githubSources(repository);
76
+ if (sources === undefined) return undefined;
77
+ const version = releasedVersion(build);
78
+ if (version !== undefined) return `${sources}/releases/tag/v${version}`;
79
+ return build.commit === undefined
80
+ ? undefined
81
+ : `${sources}/commit/${build.commit}`;
82
+ }
83
+
84
+ const BADGE_STYLE = {
85
+ flex: '0 0 auto',
86
+ fontFamily: 'var(--font-mono, ui-monospace, monospace)',
87
+ fontSize: 13,
88
+ color: 'var(--text-muted)',
89
+ whiteSpace: 'nowrap',
90
+ } as const satisfies CSSProperties;
91
+
92
+ const LINK_BADGE_STYLE = {
93
+ ...BADGE_STYLE,
94
+ color: 'var(--accent)',
95
+ } as const satisfies CSSProperties;