CarnegieLearningWeb / UpGrade

Framework for adding A/B testing to education applications
https://www.upgradeplatform.org/
BSD 3-Clause "New" or "Revised" License
25 stars 11 forks source link

Common Components Library Planning #1406

Open danoswaltCL opened 1 month ago

danoswaltCL commented 1 month ago

Figma: https://www.figma.com/file/GaKw3nDscTnMEOzIf4CAa7/UpGrade-UI-Latest-14-(Final)?type=design&node-id=8289-13488&mode=design&t=pC7mrBmoUZsvCTYL-0

Common Components Track:

Common Components

This are the basic 'skeletons' of the common components. Please refer to the figma for style details.

"Params" mean data that is necessary for the component to render, whether that be from direct Inputs or by services, which could be accomplished via callbacks and/or observable ngrx actions and selectors.

"Events" are outputs that the parent component can listen to in order to respond to user interactions. These can be EventEmitter outputs or ngrx actions.

We should tend to prefer ngrx actions and selectors to inputs and outputs when we can, as it will help us keep the data flow predictable and less tightly coupled.

This is not an exhaustive list, we'll discover what we truly need as we go.

Common Root Page Component

// events:
- dispatch feature-level data fetching NGRX store actions

Common Root Page Heading Component

// params
title: string
subtitle: string

Common Detail Page Component

Common Detail Page Heading Component

// data:
breadcrumbs: string[]

Common Details Page Overview Summary Card Component

// data:
entitySummaryDetails: EntitySummaryDetails

// events:
- tab navigation events that will inform the parent component to change the index for what goes into the content slot

Common Page Section Card List Component

// params:
tabIndex?: number
tabbableList: SectionCard[][]

Common Modal Component

// data
- modals use Mat-Dialog for many configuration details, which can be used to pass a Modal context object

Common Modal Footer Component

Common Modal Footer Cancel Button

// data
label: string
action: fn()

// events
- 

Common Modal Footer Primary Button

// data
label: string
action: fn()

ng Content-Projection Example

An angular article on a few ways to do content-projection: https://angular.io/guide/content-projection

Here is just one example of the "multi-slot" projection from that article in a simplified version of the common composite dialog modal component that can be created using ng-content and content-projection. This has a title, content, and footer slot where content will be output like router-outlet. The dialog component has two buttons in the footer that emit events when clicked. The parent component listens to these events and logs a message to the console when the buttons are clicked.

ng-template and ngTemplateOutlet can also be used to project content for more dynamic scenarios.

// common-dialog.component.ts
import { Component, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-common-dialog',
  template: `
    <div class="dialog">
      <header>
        <ng-content select="[dialogTitle]"></ng-content>
      </header>
      <section>
        <ng-content select="[dialogContent]"></ng-content>
      </section>
      <footer>
        <ng-content select="[dialogFooter]"></ng-content>
        <button (click)="cancel.emit()">Cancel</button>
        <button (click)="confirm.emit()">Confirm</button>
      </footer>
    </div>
  `,
})
export class CommonDialogComponent {
  @Output() cancel = new EventEmitter<void>();
  @Output() confirm = new EventEmitter<void>();
}
// parent.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-parent',
  template: `
    <app-common-dialog (cancel)="onCancel()" (confirm)="onConfirm()">
      <h1 dialogTitle>Title</h1>
      <p dialogContent>Content</p>
      <div dialogFooter>Footer Content</div>
    </app-common-dialog>
  `,
})
export class ParentComponent {
  onCancel() {
    console.log('Cancel clicked');
  }

  onConfirm() {
    console.log('Confirm clicked');
  }
}
VivekFitkariwala commented 1 month ago

Thanks @danoswaltCL for writing it down. Now I have a better understanding of the approach.