Peek Theme Documentation

_images/peek_ios_display_field-switching.png

The main aim of the Peek application is to display and transmit data.

What is Peek

Peek is a semi distributed pluggable python platform.

Plugins are installed across the peek services and communicate with other plugins to retrieve, transmit, store or display data.

Peek provides a platform for Python similar to the functionality JBOSS provides for JAVA. (Or at least that is in the intention, it’s early days)

The Big Bang

Peek was created and is maintained by Synerty to be a distributed, pluggable python platform that provides many of the core services needed for enterprise applications.

We wanted to integrate smaller pieces of code, that can leverage different existing boilerplate code which the platform provides. For example, services for parallel processing or services for business integrations.

The Peek Platform allows developers to better write and integrate smaller units of code.

Synerty uses the Peek platform to provide scalable enterprise grade applications to the power utilities sector.

Bootstrap

The scss for the peek app is based upon bootstrap. For more detail to bootstrap documentation please visit BootStrap.

The bootstrap classes that are related to the layouts will only work on HTML, not NativeScript. Therefore the theme will avoid selecting by bootstrap classes that are related to layouts.

The looks and feel classes are to be used. These will need to be styled from scratch for NativeScript.

The scss will be structured in such a way to ignore hierarchy and tag selection.

Note

NativeScript does not use Bootstrap for layout.

NativeScript User Interface

The user interface of NativeScript mobile apps consists of pages. Typically, the design of the user interface is developed and stored in XML files, styling is done via CSS and the business logic is developed and stored in JavaScript or TypeScript files.

Style Guide

Design Objective

The objective of this project is to stylise the existing layout to make it very impressive without changing the HTML / javascript of a page to a large extent. The job mainly involves CSS/SCSS upgrade to the base Bootstrap theme.

This app will be viewed predominately during the day. The design and layout must be clear to read in very bright sunlight.

_images/peek_app.web.jpg

Design Overview

_images/design-layouts-PeekUI.jpg
Design requirements
  1. Data must be
    1. Readable in daylight
    2. Without transparent backgrounds
  2. Large icons with text in the icons on home page
  3. Home page icons need to be more like apple icons
  4. Home page design must be impressive
  5. All screens do not need to have the same background
  6. Other screens must have static background to avoid distractions
  7. Use Nodal background as used in Peek App Branding
  8. Each icon on the home screen represents and App / Plugin and the background image for each App can change when a user clicks into it, hence having its own subtle branding but still share allot of common elements in the entire app.
Design restrictions
  1. Design must not be dark or have a dark background

Colours

A primary colour refers to a colour that appears most frequently in your app.

A secondary colour refers to a colour used to accent key parts of your UI.

The primary and secondary colours have been selected to ensure sufficient colour contrast between elements so that all users can see and use the app.

Primary Colour (Brand)

A primary colour is the color displayed most frequently across your app’s screens and components. It can also be used to accent elements, if you don’t have a secondary color.

To create contrast between elements, you can use lighter or darker tones of your primary color. The contrast between lighter and darker tones helps show division between surfaces, such as between the status bar and a toolbar.

_images/primary-colour.jpg
Secondary Colour

A secondary colour is used to accent select parts of your UI. It can be complementary or analogous to your primary colour, but it should not simply be a light or dark variation of your primary colour. It should contrast with elements that surround it and be applied sparingly as an accent.

Secondary colours are best used for:

  • Buttons, floating action buttons, and button text
  • Text fields, cursors, and text selection
  • Progress bars
  • Selection controls, buttons, and sliders
  • Links
  • Headlines
_images/secondary-colour.jpg

Typography

Font

Source (Google fonts): Play

Colours and Contrast

A text colour that is too similar to the background colour is hard to read. Text with too much contrast can also be hard to read. This is especially true of light-coloured text against dark backgrounds.

Text on the primary, primary-dark, secondary or secondary-dark will be coloured white #ffffff.

As a general rule of thumb in the Peek application text displaying data is coloured black #000000 to draw focus, text displaying information is coloured secondary-dark #707070 to avoid taking away focus from the displayed data.

Layout

Peek plugins can consist of the following:

  • Navigation Section, located at the top of the screen. Within the Navigation Section Navigation buttons are grouped together and located on the left of the screen. Action buttons are grouped located to the right of the screen. Previous and Next buttons are grouped with and located to the right of the action buttons.


  • Information Section, the landing screen of a plugin used to describe and display required information on opening the plugin such as active user.

  • Details Section, presents data (text, numbers, images, or other data) of importance.

  • Tables Section, best suited when there’s logical relationships among text, numbers, images, or other data exist in two dimensions (vertical and horizontal).

The Peek plugin contents will always be display between the header at the top and footer at the bottom.

Note

Customising plugins layout outside of the guides directions is up to the developer.

Components

TODO:

Header dynamic buttons

Footer dynamic buttons

Patterns

TODO:

Confirming an action to be completed with the Mobile Dialog Section.

Platform

Design conventions can differ from platform to platform. These differences in convention can affect the user’s ability to understand the UI or complete certain tasks.

Peek is to be designed to function identically across all platforms.

Operating system

iOS, Android and Web.

Future development: Microsoft app.

Devices

The application has been developed for screens of a resolution greater than, 1136 x 640 pixels. This is the iPhone 5 resolution.

Note

The application will function on devices with lower resolution but may not display correctly.

Tabs Section

The Tabs Section is positioned below the Title Bar, below the Navigation Section, above the plugin screen and contains buttons that route to other tab contents toggling the data presented.

The sample below shows an example of tab navigation of the inbox plugin. The ‘Inbox’ is presented as the active tab and the ‘Activity’ is presented as the inactive tab.

_images/tabs_section.web.jpg

The Tabs Section serves as screen content control.

If a Tabs Section is required it is constructed by the plugin screen.

The buttons remain a fixed size throughout a responsive lifecycle. The buttons are sized around the text they contain. The active tab button uses the primary colour styling and is slightly taller than the selectable inactive tab button.

Note

The buttons require a different theme to the Title Bar and generic peek theme buttons.

Classes

The .peek-tabs-section class contains the looks classes specific to the Tabs Section.

