tosijs-ui 1.7.3 → 1.7.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.7.4
4
+
5
+ - **Configurable header logo.** A new `logo` option lets a doc site set the brand mark shown
6
+ left of the site title, instead of always inheriting the tosijs-ui logo. Accepts the name of a
7
+ known icon (from `tosijs-ui`'s `icons`, e.g. `'tosiUi'`), an image URL / path / `data:` URI
8
+ (rendered as an `<img>`), or a raw inline `<svg>…</svg>` string. Threaded through
9
+ `SiteConfig.logo` (`tosijs-ui/site`), `createDocBrowser({ logo })`, and an embedded
10
+ `<tosi-doc-system config='{"logo":"…"}'>`. Omit it to keep the prior behavior: the tosijs-ui
11
+ logo when `projectLinks.tosijs` is set, otherwise no mark. Previously the header logo was
12
+ hard-wired to the tosijs-ui mark — the one branding element `SiteConfig` couldn't override.
13
+
3
14
  ## 1.7.3
4
15
 
5
16
  - **New `<tosi-pocket-bar>` component.** A "pocket buttonbar": a single translucent icon at
@@ -61,6 +61,15 @@ export interface DocBrowserOptions {
61
61
  context?: Record<string, any>;
62
62
  projectName?: string;
63
63
  projectLinks?: ProjectLinks;
64
+ /**
65
+ * The brand mark shown left of the site title in the header. One of:
66
+ * - the name of a known icon (from `icons`), e.g. `'tosiUi'`
67
+ * - an image URL / path / data: URI (rendered as an `<img>`)
68
+ * - a raw inline `<svg …>…</svg>` string
69
+ * Omit to fall back to the tosijs-ui logo when `projectLinks.tosijs` is set,
70
+ * or to no mark at all otherwise.
71
+ */
72
+ logo?: string;
64
73
  navSize?: number;
65
74
  minSize?: number;
66
75
  routing?: DocRoutingMode;
@@ -163,7 +163,7 @@ import { tosiLocalized } from './localize';
163
163
  import { popMenu } from './menu';
164
164
  import { codeEditor } from './code-editor';
165
165
  import { tosiDiff } from './diff';
166
- const { div, span, a, header, button, template, input, h2, details, summary, ul, li, } = elements;
166
+ const { div, span, a, header, button, template, input, h2, img, details, summary, ul, li, } = elements;
167
167
  // Test colors
168
168
  const testColor = {
169
169
  pass: varDefault.testColorPass('#0a0'),
@@ -254,11 +254,58 @@ const testIndicatorStyleSpec = {
254
254
  borderRadius: vars.roundedRadius,
255
255
  },
256
256
  };
257
+ // The brand mark shown left of the site title. `logo` (from config) may name a
258
+ // known icon, be an inline `<svg>` string, or be an image URL; when absent we
259
+ // keep the legacy behavior — the tosijs-ui logo iff this is a tosijs project,
260
+ // else nothing. Sized to match the header height so hydration doesn't reflow.
261
+ const LOGO_SIZE = 40;
262
+ const LOGO_GAP = 10;
263
+ // `icons` is a Proxy that returns a factory for ANY string (unknown names get a
264
+ // placeholder glyph), so we can't ask it whether a name is real — we route by the
265
+ // shape of the string instead: an inline `<svg>` renders as-is, a URL/path/data:
266
+ // URI renders as an <img>, and anything else is treated as an icon(-composition)
267
+ // name.
268
+ function looksLikeImageUrl(s) {
269
+ return (/^(https?:)?\/\//.test(s) ||
270
+ s.startsWith('data:') ||
271
+ s.startsWith('/') ||
272
+ s.startsWith('./') ||
273
+ s.startsWith('../') ||
274
+ /\.(png|jpe?g|gif|webp|avif|svg|ico)(\?.*)?$/i.test(s));
275
+ }
276
+ function logoMark(logo, projectLinks) {
277
+ if (logo) {
278
+ if (logo.trimStart().startsWith('<')) {
279
+ const holder = span({
280
+ style: {
281
+ display: 'inline-flex',
282
+ height: `${LOGO_SIZE}px`,
283
+ marginRight: `${LOGO_GAP}px`,
284
+ },
285
+ });
286
+ holder.innerHTML = logo;
287
+ return holder;
288
+ }
289
+ if (looksLikeImageUrl(logo)) {
290
+ return img({
291
+ src: logo,
292
+ alt: '',
293
+ style: { height: `${LOGO_SIZE}px`, marginRight: `${LOGO_GAP}px` },
294
+ });
295
+ }
296
+ return icons[logo]({
297
+ style: { _xinIconSize: LOGO_SIZE, marginRight: LOGO_GAP },
298
+ });
299
+ }
300
+ return projectLinks.tosijs
301
+ ? icons.tosiUi({ style: { _xinIconSize: LOGO_SIZE, marginRight: LOGO_GAP } })
302
+ : span();
303
+ }
257
304
  // Monotonic per-page counter so each createDocBrowser() call gets a distinct
258
305
  // tosi() registry key (see stateKey below) and two browsers can't share state.
259
306
  let docBrowserSeq = 0;
260
307
  export function createDocBrowser(options) {
261
- const { docs, context = {}, projectName = '', projectLinks = {}, navSize = 200, minSize = 600, routing = 'query', initialRoute, onRouteChange, navbarLinks, contentElement, } = options;
308
+ const { docs, context = {}, projectName = '', projectLinks = {}, logo, navSize = 200, minSize = 600, routing = 'query', initialRoute, onRouteChange, navbarLinks, contentElement, } = options;
262
309
  // Memory routing is fully self-contained: it never reads or writes
263
310
  // window.history/location, so an embedded or nested browser can't hijack the
264
311
  // host page's URL (or recurse into it).
@@ -522,11 +569,7 @@ export function createDocBrowser(options) {
522
569
  alignItems: 'center',
523
570
  borderBottom: 'none',
524
571
  },
525
- }, projectLinks.tosijs
526
- ? icons.tosiUi({
527
- style: { _xinIconSize: 40, marginRight: 10 },
528
- })
529
- : span(), h2(projectName)));
572
+ }, logoMark(logo, projectLinks), h2(projectName)));
530
573
  }
