Skip to content
Merged

PD-4789 #2748

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Orcid Angular — Agent Notes

Monorepo: main app (`src/`, project `ng-orcid`), docs (`projects/orcid-ui-docs`), and libraries. Use this for fast orientation.

> **Note for future agents:** This file is intended to be edited over time. Any section—relevant or not—may be updated, trimmed, or reorganized so the document stays lean and useful for future agents. Prefer keeping only what helps the next AI work effectively with this project.

## Quick reference: libraries

- **@orcid/ui** — `projects/orcid-ui` — Agnostic UI components, design tokens, modal shell. See `projects/orcid-ui/AGENTS.md`.
- **@orcid/registry-ui** — `projects/orcid-registry-ui` — Registry-specific components (e.g. import-works-dialog). See `projects/orcid-registry-ui/AGENTS.md`.

Both are path-mapped from repo root (`tsconfig.json`). Main app and docs consume them from source.

## When changing a library component’s API

Update the main app and that component’s doc page (usage snippet, inputs list, examples).

## If component styles differ between docs and main app

If a library component (e.g. in orcid-registry-ui) looks correct in the docs app but wrong in the main app (e.g. missing margins or spacing), try **resetting the main project**: clean build artifacts, reinstall, or reset local overrides. Stale or inconsistent build/cache state in the main app can cause component styles to not apply as in docs; a fresh build often resolves it.


## Dialogs and async data

When a dialog or view needs data from an HTTP (or other async) call, opening the dialog only after the request completes can feel slow. Consider opening the dialog **immediately** with skeleton or static data (e.g. labels, empty lists, or a `loading: true` flag), then assigning the full payload to the dialog’s component instance when the observable emits. The dialog can show placeholders or a loading state until then.
41 changes: 41 additions & 0 deletions projects/orcid-registry-ui/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Orcid Registry UI — Agent Notes (for future GPTs)

This package (`projects/orcid-registry-ui`, published as `@orcid/registry-ui`) contains **feature-oriented UI components** for the main orcid-angular application only. It is not intended for reuse outside this project.

> **Note for future agents:** This file is intended to be edited over time. Any section—relevant or not—may be updated, trimmed, or reorganized so the document stays lean and useful for future agents. Prefer keeping only what helps the next AI work effectively with this library.

## Library scope: orcid-registry-ui vs orcid-ui

- **orcid-ui** (`@orcid/ui`): Fully **agnostic** UI building blocks. No feature names or domain-specific wording. Open source–friendly and reusable across any ORCID or non-ORCID project. Components use Angular Material when possible and design tokens for styling.

- **orcid-registry-ui** (`@orcid/registry-ui`): **Registry-specific** components for the orcid-angular app only. May use feature names (e.g. “Import your works”, “Permission notifications”). Builds on **orcid-ui** components, Angular Material, and **orcid-tokens**. More flexible and app-coupled.

## Conventions

- **Package entry**: `projects/orcid-registry-ui/src/public-api.ts`
- **Components**: `projects/orcid-registry-ui/src/lib/components/**`
- Prefer **standalone components**. Use `@orcid/ui` for base primitives (modals, action surfaces, etc.) and **orcid-tokens** CSS variables for layout/color/typography.
- Dialogs that use the shared modal chrome should use `OrcidModalComponent` and `ORCID_MODAL_DIALOG_PANEL_CLASS` from `@orcid/ui` when opening with `MatDialog`.
- **Dialog data (MAT_DIALOG_DATA):** If the host may open the dialog first and assign full data later (e.g. after an async request), the data interface can include an optional flag (e.g. `loading?: boolean`) so the dialog can show a skeleton or placeholder until the host sets the complete data.

## Dependencies

- Peer: `@angular/common`, `@angular/core`, `@angular/material`, `@orcid/ui`, `rxjs`
- The host app (orcid-angular) supplies `@orcid/ui` and design tokens (e.g. via `tokens.css`).

## Building

- From repo root: `ng build orcid-registry-ui` (or use the npm script if defined).

## When changing this library’s API

If you add or change **inputs**, **data types**, or **public behavior** in a registry-ui component, update **both** the main app usage (under `src/`) and the component’s doc page (usage snippet, inputs list, examples) so they stay in sync.

## Docs site (`projects/orcid-ui-docs`)

Registry-ui doc pages live under **`src/app/pages/orcid-registry-ui/`** (orcid-ui pages live under `pages/orcid-ui/`). When adding a new registry-ui component doc:

- Add the page in `projects/orcid-ui-docs/src/app/pages/orcid-registry-ui/<name>-page.component.{ts,html,scss}`
- Import `DocumentationPageComponent` from `'../../components/documentation-page/documentation-page.component'`
- Register a lazy route in `app.routes.ts` pointing to `./pages/orcid-registry-ui/<name>-page.component`
- Add a sidebar link under the “Orcid Registry UI” section in `docs-shell.component.html`
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
<orcid-modal [title]="title">
<div orcidModalBody>
<div class="import-works-dialog__intro" *ngIf="introText">
<p class="import-works-dialog__intro-text">{{ introText }}</p>
<a
*ngIf="supportLink"
class="import-works-dialog__support-link"
[href]="supportLink.url"
target="_blank"
rel="noopener noreferrer"
>
{{ supportLink.label }}
</a>
</div>