.peek-tabs-section {
  /* Contains the Tabs Section attributes */
      ...

  .btn-group {
    /* Contains the attributes unique to the Tabs Section */

    .tabs-section-btn {
      /* Contains the Button attributes unique to the Tabs Section */

          ...

    }
    .tabs-section-btn.active {
      /* Contains the Button attributes for the active tab unique to the Tabs Section */
          ...

    }
    .tabs-section-btn-divider {
      /* Contains the button divider attributes unique to the Tabs Section */
          ...

    }
    .tabs-section-btn-disabled {
      /* Contains the button disabled attributes unique to the Tabs Section */
          ...

    }
  }
}

.peek-tabs-bar-padding {
  /* Provides padding for the screen under the Tabs Section */
      ...

}

SCSS Files

The Tabs Section style classes are found in the _tabs_section.scss.

The Tabs Section HTML layout classes are found in the _tabs_section.web.scss.

The Tabs Section NativeScript layout classes are found in the _tabs_section.ns.scss.

HTML

The peek-tabs-section is to be included before the code of the plugin screen requiring Tabs.

The tabs-section-btn-divider and tabs-section-btn-disabled classes are not required in the Web app. Their attributes are handled by pseudo-selectors of tabs-section-btn.

<div class="peek-tabs-section">
    <div class="btn-group" role="group">
        <Button class="tabs-section-btn"
                [class.active]="barIndex == 0"
                (click)="barIndex = 0">
            Inbox
        </Button>
        <Button class="tabs-section-btn"
                [class.active]="barIndex == 1"
                (click)="barIndex = 1">
            Activity
        </Button>
    </div>
</div>

NativeScript

The peek-tabs-section is to be included before the code of the plugin screen requiring Tabs.

The tabs-section-btn-divider and tabs-section-btn-disabled classes are required in the NativeScript app. Pseudo-selectors applied in the SCSS are not supported by NativeScript.

tabs-section-btn-divider will set the right side border of the button.

tabs-section-btn-disabled applies the disabled styling.

<StackLayout class="peek-tabs-section">
    <GridLayout class="btn-group" rows="auto" columns="auto, auto, *">
        <Button row="0" col="0"
                class="tabs-section-btn"
                [class.active]="barIndex == 0"
                text="Inbox"
                (tap)="barIndex = 0"></Button>
        <Button row="0" col="1"
                class="tabs-section-btn"
                [class.active]="barIndex == 1"
                text="Activity"
                (tap)="barIndex = 1"></Button>
    </GridLayout>
</StackLayout>

Mobile Dialog Section

The Mobile Dialog Section presents inputs and/or options to the Peek app user. It can involve a select drop down with a confirm and cancel buttons as per the example below.

_images/mobile_dialog_section.web.jpg

The input types can be customised by the developer depending on the plugin requirements.

Uses:

  • List Selection
  • Text Input
  • File Select
  • Action Confirm

Any plugin screen dialog will be able to use the .mobile-dialog attributes.

Classes

The .mobile-dialog class contain the classes specific to a Mobile Dialog Section.

.mobile-dialog {
/* Contains the Mobile Dialog Section looks classes unique for mobile devices */
    ...

    .dialog-label {
    /*
        Contains the label attributes unique to the Mobile Dialog Section
    */
        ...

    }
    .dialog-selector {
    /*
        Contains the selector attributes unique to the Mobile Dialog Section
    */
        ...

    }

    .dialog-btn-block {
    /*
        Contains the btn block attributes unique to the Dialog Mobile Section
    */
        ...

    }

    .dialog-action-btn-group {
    /*
        Contains the action button group attributes unique to the Dialog Mobile
        Section
    */
        ...

    }

    .dialog-action-btn {
    /*
        Contains the action button attributes unique to the Mobile Dialog Section
    */
        ...

    }
}

SCSS Files

The Mobile Dialog Section style classes are found in the _mobile_dialog_section.scss.

The Mobile Dialog Section HTML layout classes are found in the _mobile_dialog_section.web.scss.

The Mobile Dialog Section NativeScript layout classes are found in the _mobile_dialog_section.ns.scss.

HTML

The Mobile Dialog Section uses Bootstraps Forms.

Refer to the Forms for more information about creating Forms using Bootstrap.

Below is the HTML code extract op-confirm.component shown in the image at the top of, Mobile Dialog Section:

<div class="mobile-dialog" [@dialogAnimation]="dialogAnimationState"
     (@dialogAnimation.done)="animationDone($event)">
    <div class="container-fluid">

        <div class="form-group">
            <div class="dialog-label"
                 for="operationDate">Operation Date / Time :
            </div>
            <input id="operationDate" class="dialog-selector form-control"
                   [(ngModel)]="inputData.operationDate" ng2-datetime-picker
                   close-on-select="false"
                   date-format="DD-MMM-YYYY HH:mm"/>

        </div>
        <div class="form-group">
            <div class="dialog-label text-muted">Request Further Instructions :
                <button class="dialog-action-btn btn-sm"
                        (click)="inputData.requestFurtherInstructions=!inputData.requestFurtherInstructions"
                        [class.btn-success]="inputData.requestFurtherInstructions"
                        type="button">{{inputData.requestFurtherInstructions ? "Yes" :
                    "No"}}
                </button>
            </div>
        </div>

        <!--BEGIN HANDBACK DIALOG -->
        <div class="btn-group pull-right">
            <Button class="dialog-action-btn" (click)="webConfirmClicked()">
                {{inputData.actionName}}
            </Button>

            <Button class="dialog-action-btn" (click)="cancelClicked(false)">Cancel
            </Button>
        </div>
    </div>
</div>

NativeScript

The Mobile Dialog Section uses the NativeScript recursive layout system.

The StackLayout defines the horizontal groups of GridLayout Content is placed in the GridLayout that is the immediate child of the StackLayout.

Refer to the ListPicker for more information about using NativeScript ListPicker.

Below is the NativeScript code extract op-confirm.component:

