diff --git a/libs/design-system/.storybook/assets/logo/antibody-validation-reports.svg b/libs/design-system/.storybook/assets/logo/antibody-validation-reports.svg new file mode 100644 index 000000000..b2133b0a7 --- /dev/null +++ b/libs/design-system/.storybook/assets/logo/antibody-validation-reports.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/libs/design-system/.storybook/assets/logo/asctb-reporter.svg b/libs/design-system/.storybook/assets/logo/asctb-reporter.svg new file mode 100644 index 000000000..e9b5b2eb9 --- /dev/null +++ b/libs/design-system/.storybook/assets/logo/asctb-reporter.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/design-system/.storybook/assets/logo/azimuth.svg b/libs/design-system/.storybook/assets/logo/azimuth.svg new file mode 100644 index 000000000..b6d96a9b6 --- /dev/null +++ b/libs/design-system/.storybook/assets/logo/azimuth.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/libs/design-system/.storybook/assets/logo/data_portal.svg b/libs/design-system/.storybook/assets/logo/data_portal.svg new file mode 100644 index 000000000..82c37ba96 --- /dev/null +++ b/libs/design-system/.storybook/assets/logo/data_portal.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/libs/design-system/.storybook/assets/logo/eui.svg b/libs/design-system/.storybook/assets/logo/eui.svg new file mode 100644 index 000000000..e7ecb2aec --- /dev/null +++ b/libs/design-system/.storybook/assets/logo/eui.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/libs/design-system/.storybook/assets/logo/fusion.svg b/libs/design-system/.storybook/assets/logo/fusion.svg new file mode 100644 index 000000000..d417eabb2 --- /dev/null +++ b/libs/design-system/.storybook/assets/logo/fusion.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/libs/design-system/.storybook/assets/logo/hubmap.svg b/libs/design-system/.storybook/assets/logo/hubmap.svg new file mode 100644 index 000000000..95aa95d2f --- /dev/null +++ b/libs/design-system/.storybook/assets/logo/hubmap.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/libs/design-system/apps-card/ng-package.json b/libs/design-system/apps-card/ng-package.json new file mode 100644 index 000000000..c781f0df4 --- /dev/null +++ b/libs/design-system/apps-card/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "src/index.ts" + } +} diff --git a/libs/design-system/apps-card/src/index.ts b/libs/design-system/apps-card/src/index.ts new file mode 100644 index 000000000..04b8aae5b --- /dev/null +++ b/libs/design-system/apps-card/src/index.ts @@ -0,0 +1 @@ +export * from './lib/apps-card.component'; diff --git a/libs/design-system/apps-card/src/lib/apps-card.component.html b/libs/design-system/apps-card/src/lib/apps-card.component.html new file mode 100644 index 000000000..471353b33 --- /dev/null +++ b/libs/design-system/apps-card/src/lib/apps-card.component.html @@ -0,0 +1,5 @@ + + + {{ title() }} + {{ description() }} + diff --git a/libs/design-system/apps-card/src/lib/apps-card.component.scss b/libs/design-system/apps-card/src/lib/apps-card.component.scss new file mode 100644 index 000000000..d8dffbcf9 --- /dev/null +++ b/libs/design-system/apps-card/src/lib/apps-card.component.scss @@ -0,0 +1,41 @@ +:host { + a { + display: grid; + grid-template-areas: 'icon title' 'icon description'; + grid-template-columns: min-content auto; + column-gap: 1rem; + border-radius: 0.5rem; + max-width: 38rem; + align-items: center; + padding: 0.5rem; + + &:hover { + background: rgb(from var(--sys-secondary) r g b / 0.04); + } + + &:active { + background: rgb(from var(--sys-secondary) r g b / 0.08); + } + + &:focus-visible { + outline: solid var(--sys-tertiary) 2px; + } + + .icon { + grid-area: icon; + height: 3.5rem; + width: 3.5rem; + } + + .title { + font: var(--sys-label-large); + color: var(--sys-secondary); + } + + .description { + grid-area: description; + font: var(--sys-label-medium); + color: var(--sys-inverse-surface); + } + } +} diff --git a/libs/design-system/apps-card/src/lib/apps-card.component.spec.ts b/libs/design-system/apps-card/src/lib/apps-card.component.spec.ts new file mode 100644 index 000000000..89f83418a --- /dev/null +++ b/libs/design-system/apps-card/src/lib/apps-card.component.spec.ts @@ -0,0 +1,25 @@ +import { render, screen } from '@testing-library/angular'; +import { AppsCardComponent } from './apps-card.component'; + +describe('AppsCardComponent', () => { + beforeEach(async () => { + await render(AppsCardComponent, { + componentInputs: { + icon: 'test.svg', + title: 'Test Title', + description: 'Test Description', + link: 'https://www.example.com', + }, + }); + }); + + it('should create and render the card', async () => { + const cardLink = screen.getByRole('link'); + const cardImage = screen.getByRole('img'); + expect(cardImage.getAttribute('alt')).toBe('Test Title Icon'); + expect(cardImage.getAttribute('src')).toBe('test.svg'); + expect(screen.getByText('Test Title')).toBeInTheDocument(); + expect(screen.getByText('Test Description')).toBeInTheDocument(); + expect(cardLink.getAttribute('href')).toBe('https://www.example.com'); + }); +}); diff --git a/libs/design-system/apps-card/src/lib/apps-card.component.stories.ts b/libs/design-system/apps-card/src/lib/apps-card.component.stories.ts new file mode 100644 index 000000000..9a4212d9d --- /dev/null +++ b/libs/design-system/apps-card/src/lib/apps-card.component.stories.ts @@ -0,0 +1,94 @@ +import type { Meta, StoryObj } from '@storybook/angular'; +import { AppsCardComponent } from './apps-card.component'; + +const apps: Record = { + 'HuBMAP Consortium': { + icon: 'assets/logo/hubmap.svg', + title: 'HuBMAP Consortium', + description: + 'HuBMAP all access: Learn about us, our policies, data, and tools. Explore our publications and how to work with us.', + link: 'https://hubmapconsortium.org/', + }, + 'HubMAP Data Portal': { + icon: 'assets/logo/data_portal.svg', + title: 'HuBMAP Data Portal', + description: + 'Explore, visualize and download consortium-generated spatial and single cell data for the human body.', + link: 'https://portal.hubmapconsortium.org/', + }, + 'Data Portal Workspaces': { + icon: 'assets/logo/data_portal.svg', + title: 'Data Portal Workspaces', + description: + 'Access HuBMAP data in a lightweight exploration platform and perform analyses directly within the portal.', + link: 'https://portal.hubmapconsortium.org/workspaces', + }, + 'Human Reference Atlas': { + icon: 'assets/logo/hra_small.svg', + title: 'Human Reference Atlas', + description: + 'Use the HRA Portal to access atlas data, explore atlas functionality, and contribute to the Human Reference Atlas.', + link: 'https://humanatlas.io/', + }, + 'Exploration User Interface': { + icon: 'assets/logo/eui.svg', + title: 'Exploration User Interface', + description: 'Explore and validate spatially registered single-cell datasets in three-dimensions across organs.', + link: 'https://apps.humanatlas.io/eui/', + }, + 'ASCT+B Reporter': { + icon: 'assets/logo/asctb-reporter.svg', + title: 'ASCT+B Reporter', + description: + 'Explore and compare ASCT+B tables and construct validated panels for multiplexed antibody-based imaging (OMAPs) tables.', + link: 'https://hubmapconsortium.github.io/ccf-asct-reporter/', + }, + Azimuth: { + icon: 'assets/logo/azimuth.svg', + title: 'Azimuth', + description: + 'Azimuth uses a reference dataset to process, analyze, and interpret single-cell RNA-seq or ATAC-seq experiments.', + link: 'https://azimuth.hubmapconsortium.org/', + }, + FUSION: { + icon: 'assets/logo/fusion.svg', + title: 'FUSION', + description: 'Functional Unit State Identification and Navigation with WSI.', + link: 'http://fusion.hubmapconsortium.org/?utm_source=hubmap', + }, + 'Antibody Validation Reports': { + icon: 'assets/logo/antibody-validation-reports.svg', + title: 'Antibody Validation Reports', + description: + 'Provide antibody details for multiplex imaging assays and capture data requested by journals for manuscript submission.', + link: 'https://avr.hubmapconsortium.org/', + }, +}; + +const meta: Meta = { + component: AppsCardComponent, + title: 'AppsCardComponent', + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/design/BCEJn9KCIbBJ5MzqnojKQp/Design-System-Components?node-id=78-355', + }, + }, + argTypes: { + app: { + control: 'select', + options: Object.keys(apps), + mapping: apps, + }, + }, + args: { + app: apps['HuBMAP Consortium'], + }, + render: (args) => ({ + props: args['app'], + }), +}; +export default meta; +type Story = StoryObj; + +export const Primary: Story = {}; diff --git a/libs/design-system/apps-card/src/lib/apps-card.component.ts b/libs/design-system/apps-card/src/lib/apps-card.component.ts new file mode 100644 index 000000000..db9c129df --- /dev/null +++ b/libs/design-system/apps-card/src/lib/apps-card.component.ts @@ -0,0 +1,22 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +/** Apps Card Component */ +@Component({ + selector: 'hra-apps-card', + standalone: true, + imports: [CommonModule], + templateUrl: './apps-card.component.html', + styleUrl: './apps-card.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AppsCardComponent { + /** URL for the icon */ + readonly icon = input.required(); + /** Title of the card */ + readonly title = input.required(); + /** Description of the card */ + readonly description = input.required(); + /** Link of the card */ + readonly link = input.required(); +} diff --git a/libs/design-system/styles/_light-theme.scss b/libs/design-system/styles/_light-theme.scss index a422581ce..58a6cc137 100644 --- a/libs/design-system/styles/_light-theme.scss +++ b/libs/design-system/styles/_light-theme.scss @@ -60,7 +60,7 @@ $_palettes: ( neutral: ( 0: #201e3d, 10: #201e3d, - 20: #4c4c58, + 20: #4b4b5e, 25: #3c3b3b, 30: #484646, 35: #535252,