Skip to content

Flexible and customizable web component for displaying platform navigation and resource links. Built with Stencil, this component provides a clean interface for organizing and accessing multiple platform resources in a project-based context.

License

Notifications You must be signed in to change notification settings

opendevstack/ods-selector-widget

Repository files navigation

ODS Selector Widget

A flexible and customizable web component for displaying platform navigation and resource links. Built with Stencil, this component provides a clean interface for organizing and accessing multiple platform resources in a project-based context.

Features

  • 🎨 Fully Customizable: Extensive CSS custom properties for theming
  • 🔌 Framework Agnostic: Works both with Angular and React
  • 🔄 Dynamic Content: Fetches platform data from a service URL
  • 🦴 Loading States: Built-in skeleton loader and error handling
  • 🔗 Platform Selector: Dedicated platform icons with enable/disable states
  • 📑 Sectioned Layout: Organize links into logical sections with tooltips
  • 🔀 Multiple Link Types: Support for platform, project (internal), and external links with appropriate icons

Table of Contents

Installation

NPM

npm install @opendevstack/ods-selector-widget

Usage

Angular

1. Import the Component

1. Import the Component

For Angular with NgModule (traditional setup):

In your app.module.ts:

import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { defineCustomElements } from '@opendevstack/ods-selector-widget/loader';

import { AppComponent } from './app.component';

defineCustomElements(window);

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule],
  providers: [],
  bootstrap: [AppComponent],
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule { }

For Angular with Standalone Components:

In your main.ts:

import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { defineCustomElements } from '@opendevstack/ods-selector-widget/loader';

defineCustomElements(window);

bootstrapApplication(AppComponent, {
  providers: []
});

In your app.component.ts:

import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';