<StackLayout class="mobile-dialog">
    <StackLayout class="input-field" horizontalAlignment="stretch">

        <GridLayout rows="auto, auto" columns="auto, auto">
            <Label row="0" col="0" colspan="2"
                   class="dialog-label" text="Operation Date / Time :"></Label>
            <!--<GridLayout columns="*,*" rows="auto">-->
            <DatePicker class="dialog-selector" row="1" col="0" #datePicker
                        (loaded)="nsConfigureDate(datePicker)"
                        (dateChange)="nsDateChanged($event)">
            </DatePicker>
            <TimePicker class="dialog-selector" row="1" col="1" #timePicker
                        (loaded)="nsConfigureTime(timePicker)"
                        (timeChange)="nsTimeChanged($event)">

            </TimePicker>
        </GridLayout>

        <!--</GridLayout>-->

        <WrapLayout>
            <Label class="dialog-label"
                   text="Request Further Instructions : " textWrap="true"
            ></Label>
            <Switch #furtherInstruct
                    [checked]="inputData.requestFurtherInstructions"
                    (checkedChange)="inputData.requestFurtherInstructions = furtherInstruct.checked"
            ></Switch>
        </WrapLayout>
    </StackLayout>


    <GridLayout columns="*,*" rows="auto">
        <Button class="dialog-action-btn" col="0" [text]="inputData.actionName"
                (tap)="nsConfirmClicked()"></Button>
        <Button class="dialog-action-btn" col="1" text="Cancel"
                (tap)="cancelClicked(true)"></Button>
    </GridLayout>

</StackLayout>

Information Section

The Information Section shows useful plugin related descriptions, information and / or instructions. This can include data from other plugins.

Ideally the Information Section is used as the landing page before presenting the plugin screens. It could be used throughout a plugin if required.

_images/information_screen.web.jpg

The Information Section should provide the Peek App user any relevant information needed to use a plugin.

Uses:

  • Initial landing page
  • Sub section landing page (instructions for part of a plugin that may function differently)

Any plugin Screen will be able to use the .peek-information-section attributes.

Classes

The .peek-information-section class contain the classes specific to a Information Section.

.peek-information-section {
  /*
      Contains the Information Section classes
  */
  ...

  .information-section-icon {
    /*
        Contains the icon attributes unique to the peek-information-section class
    */
    ...

  }
  .information-section-title {
    /*
        Contains the title attributes unique to the peek-information-section class
    */
    ...

  }
}

SCSS Files

The Information style classes are found in the _information_section.scss.

The Information Section HTML layout classes are found in the _information_section.web.scss.

The Information Section NativeScript layout classes are found in the _information_section.ns.scss.

HTML

<div class="peek-information-section">
    <div class="information-section-title">Welcome to Field Switching</div>
    <img class="information-section-icon"
         src="/assets/peek_plugin_pof_field_switching/plugin_icon.png">

    <div class="p">Peek Field Switching allows field engineers working on the
        electricity network to electronically
        <ul>
            <li>View switching instructions</li>
            <li>Receive instructions from the control room</li>
            <li>And field confirm field switching operations</li>
        </ul>
    </div>

    <hr>
    <div class="information-section-title">Logged in as {{userDetails.displayName}}
    </div>
</div>

NativeScript

<StackLayout class="peek-information-section">
    <Image class="information-section-icon"
           src="~/assets/peek_plugin_pof_field_switching/plugin_icon.png"></Image>

    <label class="information-section-title"
           text="Welcome to Field Switching"></label>
    <label class="p"></label>

    <label class="p"
           textwrap="true"
           text="Peek Field Switching allows field engineers working on the electricity network to electronically:"></label>
    <label class="p"></label>

    <label class="p" text="* View switching instructions"></label>
    <label class="p" text="* Receive instructions from the control room"></label>
    <label class="p" text="* And field confirm field switching operations"></label>
    <label class="p"></label>

    <label class="information-section-title"
           text="Logged in as {{userDetails.displayName}}"></label>
</StackLayout>

Details Section

The Details Section presents data (text, numbers, images, or other data) of importance to the Peek app user. It involves enumerating important characteristics, emphasizing significant figures and identifying important features of data.

_images/details_section.web.jpg

Ideally this section will be configured to present only required data to the user reducing the need for the Peek app user scrolling / filtering through unnecessary data. Prioritises information by providing focus to the values.

Uses:

  • Instructions
  • Itinerary
  • Form Data (displaying not editing)

Any plugin Screen will be able to use the .peek-details-section attributes.

Classes

The .peek-details-section class contain the classes specific to a Details Section.

.peek-details-section {
/* Contains the Details Section looks classes */
    ...

    .details-section-title {
    /*
        Contains the title attributes unique to the Details Section
        this text will have the text-muted effect
    */
        ...

    }
    .details-section-value {
    /*
        Contains the value attributes unique to the Details Section
        text to have the focus of attention
    */
        ...
        .multiline {
        /*
            For HTML.
            This class is to be used for multi-line support.
            Whitespace is preserved by the browser. Text will wrap when
            necessary, and on line breaks.  Must be in a span
        */
            ...

        }
        .editable {
        /*
            Contains the editable attributes of one line of text unique to the .details-section-value class
        */
            ...

        }

        //Select lists
            ...

        }

        //Single line inputs
            ...

        }

        //Multi line inputs
            ...

        }

        .editable-md {
          /*
              Contains the editable attributes of two lines of text unique to the .details-section-value class
          */
            ...

        }

        .editable-lg {
          /*
              Contains the editable attributes of three lines of text unique to the .details-section-value class
          */
            ...

        }
    }

    .details-section-btn {
      /*
          Contains the generic button attributes unique to the .peek-details-section class
      */
        ...

    }

    .btn-group {

        .details-section-btn {
          /*
            Contains the generic button attributes inside a .btn-group unique to the .peek-details-section class
          */
            ...

        }
        .details-section-btn.active {
          /*
            Contains the Button attributes for the active button unique to the Details Section
          */
            ...

        }

        .details-section-btn-divider-left {
          /*
            Contains the button divider attributes inside a .btn-group unique to the .peek-details-section class
          */
            ...

        }
    }

    .details-section-btn-disabled {
    /*
        Contains the button disabled attributes .peek-details-section class
    */

    }
}

SCSS Files

The Details style classes are found in the _details_section.scss.

The Details Section HTML layout classes are found in the _details_section.web.scss.

The Details Section NativeScript layout classes are found in the _details_section.ns.scss.

HTML

The Details Section uses Bootstraps Grid System.

A Container contains row’s. Row create horizontal groups of columns, rows are made up of 12 columns. Content is placed in columns and only column’s can be immediate children of row’s.

Refer to the Grid System for more information about creating page layouts using the Bootstrap grid system.

