<commit_before>/*
 *  This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
 *  License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details
 */

import { List } from "immutable";
import { Icon, Loading } from "./index";
import { CSS, React, TypedMap } from "../app-framework";
import { Markdown } from "./markdown";

export interface TableOfContentsEntry {
  id: string; // id that is unique across the table of contents
  value: string; // contents of the heading -- a 1-line string formatted using markdown (will be rendered using markdown)
  level?: 1 | 2 | 3 | 4 | 5 | 6; // optional heading size/level
  icon?: string; // font awesome icon name -- default "minus" (a dash)
  number?: number[]; // section numbering, so for "- 1.2.4  A Subsction" this would be [1,2,4].
  extra?: any; // this is just passed back to the scrollTo function to provide extra info about how to scroll to this heading.
}

export type TableOfContentsEntryMap = TypedMap<TableOfContentsEntry>;
export type TableOfContentsEntryList = List<TableOfContentsEntryMap>;

interface Props {
  contents?: TableOfContentsEntryList; // an immutable.js List of entries, as above.
  scrollTo?: (TableOfContentsEntry) => void;
  style?: CSS;
}

export const TableOfContents: React.FC<Props> = React.memo(
  ({ contents, scrollTo, style }) => {
    function renderHeader(
      level: 1 | 2 | 3 | 4 | 5 | 6,
      value: string,
      icon: string
    ): JSX.Element {
      const style = { marginTop: 0 };
      const elt = (
        <>
          <Icon
            name={icon}
            style={{ width: "30px", display: "inline-block" }}
          />{" "}
          <a style={{ display: "inline-block", marginBottom: "-1em" }}>
            <Markdown value={value} />
          </a>
        </>
      );
      // NOTE: the weird style for the a above is so the markdown
      // paragraph wrapper doesn't end up on a new line; it also removes
      // the extra 1em space at the bottom of that paragraph.   We could
      // redo this more cleanly by possibly using a special markdown
      // component that omits that top-level paragraph wrapping (and uses
      // react/slate?).

      switch (level) {
        case 1:
          return <h1 style={style}>{elt}</h1>;
        case 2:
          return <h2 style={style}>{elt}</h2>;
        case 3:
          return <h3 style={style}>{elt}</h3>;
        case 4:
          return <h4 style={style}>{elt}</h4>;
        case 5:
          return <h5 style={style}>{elt}</h5>;
        default:
          return <h6 style={style}>{elt}</h6>;
      }
    }<commit_msg>fix #5240 -- Table of contents with a smaller font<commit_after>/*
 *  This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
 *  License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details
 */

import { List } from "immutable";
import { Icon, Loading } from "./index";
import { CSS, React, TypedMap } from "../app-framework";
import { Markdown } from "./markdown";

export interface TableOfContentsEntry {
  id: string; // id that is unique across the table of contents
  value: string; // contents of the heading -- a 1-line string formatted using markdown (will be rendered using markdown)
  level?: 1 | 2 | 3 | 4 | 5 | 6; // optional heading size/level
  icon?: string; // font awesome icon name -- default "minus" (a dash)
  number?: number[]; // section numbering, so for "- 1.2.4  A Subsction" this would be [1,2,4].
  extra?: any; // this is just passed back to the scrollTo function to provide extra info about how to scroll to this heading.
}

export type TableOfContentsEntryMap = TypedMap<TableOfContentsEntry>;
export type TableOfContentsEntryList = List<TableOfContentsEntryMap>;

interface Props {
  contents?: TableOfContentsEntryList; // an immutable.js List of entries, as above.
  scrollTo?: (TableOfContentsEntry) => void;
  style?: CSS;
}

export const TableOfContents: React.FC<Props> = React.memo(
  ({ contents, scrollTo, style }) => {
    function renderHeader(
      level: 1 | 2 | 3 | 4 | 5 | 6,
      value: string,
      icon: string
    ): JSX.Element {
      if (level < 1) level = 1;
      if (level > 6) level = 6;
      const fontSize = `${1 + (7 - level) / 6}em`;
      const style = { marginTop: 0, fontSize, whiteSpace:'nowrap' } as CSS;
      const elt = (
        <>
          <Icon
            name={icon}
            style={{ width: "30px", display: "inline-block" }}
          />{" "}
          <a style={{ display: "inline-block", marginBottom: "-1em" }}>
            <Markdown value={value} />
          </a>
        </>
      );

      // NOTE: the weird style for the a above is so the markdown
      // paragraph wrapper doesn't end up on a new line; it also removes
      // the extra 1em space at the bottom of that paragraph.   We could
      // redo this more cleanly by possibly using a special markdown
      // component that omits that top-level paragraph wrapping (and uses
      // react/slate?).
      return <div style={style}>{elt}</div>;
    }
{'fraction_non_alphanumeric': 0.12557396685965264, 'fraction_numerical': 0.017169095627869835, 'mean_word_length': 2.545647558386412, 'pattern_counts': {'":': 0, '<': 36, '<?xml version=': 0, '>': 40, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5097449', 'n_tokens_mistral': 1536, 'n_tokens_neox': 1469, 'n_words': 564}