@Component({
  selector: 'app-root',
  standalone: true,
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  // Component logic
}

2. Configure Angular (if needed)

Note: If you encounter the error ✘ [ERROR] No loader is configured for ".map" files, you need to update your angular.json configuration.

Add the following to your architect.build.options in angular.json:

{
  "architect": {
    "build": {
      "options": {
        "customWebpackConfig": {
          "loader": {
            ".map": "empty"
          }
        }
      }
    }
  }
}

3. Use in Template

<ods-selector-widget
  project="My Project"
  service-url="https://api.example.com/platforms/{{project}}">
</ods-selector-widget>

React

import React from 'react';
import { defineCustomElements } from '@opendevstack/ods-selector-widget/loader';

// Call this once in your app initialization
defineCustomElements(window);

function App() {
  return (
    <div>
      <ods-selector-widget
        project="My Project"
        service-url="https://api.example.com/platforms/${project}"
      />
    </div>
  );
}

export default App;

For better TypeScript support in React:

// Add to your declarations file (e.g., custom-elements.d.ts)
declare namespace JSX {
  interface IntrinsicElements {
    'ods-selector-widget': {
      project?: string;
      'service-url'?: string;
    };
  }
}

Configure React + Vite (if needed)

Note: If you encounter the error No loader is configured for ".map" files in a React + Vite project, update your vite.config.js or vite.config.ts to exclude .map files from dependency optimization.

Add the following to your Vite config:

// vite.config.js or vite.config.ts
export default {
  optimizeDeps: {
    exclude: ['*.map']
  }
}

Properties

Property Attribute Type Default Description
project project string undefined The project name displayed in the widget header
serviceUrl service-url string undefined The service URL to fetch platform data. Use ${project} as a placeholder that will be replaced with the project name

Example

<ods-selector-widget
  project="PROJECT1"
  service-url="https://api.myapp.com/platforms/${project}">
</ods-selector-widget>

API Response Format

The component expects the service URL to return JSON data in the following format:

{
  "sections": [
    {
      "section": "Select your platform",
      "tooltip": "",
      "links": [
        {
          "label": "Platform One",
          "url": "https://platform1.com",
          "abbreviation": "P1",
          "type": "platform"
        },
        {
          "label": "Platform Two",
          "url": "https://platform2.com",
          "abbreviation": "P2",
          "type": "platform",
          "disabled": true
        },
        {
          "label": "Platform Three",
          "url": "https://platform3.com",
          "abbreviation": "P3",
          "type": "platform",
          "disabled": true
        }
      ]
    },
    {
      "section": "Documentation",
      "tooltip": "Access project documentation and guides",
      "links": [
        {
          "label": "API Reference",
          "url": "https://docs.example.com/api",
          "tooltip": "Complete API documentation",
          "type": "external"
        },
        {
          "label": "Getting Started",
          "url": "https://docs.example.com/getting-started",
          "tooltip": "Quick start guide",
          "type": "project"
        }
      ]
    },
    {
      "section": "Tools",
      "tooltip": "Development and monitoring tools",
      "links": [
        {
          "label": "Dashboard",
          "url": "https://dashboard.example.com",
          "tooltip": "Project dashboard",
          "type": "external"
        }
      ]
    }
  ]
}

API Response Schema

  • sections (array): Array of content sections to display. Each section can contain either platform links or regular resource links.
    • section (string): Section title
    • tooltip (string, optional): Tooltip text for the section header
    • links (array): Array of links in this section
      • label (string): Link display text
      • url (string): Link destination URL
      • type (string): Link type - "platform", "project", or "external"
        • "platform": Renders as platform selector icons (when all links in a section are platform type)
        • "project": Renders as list item with internal link arrow icon
        • "external": Renders as list item with external link squared arrow icon
      • tooltip (string, optional): Tooltip text for the link (shown on hover for non-platform links)
      • abbreviation (string, optional): Short text shown in platform icon (required for type: "platform")
      • disabled (boolean, optional): If true, the platform link is disabled and shown as non-clickable (only applicable for type: "platform")

Rendering Behavior

The component automatically adapts its rendering based on the link types within each section:

  • Platform Section: If all links in a section have type: "platform", they are rendered as clickable platform icons in a horizontal layout. This is typically used for the main platform selector section.

  • Link List Section: If a section contains any non-platform links (type: "project" or type: "external"), all links in that section are rendered as a vertical list with appropriate arrow icons split in two columns.

Example:

{
  "sections": [
    {
      "section": "Platforms",
      "links": [
        { "label": "Platform 1", "url": "...", "abbreviation": "P1", "type": "platform" },
        { "label": "Platform 2", "url": "...", "abbreviation": "P2", "type": "platform" }
      ]
    }
  ]
}

The example above renders as platform icons

{
  "sections": [
    {
      "section": "Resources",
      "links": [
        { "label": "Documentation", "url": "...", "type": "external" },
        { "label": "Dashboard", "url": "...", "type": "project" }
      ]
    }
  ]
}

The example above renders as a list with arrow/squared arrow icons.

Styling

The component uses CSS custom properties (CSS variables) for easy theming. You can override these in your stylesheet:

Available CSS Custom Properties

ods-selector-widget {
  /* Font family */
  --ods-selector-widget-font-family: 'Inter', sans-serif;

  /* Primary colors */
  --ods-selector-widget-color-primary: #08312A;
  --ods-selector-widget-color-white: #FFF;
  --ods-selector-widget-color-border: #5C5B59;
  --ods-selector-widget-color-shadow: rgba(0, 0, 0, 0.05);
  --ods-selector-widget-color-shadow-hover: rgba(0, 0, 0, 0.25);

  /* Header colors */
  --ods-selector-widget-header-bg: #CCFAE5;
  --ods-selector-widget-header-text: #08312A;

  /* Platform icon colors */
  --ods-selector-widget-platform-icon-bg: #08312A;
  --ods-selector-widget-platform-icon-text: white;
  --ods-selector-widget-first-platform-bg: #008E4C;
  --ods-selector-widget-first-platform-text: #ffffff;
  --ods-selector-widget-second-platform-bg: #5E71FF;
  --ods-selector-widget-second-platform-text: #ffffff;
  --ods-selector-widget-third-platform-bg: #00C86B;
  --ods-selector-widget-third-platform-text: #ffffff;

  /* Disabled state colors */
  --ods-selector-widget-disabled-bg: #E5E3DE;
  --ods-selector-widget-disabled-text: #898885;

  /* Section colors */
  --ods-selector-widget-section-text: #08312A;
  --ods-selector-widget-divider-color: #D3D3D3;

  /* Link colors */
  --ods-selector-widget-link-text: #08312A;
  --ods-selector-widget-link-hover: #6B8375;

  /* Error section colors */
  --ods-selector-widget-error-text: #051D19;
  --ods-selector-widget-error-button-border: #08312A;
  --ods-selector-widget-error-button-text: #08312A;
  --ods-selector-widget-error-button-hover-text: #6B8375;
  --ods-selector-widget-error-button-hover-border: #6B8375;

  /* Tooltip colors */
  --ods-selector-widget-tooltip-bg: #051D19;
  --ods-selector-widget-tooltip-text: #fff;

  /* Skeleton loader colors */
  --ods-selector-widget-skeleton-bg: #F6F5F3;
  --ods-selector-widget-skeleton-shimmer: #e4e3e2;
}

Example: Custom Theme

ods-selector-widget {
  --ods-selector-widget-font-family: "YourCustomFont", sans-serif;
  --ods-selector-widget-color-primary: #2563eb;
  --ods-selector-widget-header-bg: #dbeafe;
  --ods-selector-widget-header-text: #1e40af;
  --ods-selector-widget-first-platform-bg: #10b981;
  --ods-selector-widget-second-platform-bg: #8b5cf6;
  --ods-selector-widget-third-platform-bg: #f59e0b;
}

Development

Prerequisites

  • Node.js (v14 or higher)
  • npm (v6 or higher)

Setup

# Clone the repository
git clone https://github.com/opendevstack/ods-selector-widget.git
cd ods-selector-widget

# Install dependencies
npm install

Available Scripts

# Start development server with live reload
npm start

# Build for production
npm run build

# Run tests
npm test

# Run tests in watch mode
npm run test.watch

# Generate a new component
npm run generate

Project Structure

ods-selector-widget/
├── src/
│   ├── components/
│   │   └── ods-selector-widget/
│   │       ├── ods-selector-widget.tsx    # Component logic
│   │       ├── ods-selector-widget.css    # Component styles
│   │       ├── ods-selector-widget.spec.ts # Unit tests
│   │       └── ods-selector-widget.e2e.ts  # E2E tests
│   ├── index.html    # Demo page
│   └── index.ts      # Entry point
├── dist/             # Build output
├── www/              # Dev server output
└── stencil.config.ts # Stencil configuration

Testing

The component includes both unit and end-to-end tests:

# Run all tests
npm test

# Run only unit tests
npm run test -- --spec

# Run only e2e tests
npm run test -- --e2e

# Generate coverage report
npm test -- --coverage

Browser Support

This component works in all modern browsers that support:

  • Custom Elements V1
  • Shadow DOM
  • ES Modules

For older browsers, you may need to include polyfills.

Contributing

Contributions are welcome! Please follow these guidelines:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Contribution Guidelines

  • Write clear, descriptive commit messages
  • Add tests for new features
  • Update documentation as needed
  • Follow the existing code style
  • Ensure all tests pass before submitting PR

License

This project is licensed under the Apache License - see the LICENSE file for details.

Support

If you encounter any issues or have questions:

Acknowledgments

Built with Stencil - A toolchain for building reusable, scalable Design Systems.

About

Flexible and customizable web component for displaying platform navigation and resource links. Built with Stencil, this component provides a clean interface for organizing and accessing multiple platform resources in a project-based context.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published