Below is the HTML code extract of three rows:

<div class="peek-nav-bar-padding peek-details-section">
    <div class="container-fluid">
        <!--Displayed form data -->
        <div class="row">
            <div class="col-xs-6">
                <div class="details-section-title">
                    Control Engineer
                </div>
                <div class="details-section-value">
                    {{job.activeControlEngineer}}
                </div>
            </div>
            <div class="col-xs-6">
                <div class="details-section-title">
                    Field State
                </div>
                <div class="details-section-value">
                    {{job.fieldStatus.niceName}}
                </div>
            </div>
        </div>

        <hr>
        <div class="row">
            <div class="col-xs-12">
                <div class="details-section-title">
                    Name
                </div>
                <div class="details-section-value">
                    {{job.jobName}}
                </div>
            </div>
        </div>

        <hr>
        <div class="row">
            <div class="col-xs-12">
                <div class="details-section-title">Work Description</div>
                <div class="details-section-value">
                    <span class="multiline">{{job.workSummary}}</span>
                </div>
            </div>
        </div>

        <hr>

NativeScript

The Details Section uses the NativeScript recursive layout system.

The StackLayout defines the horizontal groups of GridLayout Content is placed in the GridLayout that is the immediate child of the StackLayout.

Below is the NativeScript code extract of two rows from the screenshot in the beginning of the Details Section:

<StackLayout class="peek-details-section">
    <GridLayout rows="auto, auto" columns="*, *">
        <!-- Column 1 -->
        <Label row="0" col="0" class="details-section-title"
               text="Control Engineer"></Label>
        <Label row="1" col="0" class="details-section-value" textWrap="true"
               [text]="job.activeControlEngineer"></Label>
        <!-- Column 2 -->
        <Label row="0" col="1" class="details-section-title"
               text="Field State"></Label>
        <Label row="1" col="1" class="details-section-value"
               [text]="job.fieldStatus.niceName"></Label>
    </GridLayout>

    <!-- Spacer -->
    <Label class="h3" text=""></Label>

    <!--<hr>-->
    <GridLayout rows="auto, auto" columns="*">
        <Label row="0" col="0" class="details-section-title" text="Name"></Label>
        <Label row="1" col="0" class="details-section-value" textWrap="true"
               [text]="job.jobName"></Label>
    </GridLayout>

    <!-- Spacer -->
    <Label class="h3" text=""></Label>

    <!--<hr>-->

Tables Section

The Tables Section is best suited when there’s logical relationships among text, numbers, images, or other data exist in two dimensions (vertical and horizontal). These relationships are represented in columns and rows, and the columns and rows must be recognizable in order for the logical relationships to be perceived.

Useful for viewing detailed data and precise values, good for comparing individual values.

_images/tables_section.web.jpg

The objective of this technique is to present tabular information in a way that preserves relationships within the information.

  • Filter or sort data
  • Show exact data
  • Visualise single or two dimensional data.

Any plugin Screen will be able to use the .peek-tables-section attributes.

Classes

The .peek-tables-section class contain the classes specific to a Tables Section.

.peek-tables-section{
/* Contains the Tables Section classes */
  ...

  .table{
  /* Contains the table attributes unique to the Tables Section */
    ...
  }

  .tr{
  /* Contains the table row attributes unique to the .table class */
    ...

  }
  .th{
  /* Contains the table head cell attributes unique to the .table class */
    ...

  }
  .td{
  /* Contains the table row cell attributes unique to the .table class */
    ...

  }

  .bg-odd {
  /*
    Applies the table even rows background theme
    This class also exists inside the .bg-... classes found in :ref:`other_useful_styles`.
  */
      ...

  }
}

SCSS Files

The Tables style classes are found in the _tables_section.scss.

The Tables Section HTML layout classes are found in the _tables_section.web.scss.

The Tables Section NativeScript layout classes are found in the _tables_section.ns.scss.

HTML

The Tables Section uses Bootstraps Tables.

Below is the HTML code extract of table header and two rows from Tables Section:

<div class="peek-tables-section">
    <table class="table">
        <thead>
        <tr class="tr">
            <th class="th">ID</th>
            <th class="th">Name</th>
            <th class="th">Scheduled Date</th>
            <th class="th">Status</th>
        </tr>
        </thead>
        <tbody>
        <tr class="tr"
            *ngFor="let item of incidents; odd as odd"
            [class.bg-primary]="item.fieldStatus.isActive"
            [class.bg-warning]="item.fieldStatus.isDispatched"
            [class.bg-success]="item.fieldStatus.isAccepted"
            (click)="jobClicked(item)">
            <td class="td"
                [class.bg-odd]="odd" [class.bg-even]="even">
                {{item.jobNumber}}

            </td>
            <td class="td"
                [class.bg-odd]="odd" [class.bg-even]="even">
                {{item.jobName}}

            </td>
            <td class="td"
                [class.bg-odd]="odd" [class.bg-even]="even">
                {{item.scheduledDate
                | date:'HH:mm EE dd-MMM'}}

            </td>
            <td class="td"
                [class.bg-odd]="odd" [class.bg-even]="even">
                {{item.fieldStatus.niceName}}

            </td>
        </tr>
        </tbody>
    </table>
</div>

NativeScript

The Tables Section uses Listview.

Below is the NativeScript code extract of table header and two rows from Tables Section:

<StackLayout class="peek-tables-section">
    <StackLayout class="table">
        <GridLayout rows="auto" columns="2*, 3*, 2*">
            <Label class="th" row="0" col="0" text="Job"></Label>
            <Label class="th" row="0" col="1" text="Scheduled"></Label>
            <Label class="th" row="0" col="2" text="Status"></Label>
        </GridLayout>

        <GridLayout rows="*" columns="*">
            <ListView [items]="jobs">
                <ng-template let-item="item" let-i="index" let-odd="odd" let-even="even">
                    <StackLayout
                            [class.bg-primary]="item.fieldStatus.isActive"
                            [class.bg-info]="item.fieldStatus.isAccepted"
                            [class.bg-success]="item.fieldStatus.isDispatched"
                            (tap)="jobClicked(item)">
                        <GridLayout rows="2*,2*,*" columns="2*, 3*, 2*"
                                    class="tr"
                                    [class.bg-odd]="odd" [class.bg-even]="even">
                            <!-- Details -->
                            <Label row="0" col="0"
                                   class="td"
                                   [text]="item.jobNumber"></Label>
                            <Label row="0" col="1"
                                   class="td"
                                   [text]="item.scheduledDate | date:'HH:mm EE dd-MMM'"></Label>
                            <Label row="0" col="2"
                                   class="td"
                                   [text]="item.fieldStatus.niceName"></Label>
                            <!-- Description -->
                            <Label row="1" col="0" colSpan="3"
                                    class="td"
                                   [text]="item.jobName" textWrap="true"></Label>
                        </GridLayout>
                    </StackLayout>
                </ng-template>
            </ListView>
        </GridLayout>
    </StackLayout>