531
574
  headerContent.push(span({ class: 'elastic' }));
532
575
  // A header link renders as an icon (if `icon` names a known icon) or its label.
@@ -409,6 +409,7 @@ export class TosiDocSystem extends Component {
409
409
  },
410
410
  projectName: config.projectName,
411
411
  projectLinks: config.projectLinks,
412
+ logo: config.logo,
412
413
  navbarLinks: navbarLinks.length ? navbarLinks : undefined,
413
414
  contentElement,
414
415
  });
@@ -18,6 +18,8 @@ export interface GenerateSiteConfig {
18
18
  /** default og:image (per-page overridable via doc metadata) */
19
19
  ogImage?: string;
20
20
  projectLinks?: ProjectLinks;
21
+ /** brand mark left of the title: icon name, image URL, or inline <svg> */
22
+ logo?: string;
21
23
  /** header-bar links (rendered as real <a> for no-JS, upgraded on hydration) */
22
24
  navbarLinks?: LinkItem[];
23
25
  /** translation table (TSV) for the settings menu's language picker */
@@ -251,6 +251,7 @@ export async function generateSite(config) {
251
251
  const configAttr = escapeAttr(JSON.stringify({
252
252
  projectName: config.projectName,
253
253
  projectLinks: config.projectLinks,
254
+ logo: config.logo,
254
255
  }));
255
256
  // The theme stylesheet (config.stylesUrl) is written separately by
256
257
  // ./generate-css.ts; pages here just <link> to it.
@@ -600,6 +600,7 @@ export async function buildSite(config) {
600
600
  baseUrl: config.baseUrl,
601
601
  lang: config.lang,
602
602
  projectLinks: config.projectLinks,
603
+ logo: config.logo,
603
604
  navbarLinks: config.navbarLinks,
604
605
  localizedStrings: config.localizedStrings,
605
606
  favicon: config.favicon,
@@ -30,6 +30,13 @@ export interface SiteConfig {
30
30
  headExtra?: string;
31
31
  /** logo + view-source links (createDocBrowser projectLinks) */
32
32
  projectLinks?: ProjectLinks;
33
+ /**
34
+ * Brand mark shown left of the site title in the header. One of: the name of a
35
+ * known icon (from `tosijs-ui`'s `icons`, e.g. `'tosiUi'`), an image URL / path
36
+ * / `data:` URI, or a raw inline `<svg …>…</svg>` string. Omit to fall back to
37
+ * the tosijs-ui logo when `projectLinks.tosijs` is set, or to no mark otherwise.
38
+ */
39
+ logo?: string;
33
40
  /** header-bar icon links */
34
41
  navbarLinks?: LinkItem[];
35
42
  /** base theme colors — most of the palette is derived from `accent` */