Загрузка данных


import { Button } from 'exchange-elements/v2';

import { Observable } from 'rxjs';

import { GearIcon, TrashIcon } from '@components/Icon';
import { LegendModel, ohlcValuesToShowForMainSerie } from '@core/Legend';

import { OHLCConfig } from '@src/types';
import { formatDisplayText, useObservable } from '@src/utils';

import styles from './index.module.scss';

export interface LegendProps {
  ohlcConfig?: OHLCConfig;
  viewModel: Observable<LegendModel>;
}

const mainSerieKeys = new Set(ohlcValuesToShowForMainSerie);

function getEntries(values: LegendModel[number]['values']) {
  return values instanceof Map ? Array.from(values.entries()) : Object.entries(values);
}

export const LegendComponent = ({ ohlcConfig, viewModel }: LegendProps) => {
  const model = useObservable(viewModel);
  const showMainSerieValues = Boolean(ohlcConfig?.show);

  return (
    <section className={styles.legend}>
      {model?.map((item) => (
        <div
          key={`legend-${item.name}`}
          className={styles.row}
        >
          <div className={styles.symbol}>{item.name}</div>

          <div className={styles.priceWrapper}>
            {getEntries(item.values).map(([key, value]) => {
              if (!item.isIndicator && (!showMainSerieValues || !mainSerieKeys.has(key))) {
                return null;
              }

              const text = formatDisplayText(value.value);

              if (!text) {
                return null;
              }

              return (
                <div
                  key={`${item.name}-${key}`}
                  className={styles.item}
                >
                  {value.name && <span>{value.name}</span>}
                  <span
                    className={styles.price}
                    style={{ color: value.color }}
                  >
                    {text}
                  </span>
                </div>
              );
            })}

            {item.settings && (
              <Button
                size="sm"
                className={styles.button}
                onClick={item.settings}
                label={<GearIcon />}
              />
            )}

            {item.remove && (
              <Button
                size="sm"
                className={styles.button}
                onClick={item.remove}
                label={<TrashIcon />}
              />
            )}
          </div>
        </div>
      ))}
    </section>
  );
};







.legend {
  position: absolute;
  z-index: 10;
  top: var(--space-0500);
  left: var(--space-0500);
  display: flex;
  flex-direction: column;
  gap: var(--space-0250);
  pointer-events: auto;
}

.row {
  width: 100%;
  max-width: max-content;
  display: flex;
  align-items: center;
  gap: var(--space-0500);

  .symbol,
  .item,
  .price {
    font-size: var(--space-0750);
    font-weight: var(--font-medium);
  }

  .priceWrapper {
    position: relative;
    display: flex;
    justify-content: start;
    align-items: center;
    gap: var(--space-0500);
  }

  .item {
    display: flex;
    align-items: center;
    gap: var(--space-0250);
  }

  .button {
    display: none;
    width: var(--space-1000);
    height: var(--space-1000);
    border-radius: var(--space-0125);
    color: var(--neutral-13);
    padding: 0;
    min-width: 0;
    opacity: 0;
    pointer-events: none;

    & p {
      display: flex;
      justify-content: center;
      align-items: start;
      padding: 0;

      svg {
        width: var(--space-0875);
        height: var(--space-0875);
      }
    }
  }

  &:hover .button {
    display: block;
    opacity: 1;
    pointer-events: auto;
  }

  &:hover .item {
    display: none;
    opacity: 0;
    pointer-events: none;
  }
}