</StackLayout>

Note

For the ListView to fill the screen space it is required to be the child of a GridLayout. Star mode for GridLayout row and column means that child ListView will expand to fill the gap left from other elements in the screen.

Other Useful Styles

Peek Theme is applied to bootstrap and some newly created classes as not all Peek Plugins require specific style configurations.

Most of the Peek Plugin Screens will use the generic bootstrap classes.

These classes are available throughout Peek and attribute changes are found in _bootstrap_adjustments.scss.

Title

Generic Peek theme Title.

.title {
/* Applies the title theme */
    ...

}

Headings

Generic Headings 1 through to 6.

Bootstrap Headings

.h1 {
/* Applies the heading theme */
    ...

}
.h2 {
/* Applies the heading theme */
    ...

}
.h3 {
/* Applies the heading theme */
    ...

}
.h4 {
/* Applies the heading theme */
    ...

}
.h5 {
/* Applies the heading theme */
    ...

}
.h6 {
/* Applies the heading theme */
    ...

}

Text

Generic Peek theme Text.

.p {
/* Applies the text theme */
    ...

}

Divider

The divider is styled as per the peek theme and can be used throughout the peek app.

The <hr> tag defines a thematic break in the HTML app.

The <StackLayout class=”hr”> element defines the thematic break in the NativeScript app.

.hr {
/* Applies the line divider theme */
    ...

}

Contextual Backgrounds

Set the background of an element to any contextual class.

Bootstrap Contextual Backgrounds

NativeScript Contextual Colors

Note

Only bg-primary and bg-danger exist in the NativeScript
Styling Infrastructure. The other classes need their attributes created from scratch to function in NativeScript.
.bg-primary{
/* Applies the primary background theme */
    ...

}
.bg-success{
/* Applies the success background theme */
    ...

}
.bg-info{
/* Applies the info background theme */
    ...

}
.bg-warning{
/* Applies the warning background theme */
    ...

}
.bg-danger{
/* Applies the danger background theme */
    ...

}

Button

Generic Peek theme button.

Bootstrap button example

NativeScript Button

.btn {
/*  Contains the generic button attributes */
    ...

}

For using Icons in buttons see Font Awesome Icons in Buttons

Contextual Buttons

Modify the button background colour and/or text colour of any button element.

Bootstrap Contextual Buttons

NativeScript Contextual Colors

Note

These classes need their attributes created from scratch to function in NativeScript.

Contextual button classes:

.btn-primary {
/* Applies the primary button theme */
    ...

}

.btn-success {
/* Applies the success button theme */
    ...

}

.btn-info {
/* Applies the info button theme */
    ...

}

.btn-warning {
/* Applies the warning button theme */
    ...

}

.btn-danger {
/* Applies the danger button theme */
    ...

}

Font Awesome

The Peek Theme uses Font Awesome Icons. This guide explains how to use the font awesome icons for the Peek application in both NativeScript and Web.

Visit the Font Awesome Cheatsheet for icon names. These are reference names to the unicode.

WEB Syntax

To create the ‘unlink’ icon used in the title-bar:

This is the syntax used in angular:

<fa *ngIf="!vortexIsOnline"
    name="unlink"
    tooltip="Connection to server is offline">

</fa>

This is the result in the browser:

<fa name="unlink" tooltip="Connection to server is offline" ng-reflect-name="unlink">
    <i aria-hidden="true" class="fa fa-unlink" ng-reflect-klass="fa fa-unlink" ng-reflect-ng-class=""></i>
  </fa>

To create the ‘comment-o’ icon as used in the Peek Chat plugin:


This is the syntax used in angular:

<fa class="pl-inbox-icon"
    *ngIf="task.isMessage() && !task.isCompleted()"
    name="comment-o">

</fa>

This is the result in the browser:

<fa class="pl-inbox-icon" name="comment-o" ng-reflect-name="comment-o">
    <i aria-hidden="true" class="fa fa-comment-o" ng-reflect-klass="fa fa-comment-o" ng-reflect-ng-class=""></i>
  </fa>
Component Selectors
Selectors
<ng2-fa></ng2-fa>
<fa></fa>
<ng4-fa></ng4-fa>
<ng-fa></ng-fa>
Component Options
name type options optional
name String F-A Icons No
size String lg, 2x, 3x, 4x, 5x Yes
fixed Boolean true | false Yes
animation String spin | pulse Yes
rotate Number | String 90 | 180 | 270 horizontal | vertical Yes
inverse Boolean true | false Yes

NativeScript Syntax

To create the ‘unlink’ icon used in the title-bar:

<Label *ngIf="!vortexIsOnline" class="fa" [text]="'fa-unlink' | fonticon"></Label>

To create the ‘comment-o’ icon as used in the Peek Chat plugin:


<Label row="0" col="0"
       *ngIf="item.isMessage() && !item.isCompleted()"
       class="pl-inbox-icon fa h2"
       [text]="'fa-comment-o' | fonticon"></Label>

Font Awesome Icons in Buttons

Web app example:

<button class="btn" (click)="editClicked()" *ngIf="!updateMode">
    <fa name="pencil"></fa> Edit
</button>

NativeScript app example:

<Button class="btn fa"
        text="{{'fa-pencil' | fonticon }} Edit"
        (tap)="editClicked()"
        *ngIf="!updateMode">
</Button>

Peek Screen Examples

This section describes the styling of the built in peek platform displays.

Title Bar

_images/title_bar.web.jpg

The Title Bar is fixed to the top of the screen.

The buttons remain a fixed size throughout a responsive lifecycle.

