Skip to content

Latest commit

 

History

History
329 lines (250 loc) · 11.2 KB

File metadata and controls

329 lines (250 loc) · 11.2 KB

UI Styleguide for B2B Angular Application

Welcome to the UI Styleguide for Apache StreamPipes.
This guide defines the visual language, interaction patterns, components, and coding standards that ensure a consistent and scalable user experience.

This guide is the place for concrete component usage and markup. Tokens, colour roles, the typography scale, elevation and the named design rules are defined in the repository-root DESIGN.md, which is normative when the two disagree; product intent and anti-references are in PRODUCT.md.


Design Tokens

  • Color tokens: _theme-colors.scss (can be overridden by users for individual theming)
  • Custom variables: _custom-variables.scss (can be overriden by users for individual theming)
  • General variables: _variables.scss
  • Typography: _typography.scss
  • Spacing: _spacing.scss

4. UI Components

Basic Layouts

Page-level views use sp-basic-view as their full-height shell. Hide its legacy toolbar when the page has a title and compose the page identity, navigation, and content in this order:

<sp-basic-view [hideNavbar]="true" [padding]="true">
  <sp-page-header
    [title]="pageTitle"
    [description]="pageDescription"
    icon="settings"
    iconColor="var(--color-primary)"
    [backLinkTarget]="['overview']"
  >
    <div pageActions>
      <!-- Page-wide status, identifiers, and actions belong here. -->
    </div>
  </sp-page-header>

  <sp-page-nav-tabs
    [spNavigationItems]="tabs"
    [activeLink]="activeLink"
    [ariaLabel]="'Details' | translate"
  ></sp-page-nav-tabs>

  <div class="page-content">
    <!-- Active view content -->
  </div>
</sp-basic-view>

The page header leads, optional sibling-view navigation follows immediately, and the active content starts after one deliberate spacing interval. Use --space-lg above the content and reduce it to --space-md in narrow containers. Do not add an outer page margin or another padded navigation wrapper inside sp-basic-view; its padding input owns the page inset.

When multiple routes share the same identity and tabs, create a small feature layout component around this composition and project route-specific content and pageActions into it. This keeps loading, not-found, responsive, and header metadata behavior consistent across sibling views.

sp-basic-nav-tabs is a legacy compatibility wrapper. Do not use it for new page-level views or when migrating an existing view. Use sp-page-nav-tabs below sp-page-header instead. It scrolls horizontally on narrow screens; do not compress, wrap, or duplicate the tab row.

If the tabs switch local content rather than sibling routes, use Angular Material tabs with the shared page-navigation treatment:

<mat-tab-group class="sp-page-tabs" [mat-stretch-tabs]="false">
  <mat-tab [label]="'Overview' | translate"></mat-tab>
  <mat-tab [label]="'Details' | translate"></mat-tab>
</mat-tab-group>

Reserve sp-page-tabs for the primary tab row directly below sp-page-header. Tabs embedded in dialogs, editors, or panels keep the default compact Material styling.

Secondary Toolbar

Use sp-secondary-toolbar below sp-page-header (and page navigation, when present) for content controls such as filters, view options, or selection actions. Import SpSecondaryToolbarComponent from @streampipes/shared-ui into the consuming component. It works without a workspace and projects arbitrary content:

<sp-secondary-toolbar>
  <div
    fxLayout="row wrap"
    fxLayoutAlign="start center"
    fxLayoutGap="var(--space-sm)"
  >
    <button mat-flat-button class="btn-secondary" (click)="resetFilters()">
      {{ 'Reset filters' | translate }}
    </button>
    <!-- Additional filters or view controls -->
  </div>
</sp-secondary-toolbar>

The toolbar supplies the shared surface, bottom divider, and compact spacing. The consumer owns control layout, accessible labels, and behavior. Set [padding]="false" when projecting a component that already supplies spacing. An empty toolbar is hidden. sp-workspace-container uses this component internally; existing content marked with workspaceToolbar needs no changes.

Headers and Titles

Use sp-page-header for the single page-level title. Give top-level domain pages their established Material icon and semantic color variable. Colors must come from the deployment theme; never resolve or hard-code a domain color in a feature component.

Place page-wide actions, compact status labels, and copyable identifiers in the pageActions slot. Repeated utility actions such as refresh should be icon-only buttons with an accessible label and tooltip. Keep section-specific actions in the corresponding sp-split-section action slot.

Use sp-basic-header-title-component only for embedded headings where a sp-split-section is not appropriate:

<sp-basic-header-title-component [title]="A" [description]="B" [level]="1">
</sp-basic-header-title-component>

Level can be either 1, 2 or 3. Do not use level 1 as a second page title below sp-page-header. Prefer sp-split-section for titled content groups.

