File

src/app/modules/right-sidebar/right-sidebar.component.ts

Description

The right sidebar

Metadata

Index

Properties
Inputs
Outputs
HostBindings

Constructor

constructor(model: ModelState, registration: RegistrationState, page: PageState, astags: AnatomicalStructureTagState)

Creates an instance of right sidebar component.

Parameters :
Name Type Optional Description
model ModelState No

Model state service

registration RegistrationState No

Registration state service

page PageState No

The page state

astags AnatomicalStructureTagState No

The anatomical structure tags state

Inputs

modalClosed
Type : boolean
Default value : false

Whether or not the initial registration modal has been closed

Outputs

registrationExpanded
Type : EventEmitter

HostBindings

class
Type : "ccf-right-sidebar"
Default value : 'ccf-right-sidebar'

HTML class name

Properties

Readonly clsName
Type : string
Default value : 'ccf-right-sidebar'
Decorators :
@HostBinding('class')

HTML class name

import { ChangeDetectionStrategy, Component, EventEmitter, HostBinding, Input, Output } from '@angular/core';

import { AnatomicalStructureTagState } from '../../core/store/anatomical-structure-tags/anatomical-structure-tags.state';
import { ModelState } from '../../core/store/model/model.state';
import { PageState } from '../../core/store/page/page.state';
import { RegistrationState } from '../../core/store/registration/registration.state';

/**
 * The right sidebar
 */