Plugins can add buttons after the “Home” button on the left, or on the right of the Title Bar.

The buttons on the right of the Title Bar will range from none to three.

The Title Bar will contain no more than four buttons.

The centralized title remains a single line and truncates a ... if the line exceeds the minimum screen width.

The title has a fixed width of 40px.

The Title Bar is unique, therefore the classes used will be specific for the Title Bar.

Classes

The .peek-title-bar class contains the classes specific to the Title Bar.

.peek-title-bar{
/* Contains the Title Bar classes */
    ...

    }
    .title-bar-btn{
    /* Contains the button attributes unique to the Title Bar */
        ...

    }
    .title-bar-title{
    /* Contains the title attributes unique to the Title Bar */
        ...

    }
}
.peek-page-contents{
/* Contains the padding to stop the screens being covered by the title-bar */
    ...

}
SCSS Files

The Title Bar style classes are found in the _title_bar.scss.

The Title Bar HTML layout classes are found in the _title_bar.web.scss.

The Title Bar NativeScript layout classes are found in the _title_bar.ns.scss.

HTML
_images/title_bar.web.jpg
<div class="peek-title-bar"
     [class.bg-danger]="!vortexIsOnline">
  <div class="btn-group pull-left"
       role="group">
    <button class="title-bar-btn"
            [routerLink]="['/']">
      Home

    </button>
  </div>
  <div class="title-bar-title pull-left">
    {{title}}

  </div>
  <div class="btn-group pull-right"
       role="group">
    <button class="title-bar-btn"
            *ngFor="let link of rightLinks"
            [routerLink]="[link.resourcePath]">
      {{linkTitle(link)}}

    </button>
  </div>
</div>
NativeScript
_images/title_bar.ns.jpg
<GridLayout class="peek-title-bar"
            [class.bg-danger]="!vortexIsOnline"
            rows="auto" columns="auto, *, auto">

  <Button class="btn" col="0" row="0"
          text="Home"
          [nsRouterLink]="['/']">

  </Button>

  <Button class="btn"
          *ngFor="let link of leftLinks"
          col="0" row="0"
          [text]="linkTitle(link)"
          [nsRouterLink]="[link.resourcePath]">

  </Button>

  <Label class="title"
         col="1" row="0"
         [text]="title">

  </Label>

  <Button class="btn"
          *ngFor="let link of rightLinks"
          col="2" row="0"
          [text]="linkTitle(link)"
          [nsRouterLink]="[link.resourcePath]">

  </Button>
</GridLayout>

Home Screen

The Home Screen is a unique screen in Peek that displays a link to available plugins that have front-ends.

_images/home_screen.web.jpg
Classes

The .peek-home-screen class will contain the classes specific to the Home Screen.

.peek-home-screen{
/*
    Contains the Home Screen classes
*/
    ...

    .home-screen-icon{
    /*
        Contains the Button attributes unique to the Home Screen
        Buttons responsively wrap
    */
        ...

    }
    .home-screen-image{
    /*
        Contains the Image attributes unique to the Home Screen
        Strictly uses images
    */
        ...

    }
    .home-screen-title{
    /* Contains the Button Title attributes unique to the Home Screen */
        ...

    }
}

 .peek-home-screen-background{
/*
    Contains the Background attributes
    Home Screen background is unique and different to other screens
    Cannot use the body tag
*/
    ...

}
Background Image
_images/home_background.png
SCSS Files

The Home Screen style classes are found in the _home_screen.scss.

The Home Screen HTML layout classes are found in the _home_screen.web.scss.

The Home Screen NativeScript layout classes are found in the _home_screen.ns.scss.

HTML
<div class="peek-home-screen">
  <div class="container-fluid">
    <div class="row">
      <div class="title h3"
           *ngIf="!appDetails.length">
        No Plugins Installed

      </div>
      <div class="col-xs-6 col-sm-4 col-md-3 col-lg-2"
           *ngFor="let app of appDetails">
        <a class="home-screen-icon"
           [routerLink]="[app.resourcePath]">
          <img class="home-screen-image"
               [src]="[app.pluginIconPath]">
          <div class="home-screen-title">
            {{app.title}}

          </div>
        </a>
      </div>
    </div>
  </div>
</div>
NativeScript
<ScrollView class="peek-home-screen">
  <WrapLayout>
    <Label class="message"
           *ngIf="!appDetails.length"
           text="No Plugins Installed">

    </Label>
    <GridLayout class="icon"
                *ngFor="let app of appDetails"
                rows="*,auto" columns="*"
                [nsRouterLink]="[app.resourcePath]">
      <Image class="image"
             row="0" col="0"
             src="~{{app.pluginIconPath}}">

      </Image>
      <Label class="title"
             row="1" col="0"
             [text]="app.title">

      </Label>
    </GridLayout>
  </WrapLayout>
</ScrollView>

Plugin Screen Examples

This section describes the styling of the public plugin displays.

Peek Plugin Inbox Style Example

Peek Plugin Inbox displays a list of unacknowledged items issued to the logged in user.

Inbox:

_images/inbox-tasks.web.jpg

Peek Plugin Activity display a log of items issued to the logged in user.

Activity:

_images/inbox-activity.web.jpg

If a device user has a role of performing tasks, which are managed by Peek, Peek will issue items to the user via this plugin.

  1. The active task plugin receives items from other plugins
  2. The new items are persisted within the Peek Storage database
  3. Delivery to the users device is ensured
  4. Once the item is on the user device, it may be :
    1. Selected from the ‘Inbox’ tab, this will route to the plugin that issued the item.
    2. Actioned, actions will be delivered back to the initiating plugin back on the peek server.
  5. All items and the state of items are viewable from an administrators page.
  6. The Inbox Screen is accessed by the ‘Tasks’ button in the Title Bar.
  7. The ‘Tasks’ button also shows the number of tasks.

Examples:

  1. The following are use case examples of what can be done with the Active Task plugin.
  2. Notifications that arrive as read, and require no action. This can create an audit trail for the user.
  3. Notification that are unread until the user selects them. Selecting them will navigate to another plugin, the initiating plugin will be notified and it can then mark the task as read or delete it.
  4. Actions that are required. Actions can be created by initiating plugins, and stay “unread / unactioned” until the user completes what ever action is required within another plugin. The initiating plugin then removes or marks the action as completed.
  5. Question. A task can be created with multiple actions, upon selecting an action, the initiating plugin will be notified, it can then remove the task.