Sections

In some views it might make sense to organize the layout based on panels.

<sp-split-section [title]="A" [subtitle]="B" [level]="2"> </sp-split-section>

Use level to control the size of the section header and margins. In views with enough space, we use level=2. In dialogs and in dense layouts, we use level=3.

Buttons

Buttons are defined as follows:

<button mat-flat-button>
  optional icon: use <mat-icon></mat-icon> wrap the text in a span blog:
  <span>Text</span>
</button>

Always use mat-flat-button style.

There are different forms of buttons that we can use:

  • Primary buttons are rendered when no other CSS classes are applied. Primary buttons serve to identify an action.
  • Secondary buttons are applied with the btn-secondary css class (for legacy reasons, also mat-basic is possible)
  • Warning/Error buttons are applied with the btn-warn css class.

Smaller buttons can be applied with the small-button css class. Use small buttons only in dense layouts.

Forms

Never use the Angular Material mat-label and floating labels.

To show form inputs, we can wrap a form element into a sp-form-field block:

<sp-form-field [level]="2" [label]="Label" [description]="Description">
  form content
</sp-form-field>

To render smaller inputs in a dense layout, assign the CSS class form-field-small.

You can also define an optional tooltip which is shown above the label.

Search Select

Use sp-search-select when users need to select one or more items from a searchable list, such as datasets, labels, sites, asset types, users, roles or groups.

Keep data loading, persistence and feature-specific actions outside the component. For example, actions such as Manage Labels or refresh buttons should remain in the parent view, usually in the surrounding sp-form-field actions.

Single-select example:

<sp-search-select
  [items]="availableMeasurements"
  [(value)]="selectedMeasurement"
  [placeholder]="'Search datasets' | translate"
>
</sp-search-select>

Multi-select example:

<sp-search-select
  [items]="labels"
  [(value)]="selectedLabels"
  [multiple]="true"
  [placeholder]="'Add labels' | translate"
>
</sp-search-select>

The component keeps the selected value as the full object. It displays items by convention using label, name, measureName, title, email, groupName, value, filename, assetName, _id or id, and filters client-side by the displayed value.

Objects with a color property are rendered as small sp-label badges in both the selected value and the dropdown. This covers labels without adding label-specific inputs to the component:

<sp-search-select
  [items]="labels"
  [(value)]="selectedLabels"
  [multiple]="true"
  [placeholder]="'Add labels' | translate"
>
</sp-search-select>

Use optional templates only when the default text or colored-label rendering is not enough:

<sp-search-select
  [items]="users"
  [(value)]="selectedUsers"
  [multiple]="true"
  [placeholder]="'Add users' | translate"
>
  <ng-template spSearchSelectOption let-user>
    {{ user.email }} ({{ user.principalId }})
  </ng-template>

  <ng-template spSearchSelectChip let-user> {{ user.email }} </ng-template>
</sp-search-select>

Do not add feature-specific inputs such as label color keys, server-side search, action slots or custom comparison functions unless there is a concrete reusable need. Prefer the minimal API and keep feature behavior in the parent component.

Label

Use form labels to ensure a consistent layout of forms and labels. In cases where the sp-form-field wrapper is not used, the label component can also be accessed directly:

<sp-form-label [level]="2" [label]="Label" [description]="Description">
</sp-form-label>

Alert Banners

Alert banners are used to show error/info/warning/success messages. Use it as follows:

<sp-alert-banner type="info" [title]="Hello" [description]="World">
  Additional content
</sp-alert-banner>

Allowed types are info, warning, error and success. You can also add additional content to the banner.

Progress bar

Use sp-progress-bar when real progress is available. Provide the current value, the max value, and optional title or item label text.

<sp-progress-bar
  [title]="'Uploading CSV data' | translate"
  [ariaLabel]="'CSV import progress' | translate"
  [value]="processedRows"
  [max]="totalRows"
  [itemLabel]="'rows imported' | translate"
></sp-progress-bar>

Spinner

Use sp-spinner for indeterminate loading states where no real progress value is available. Prefer it over direct mat-spinner usage to keep loading indicators consistent.

<sp-spinner [text]="'Loading assets' | translate" [diameter]="30"></sp-spinner>

For compact inline loading states, use a smaller diameter and row layout:

<sp-spinner [diameter]="20" layout="row"></sp-spinner>

Tables

For rendering tables, always use the sp-table component which comes with pre-defined features for paging, sorting and layout. In most cases, table actions should be shown in a popup menu to ensure a clean UI. Check the examples to see how to add table actions.

Localization & Internationalization (i18n)

Always prepare strings for translation:

{{ 'XYZ' | translate }}
<my-component [label]="'ABC' | translate"></my-component>