@Component({
  selector: 'ccf-right-sidebar',
  templateUrl: './right-sidebar.component.html',
  styleUrls: ['./right-sidebar.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class RightSidebarComponent {
  /** HTML class name */
  @HostBinding('class') readonly clsName = 'ccf-right-sidebar';

  /** Whether or not the initial registration modal has been closed */
  @Input() modalClosed = false;

  @Output() readonly registrationExpanded = new EventEmitter<boolean>();

  /**
   * Creates an instance of right sidebar component.
   *
   * @param model Model state service
   * @param registration Registration state service
   * @param page The page state
   * @param astags The anatomical structure tags state
   */
  constructor(
    readonly model: ModelState,
    readonly registration: RegistrationState,
    readonly page: PageState,
    readonly astags: AnatomicalStructureTagState,
  ) {}
}
<div class="info-button-container">
  <ccf-info-button
    videoID="j4f9_xdBrK0"
    infoTitle="CCF Registration User Interface"
    documentationUrl="assets/docs/README.md"
  ></ccf-info-button>
</div>
<div class="scroll-wrapper">
  <div class="container">
    <mat-expansion-panel
      class="registration-metadata-panel"
      (opened)="registrationExpanded.emit(true)"
      (closed)="registrationExpanded.emit(false)"
    >
      <mat-expansion-panel-header class="header">
        <mat-panel-title matTooltip="">Registration Metadata</mat-panel-title>
      </mat-expansion-panel-header>

      <ccf-registration-metadata></ccf-registration-metadata>
    </mat-expansion-panel>

    <mat-divider></mat-divider>

    <mat-expansion-panel class="tissue-block-controls-panel" [expanded]="true">
      <mat-expansion-panel-header class="header">
        <mat-panel-title matTooltip="">Tissue Block Controls</mat-panel-title>
      </mat-expansion-panel-header>

      <ccf-block-size-input [blockSize]="(model.blockSize$ | async)!" (blockSizeChange)="model.setBlockSize($event)">
      </ccf-block-size-input>

      <ccf-slices-input
        [slicesConfig]="$any(model.slicesConfig$ | async)"
        (slicesConfigChange)="model.setSlicesConfig($event)"
      >
      </ccf-slices-input>

      <ccf-rotation-slider [rotation]="$any(model.rotation$ | async)" (rotationChange)="model.setRotation($event)">
      </ccf-rotation-slider>
    </mat-expansion-panel>

    <mat-divider></mat-divider>
    <mat-expansion-panel class="tags-container" [expanded]="true">
      <mat-expansion-panel-header class="header">
        <mat-panel-title matTooltip="Review tags generated via collision detection. Add or delete tags as needed."
          >Anatomical Structure Tags</mat-panel-title
        >
      </mat-expansion-panel-header>

      <ccf-tag-search [search]="astags.searchExternal" (added)="astags.addTags($event)"> </ccf-tag-search>

      <ccf-tag-list
        *ngIf="(model.organ$ | async)?.name; else tagListPlaceholder"
        class="tag-list"
        [tags]="(astags.tags$ | async) ?? []"
        (tagRemoved)="astags.removeTag($event)"
      >
      </ccf-tag-list>
      <ng-template #tagListPlaceholder> </ng-template>

      <div class="legend">
        <span class="dot assigned"></span>
        <span class="text assigned">Assigned</span>
        <span class="dot added"></span>
        <span class="text added">Added</span>
      </div>
    </mat-expansion-panel>
    <mat-divider></mat-divider>

    <div class="filler"></div>

    <ccf-review-button
      class="review-button"
      [registrationCallbackSet]="(page.registrationCallbackSet$ | async) ?? false"
      [displayErrors]="(registration.displayErrors$ | async) ?? false"
      [userValid]="(registration.valid$ | async) ?? false"
      [metaData]="(registration.metadata$ | async) ?? []"
      (registerData)="registration.register()"
      (enterErrorMode)="registration.setDisplayErrors(!registration.isValid)"
    >
    </ccf-review-button>
  </div>
</div>

./right-sidebar.component.scss

:host {
  display: block;
  height: calc(100% - 2.5rem);
  margin-top: 1rem;
  margin-bottom: 1.5rem;

  .info-button-container {
    height: 3.75rem;
    display: flex;
    justify-content: flex-end;
  }

  .scroll-wrapper {
    overflow-y: scroll;
    height: calc(100% - 6rem);

    scrollbar-width: thin;
    &::-webkit-scrollbar {
      width: 0.75rem;
    }

    .container {
      display: flex;
      flex-direction: column;
      min-height: 100%;
      margin: 0 1.5rem;

      .review-button {
        position: absolute;
        bottom: 1.5rem;
        z-index: 999;
        width: calc(100% - 3.5rem);
      }

      mat-divider {
        border-top-width: 3px;
      }

      mat-expansion-panel {
        box-shadow: none;

        mat-expansion-panel-header {
          padding: 0 0.5rem 0 0;
          font-weight: bold;
          -webkit-user-select: none;
          -moz-user-select: none;
          font-size: 1rem;
          height: 3rem;
        }

        ::ng-deep .mat-expansion-panel-body {
          padding-left: 0;
          padding-right: 0;
        }
      }

      .tags-container {
        // Allow tag search to overflow when displaying results
        overflow: visible;

        ::ng-deep .mat-expansion-panel-body {
          padding-left: 0;
          padding-right: 0;
        }

        .header {
          height: 3rem;
        }

        .search {
          margin-top: 1rem;

          .icon.add {
            position: absolute;
            // Sizes and offsets found by experimentation
            width: 3.625rem;
            height: 3.625rem;
            font-size: 3.625rem;
            top: -1.9375rem;
            right: -1.1875rem;
          }
        }

        .tag-list {
          max-height: 32rem;
          margin-left: -1rem;
        }

        .tag-list-placeholder {
          display: flex;
          height: 4rem;
          align-items: center;
          justify-content: center;
          font-weight: 400;
        }

        .legend {
          display: flex;
          width: 100%;
          margin-top: 1.5rem;
          align-items: center;
          font-size: 0.9rem;

          .dot {
            display: inline-block;
            width: 1rem;
            height: 1rem;
            border-radius: 50%;

            &.assigned {
              margin-left: 0.5rem;
            }

            &.added {
              margin-left: 1rem;
            }
          }

          .text {
            margin-left: 0.5rem;
          }
        }
      }

      .filler {
        flex-grow: 1;
      }
    }
  }
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""