Components

The plugin-active-task-client component builds the navigation tabs. The tabs route to the components plugin-active-task-task-list and plugin-active-task-activity-list.

The plugin-active-task-task-list component builds rows of outstanding tasks from plugins configured to issue tasks.

The plugin-active-task-activity-list component builds rows of the activity from the plugins configured to show activity.

Classes

The .plugin-inbox class contains the classes specific to the Peek Plugin Active Task.

.pl-inbox,
.pl-inboxActivity,
.pl-inboxTasks {

  .pl-inbox {
    /*
        Contains the style and classes for the inbox container
    */
    ...

    .pl-inbox-item {
      /*
          Contains the style and classes for the
      */
      ...

      .pl-inbox-icon {
        /*
            Contains the icon attributes unique to the .pl-inbox-item class
        */
        ...

      }
      .pl-inbox-info {
        /*
            Contains the info attributes unique to the .pl-inbox-item class
        */
        ...

        .pl-inbox-title {
          /*
              Contains the title text attributes unique to the .pl-inbox-info class
          */
          ...

        }
        .pl-inbox-description {
          /*
              Contains the description text attributes unique to the .pl-inbox-info class
          */
          ...

        }
        .pl-inbox-date-time {
          /*
              Contains the date and time attributes unique to the .pl-inbox-info class
          */
          ...

        }
      }
    }
    .pl-inbox-read-more {
      /*
          Contains the read more link attributes unique to the .plugin-inbox class
      */
      ...

      }
    }
  }
}
SCSS Files

The Inbox style classes are found in the _plugin_inbox.scss.

The Inbox HTML layout classes are found in the _plugin_inbox.web.scss.

The Inbox NativeScript layout classes are found in the _plugin_inbox.ns.scss.

HTML
plugin-active-task-client
<div class="pl-inbox">

    <ul class="nav nav-tabs"
        role="tablist">
        <li class="active"
            role="presentation">
            <a aria-controls="home"
               data-toggle="tab"
               href="http://localhost:4200/#inboxTasks"
               role="tab">
                Inbox

            </a>
        </li>
        <li role="presentation">
            <a aria-controls="profile"
               data-toggle="tab"
               href="http://localhost:4200/#inboxActivity"
               role="tab">
                Activity

            </a>
        </li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active"
             role="tabpanel"
             id="inboxTasks">
            <plugin-active-task-task-list></plugin-active-task-task-list>

        </div>
        <div class="tab-pane"
             role="tabpanel"
             id="inboxActivity">
            <plugin-active-task-activity-list></plugin-active-task-activity-list>

        </div>
    </div>
</div>
plugin-active-task-task-list
<div class="pl-inbox-tasks">
    <div class="h3"
         *ngIf="tasks.length === 0">
        The inbox is empty.

    </div>
    <div class="pl-inbox-item bg-success"
         *ngFor="let task of tasks"
         (click)="taskClicked(task)">
        <div class="pl-inbox-icon">
            <i class="fa fa-comment"
               aria-hidden="true"></i>

        </div>
        <div class="pl-inbox-info">
            <div class="pl-inbox-title">
                {{task.title}}

            </div>
            <div class="pl-inbox-description">
                {{task.description}}

            </div>
            <div class="pl-inbox-date-time">
                {{timePast(task)}} ago, {{dateTime(task)}}

            </div>
        </div>
        <div class="pl-inbox-read-more">
            <i class="fa fa-chevron-right"
               aria-hidden="true"></i>

        </div>
    </div>
</div>
plugin-active-task-activity-list
<div class="pl-inbox-activity">
    <div class="message"
         *ngIf="activities.length === 0">
        There is no recent activity.

    </div>
    <div class="pl-inbox-item"
         *ngFor="let activity of activities"
         (click)="activityClicked(activity)">
        <div class="pl-inbox-info">
            <div class="pl-inbox-title">
                {{activity.title}}

            </div>
            <div class="pl-inbox-description">
                {{activity.description}}

            </div>
            <div class="pl-inbox-date-time">
                {{timePast(activity)}} ago, {{dateTime(activity)}}

            </div>
        </div>
        <div class="pl-inbox-read-more">
            <i class="fa fa-chevron-right"
               aria-hidden="true"></i>

        </div>
    </div>
</div>

Peek Plugin Chat Style Example

Peek Plugin Chat displays active chat sessions and their messages.

  • The active chat sessions should indicate if there are unread messages.
  • The message lists will display sent messages on the right and received messages on the left.
  • Background contextual colours will distinguish a successfully sent message or an emergency “SOS” message received.

Chats:

_images/chat-chats.web.jpg

Messages:

_images/chat-msgs.web.jpg

Originally this plugin was designed to send messages between the power grid control room and field engineers.

Simple communications with external systems.

Components

The chat-list component displays a list of active chat sessions that route to the msg-list component. The “New Chat” button in the Navigation Bar routes to the new-chat component.

The new-chat component creates new chat sessions. The user builds a list of one or more users for a new chat session.

The msg-list component shows the list of sent and received messages for the selected chat session. The “angle-left” button in the Navigation Bar routes to the chat-list component. The user has the option to compose a new message to send of send an “SOS” message.

Classes

The .plugin-chat-list class contain the classes specific to the chat-list component. The .plugin-chat-messages class contains the classes specific to the msg-list component. The new-chat component uses generic classes, see Other Useful Styles.

.plugin-chat-list {
  /*
      Contains the chat-list component classes
  */
  ...

  .chat-list-messages {
    /*
        Contains the Messages attributes unique to the Chat List
    */
    ...

    .chat-list-icon {
      /*
          Contains the icon attributes unique to the message class
          The icon is used to indicate unread messages
      */
      ...

    }
    .chat-list-title {
      /*
          Contains the topic text attributes unique to the message class
      */
      ...

    }
  }
}