<section class="import-works-dialog__section" *ngIf="loading || certifiedLinks.length">
<h3 class="import-works-dialog__section-heading">
{{ certifiedSectionHeading }}
</h3>
<div class="import-works-dialog__card-list">
<!-- Shimmer skeleton cards while loading -->
<ng-container *ngIf="loading">
<div
*ngFor="let _ of certifiedSkeletonCount"
class="import-works-dialog__card import-works-dialog__card--certified import-works-dialog__card--skeleton"
aria-hidden="true"
>
<div class="import-works-dialog__card-icon">
<orcid-skeleton-placeholder [accentBackground]="false" shape="square" width="48px" height="48px"></orcid-skeleton-placeholder>
</div>
<div class="import-works-dialog__card-content">
<orcid-skeleton-placeholder [accentBackground]="false" class="import-works-dialog__skeleton-title" height="27px" width="60%"></orcid-skeleton-placeholder>
<orcid-skeleton-placeholder [accentBackground]="false" class="import-works-dialog__skeleton-line" height="21px" width="85%"></orcid-skeleton-placeholder>
</div>
<div class="import-works-dialog__card-actions">
<orcid-skeleton-placeholder [accentBackground]="false" class="import-works-dialog__skeleton-btn" height="36px" width="120px"></orcid-skeleton-placeholder>
</div>
</div>
</ng-container>
<!-- Real certified links -->
<ng-container *ngIf="!loading">
<div
*ngFor="let link of certifiedLinks"
class="import-works-dialog__card import-works-dialog__card--certified"
>
<div class="import-works-dialog__card-icon" *ngIf="link.imageUrl || link.icon">
<img *ngIf="link.imageUrl" [src]="link.imageUrl" [alt]="link.name + ' logo'" class="import-works-dialog__card-img" />
<mat-icon *ngIf="!link.imageUrl && link.icon" [attr.aria-hidden]="true">{{ link.icon }}</mat-icon>
</div>
<div class="import-works-dialog__card-content">
<p class="import-works-dialog__card-title">{{ link.name }}</p>
<p class="import-works-dialog__card-description">
{{ link.description }}
</p>
</div>
<div class="import-works-dialog__card-actions">
<ng-container *ngIf="link.connected; else connectCertified">
<span class="import-works-dialog__connected">
<span class="import-works-dialog__connected-dot" aria-hidden="true"></span>
{{ connectedLabel }}
</span>
</ng-container>
<ng-template #connectCertified>
<button
mat-flat-button
class="import-works-dialog__btn-connect"
(click)="openInNewTab(link.url)"
>
{{ connectNowLabel }}
</button>
</ng-template>
</div>
</div>
</ng-container>
</div>
</section>

<section class="import-works-dialog__section import-works-dialog__section--more" *ngIf="loading || moreServicesLinks.length">
<div class="import-works-dialog__more-panel">
<button
type="button"
class="import-works-dialog__more-header"
(click)="toggleMoreServices()"
[attr.aria-expanded]="moreServicesExpanded"
[attr.aria-controls]="'import-works-more-list'"
id="import-works-more-heading"
>
<mat-icon class="import-works-dialog__more-chevron" aria-hidden="true">
{{ moreServicesExpanded ? 'expand_more' : 'expand_less' }}
</mat-icon>
<span class="import-works-dialog__more-heading-text">
{{ moreServicesHeading }}
<span class="import-works-dialog__more-count" *ngIf="!loading">({{ moreServicesLinks.length }})</span>
</span>
</button>
<div
id="import-works-more-list"
class="import-works-dialog__more-list"
role="region"
[attr.aria-labelledby]="'import-works-more-heading'"
[hidden]="!moreServicesExpanded"
>
<!-- Shimmer skeleton cards while loading -->
<ng-container *ngIf="loading">
<div
*ngFor="let _ of moreServicesSkeletonCount"
class="import-works-dialog__card import-works-dialog__card--more import-works-dialog__card--skeleton"
aria-hidden="true"
>
<div class="import-works-dialog__card-icon">
<orcid-skeleton-placeholder [accentBackground]="false" shape="square" width="48px" height="48px"></orcid-skeleton-placeholder>
</div>
<div class="import-works-dialog__card-content">
<orcid-skeleton-placeholder [accentBackground]="false" class="import-works-dialog__skeleton-title" height="27px" width="55%"></orcid-skeleton-placeholder>
<orcid-skeleton-placeholder [accentBackground]="false" class="import-works-dialog__skeleton-line" height="21px" width="100%"></orcid-skeleton-placeholder>
<orcid-skeleton-placeholder [accentBackground]="false" class="import-works-dialog__skeleton-line" height="21px" width="80%"></orcid-skeleton-placeholder>
</div>
<div class="import-works-dialog__card-actions">
<orcid-skeleton-placeholder [accentBackground]="false" class="import-works-dialog__skeleton-btn" height="36px" width="120px"></orcid-skeleton-placeholder>
</div>
</div>
</ng-container>
<!-- Real more services links -->
<ng-container *ngIf="!loading">
<div
*ngFor="let link of moreServicesLinks"
class="import-works-dialog__card import-works-dialog__card--more"
>
<div class="import-works-dialog__card-icon" *ngIf="link.imageUrl || link.icon">
<img *ngIf="link.imageUrl" [src]="link.imageUrl" [alt]="link.name + ' logo'" class="import-works-dialog__card-img" />
<mat-icon *ngIf="!link.imageUrl && link.icon" [attr.aria-hidden]="true">{{ link.icon }}</mat-icon>
</div>
<div class="import-works-dialog__card-content">
<p class="import-works-dialog__card-title">{{ link.name }}</p>
<p class="import-works-dialog__card-description">
{{ link.description }}
</p>
</div>
<div class="import-works-dialog__card-actions">
<button
mat-stroked-button
class="import-works-dialog__btn-connect-more"
(click)="openInNewTab(link.url)"
>
{{ connectNowLabel }}
</button>
</div>
</div>
</ng-container>
</div>
</div>
</section>
</div>
</orcid-modal>
Loading