.plugin-chat-messages {
  /*
      Contains the msg-list component classes
  */
  ...

  .chat-messages-list {
    /*
        Attributes for the container of messages, unique to the Chat
        Messages.
        Scrolls through the messages with most recent at the bottom.
    */
    ...

    .chat-messages-sent {
      /*
          Contains the sent message attributes unique to the message-list
          class.
          Container is right aligned with background colour different to the
          received class.
          bg-success class applied for a successfully sent message.
      */
      ...

    }
    .chat-messages-received {
      /*
          Contains the received text attributes unique to the message-list
          class.
          Container is right aligned with background colour different to the
          sent class.
          bg-warning class applied for an emergency priority message.
      */
      ...

    }
    .chat-messages-details {
      /*
          Contains the message details text attributes unique to the
          message-list class.
          The message details should not be the focus of attention (text-muted)
      */
      ...

    }
    .chat-messages-emergency {
      /*
          Contains the emergency priority message text attributes unique to the
          message-list class
      */
      ...

    }
    .chat-messages-normal {
      /*
          Contains the normal priority message text attributes unique to the
          message-list class
      */
      ...

    }
  }
  .chat-messages-compose {
    /*
        Contains the compose message area attributes unique to the
        chat messages.
        Fixed to the bottom of the screen.
    */
    ...

    .chat-messages-new-text {
      /*
          Contains the new message text attributes unique to the
          chat-messages-compose class.
      */
      ...

    }
  }
}
.chat-messages-btn-group {
    ...

  .chat-messages-btn {
    /*
        Contains the button attributes unique to the
        chat-messages-compose class.
    */
    ...

  }
}
SCSS Files

The Inbox style classes are found in the _plugin_chat.scss.

The Inbox HTML layout classes are found in the _plugin_chat.web.scss.

The Inbox NativeScript layout classes are found in the _plugin_chat.ns.scss.

HTML
chat-list component
<!--TRANSITION WITH REASON DIALOG -->
<pl-chat-new-chat
        *ngIf="isNewChatDialogShown()"
        (create)="dialogConfirmed($event)"
        (cancel)="dialogCanceled()"
        [data]="newChatDialogData">

</pl-chat-new-chat>


<div class="peek-nav-section">
    <!--
        The following 'div' groups button to the left of the Nav Bar.
        Can contain one to many buttons
    -->
    <div class="btn-group pull-left"
         *ngIf="!isNewChatDialogShown()"
         role="group">
        <button class="btn"
                role="group"
                (click)="newChatClicked()">
            New Chat
        </button>
    </div>
</div>

<div class="plugin-chat-list">
    <!-- Use the template tag syntax, as this works with nativescript too -->
    <ng-template ngFor let-chat [ngForOf]="chats" let-i="index">
        <div class="chat-list-messages" (click)="chatClicked(chat)">

            <!-- Unread indicator -->
            <fa class="chat-list-icon" name="fw" *ngIf="isChatRead(chat)"></fa>
            <fa class="chat-list-icon" name="comment-o" *ngIf="!isChatRead(chat)"></fa>

            <!-- Other Users -->
            <div class="chat-list-title" *ngFor="let user of otherChatUsers(chat)">
                {{userDisplayName(user)}} ({{user.userId}})
            </div>
        </div>
    </ng-template>
</div>
new-chat component
<div [@dialogAnimation]="dialogAnimationState"
     (@dialogAnimation.done)="animationDone($event)">

    <div class="h2">
        Start a chat wth :
    </div>

    <div class="p"
         *ngIf="!createButtonEnabled()">
        No users selected
    </div>
    <ul>
        <li *ngFor="let u of data.users">
            {{u.displayName}}
        </li>
    </ul>

    <div class="form-group">
        <label class="h4"
               for="userIdField">
            Add User:
        </label>
        <select class="form-control"
                id="userIdField"
                name="userId"
                [(ngModel)]="selectedUserIndex">
            <option [value]="i" *ngFor="let i = index; let item of usersStrList">
                {{item}}
            </option>
        </select>
    </div>


    <!-- BEGIN HANDBACK DIALOG -->
    <div>
        <Button class="btn" (click)="addUserClicked()"
                [disabled]="!newButtonEnabled()">
            Add User
        </Button>

        <Button class="btn" (click)="confirmClicked(false)"
                [disabled]="!createButtonEnabled()">
            Create Chat
        </Button>

        <Button class="btn" (click)="cancelClicked(false)">
            Cancel
        </Button>
    </div>
</div>
msg-list component
<div class="peek-nav-section">
    <div class="btn-group pull-left"
         role="group">
        <button class="btn"
                role="group"
                (click)="navToChatsClicked()">
            <fa name="angle-left"></fa>
        </button>
    </div>
</div>

<div class="plugin-chat-messages"
     #messageListRef>
    <!-- No Messages -->
    <div class="h3"
         *ngIf="!haveMessages()">
        No messages

    </div>
    <div class="chat-messages-list">

        <div *ngFor="let i=index; let msg of messages()">
            <!-- Unread marker -->
            <hr *ngIf="isFirstUnreadMesage(i)"/>

            <!-- From and Date -->
            <div [class.sent]="isMessageFromThisUser(msg)"
                 [class.received]="!isMessageFromThisUser(msg)">
                <div class="chat-messages-details"
                     *ngIf="!isMessageFromThisUser(msg)">
                    From {{userDisplayName(msg)}} ({{msg.fromUserId}}), {{timePast(msg)}}
                    ago

                </div>
                <div class="chat-messages-details"
                     *ngIf="isMessageFromThisUser(msg)">
                    {{timePast(msg)}} ago

                </div>
                <div [class.chat-messages-sent]="isMessageFromThisUser(msg)"
                     [class.chat-messages-received]="!isMessageFromThisUser(msg)"
                     [class.bg-success]="isNormalPriority(msg)"
                     [class.bg-danger]="isEmergencyPriority(msg)">

                    <div class="chat-messages-normal"
                         *ngIf="isNormalPriority(msg)">
                        {{msg.message}}

                    </div>
                    <div class="chat-messages-emergency"
                         *ngIf="isEmergencyPriority(msg)">
                        {{msg.message}}

                    </div>
                </div>
            </div>
        </div>
    </div>

    <div class="chat-messages-compose">
    <textarea class="form-control"
              [(ngModel)]="newMessageText">

    </textarea>
        <button class="btn" type="button"
                [disabled]="!sendEnabled()"
                (click)="sendMsgClicked()">
            Send

        </button>
        <button class="btn" type="button"
                (click)="sendSosClicked()">
            SOS

        </button>
    </div>
</div>