Bookings operations

An enterprise reservation workflow assembled from AngularCSS components.

This AngularTS application composes sidebar, input group, tabs, badge, avatar, scroll area, empty, button, and dialog components into a responsive upcoming bookings workflow. Search, status filtering, booking selection, dialog state, and mobile navigation are functional. All scripts, styles, and Lucide icons are bundled locally.

View source
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>AngularCSS Bookings</title>
    <link rel="stylesheet" href="../../../css/preflight.css" />
    <link rel="stylesheet" href="../../../css/angular.css" />
    <link rel="stylesheet" href="./bookings.css" />
    <script src="../../../js/angular-ts.umd.js"></script>
    <script src="../../../js/angular-css.umd.js"></script>
    <script src="./bookings.js"></script>
  </head>
  <body
    ng-app="bookingsDemo"
    ng-controller="BookingsController as bookings"
    ng-cloak
  >
    <div class="booking-shell" data-testid="booking-shell">
      <nav class="booking-rail" aria-label="Application navigation">
        <a class="booking-brand" href="./" aria-label="OrbitPass home">O</a>
        <div class="booking-rail-primary">
          <a href="#search" aria-label="Search"
            ><span ng-icon="search"></span
          ></a>
          <a class="is-active" href="#bookings" aria-label="Bookings">
            <span ng-icon="bookings"></span><small>Bookings</small>
          </a>
          <a href="#support" aria-label="Support">
            <span ng-icon="support"></span><small>Support</small>
          </a>
          <a href="#admin" aria-label="Admin">
            <span ng-icon="settings"></span><small>Admin</small>
          </a>
        </div>
        <div class="booking-rail-footer">
          <button type="button" aria-label="Notifications">
            <span ng-icon="bell"></span><span class="notification-dot"></span>
          </button>
          <span size="sm" class="avatar">
            <span>EE</span>
            <output aria-label="Online"></output>
          </span>
        </div>
      </nav>

      <aside
        id="booking-sidebar"
        class="booking-secondary"
        ng-sidebar
        style="--sidebar-width: 14rem"
      >
        <div>
          <header class="booking-sidebar-header">
            <strong>Bookings</strong>
            <button size="icon-sm" variant="ghost" aria-label="Add booking">
              <span ng-icon="plus"></span>
            </button>
          </header>
          <hr />
          <nav>
            <section>
              <div>
                <ul>
                  <li>
                    <button aria-current="page">
                      <span ng-icon="bookings"></span><span>Upcoming</span>
                    </button>
                    <output>40</output>
                  </li>
                  <li>
                    <button>
                      <span ng-icon="clock"></span><span>Past</span>
                    </button>
                    <output>0</output>
                  </li>
                  <li>
                    <button>
                      <span ng-icon="customers"></span><span>Customers</span>
                    </button>
                    <output>21</output>
                  </li>
                  <li>
                    <button>
                      <span ng-icon="invoices"></span><span>Invoices</span>
                    </button>
                    <output>0</output>
                  </li>
                </ul>
              </div>
            </section>
          </nav>
          <footer class="booking-sidebar-footer">
            <span class="muted">Signed in as</span>
            <strong>Emma Executive</strong>
          </footer>
        </div>
      </aside>

      <main class="booking-main" id="bookings">
        <header class="booking-toolbar">
          <div class="booking-title-row">
            <button
              class="booking-mobile-menu"
              size="icon-sm"
              variant="outline"
              aria-controls="booking-sidebar"
              aria-label="Toggle booking navigation"
            >
              <span ng-icon="menu"></span>
            </button>
            <div>
              <span class="booking-eyebrow">Bookings</span>
              <h1>Upcoming</h1>
            </div>
          </div>
          <div class="booking-search input-group">
            <span ng-icon="search"></span>
            <input
              ng-model="bookings.query"
              data-change="bookings.updateVisible()"
              type="search"
              aria-label="Search bookings"
              placeholder="Search bookings"
            />
            <span align="inline-end">
              <kbd>/</kbd>
            </span>
          </div>
        </header>

        <div class="booking-filterbar">
          <nav variant="line" aria-label="Booking status">
            <button
              type="button"
              aria-pressed="{{ bookings.status === 'All' }}"
              ng-click="bookings.setStatus('All')"
            >
              All
            </button>
            <button
              ng-click="bookings.setStatus('Confirmed')"
              aria-pressed="{{ bookings.status === 'Confirmed' }}"
            >
              Confirmed
            </button>
            <button
              ng-click="bookings.setStatus('Pending')"
              aria-pressed="{{ bookings.status === 'Pending' }}"
            >
              Pending
            </button>
            <button
              ng-click="bookings.setStatus('Change Requested')"
              aria-pressed="{{ bookings.status === 'Change Requested' }}"
            >
              Change requested
            </button>
          </nav>
          <span class="booking-result-count">
            <strong ng-bind="bookings.visibleCount"></strong> results
          </span>
        </div>

        <section
          class="booking-scroll scroll-area"
          tabindex="0"
          aria-label="Bookings"
        >
          <div class="booking-list" aria-live="polite">
            <article
              class="booking-row"
              ng-repeat="booking in bookings.bookings"
              ng-show="booking.visible"
            >
              <button
                class="booking-row-trigger"
                type="button"
                aria-controls="booking-detail-dialog-content"
                commandfor="booking-detail-dialog-content"
                command="show-modal"
                ng-click="bookings.select(booking)"
              >
                <span class="booking-summary">
                  <span
                    class="booking-reference"
                    ng-bind="booking.reference"
                  ></span>
                  <span
                    ><span ng-icon="ticket"></span
                    ><span ng-bind="booking.service"></span
                  ></span>
                  <span
                    ><span ng-icon="rocket"></span
                    ><span ng-bind="booking.vessel"></span
                  ></span>
                  <span
                    status="{{ booking.status }}"
                    ng-bind="booking.status"
                    class="badge"
                  ></span>
                </span>

                <span class="booking-route">
                  <span class="booking-place">
                    <strong ng-bind="booking.origin"></strong>
                    <span ng-bind="booking.departure"></span>
                  </span>
                  <span class="booking-journey" aria-hidden="true">
                    <span class="booking-route-line"></span>
                    <span ng-icon="plane"></span>
                    <small ng-bind="booking.duration"></small>
                  </span>
                  <span class="booking-place booking-destination">
                    <strong ng-bind="booking.destination"></strong>
                    <span ng-bind="booking.arrival"></span>
                  </span>
                </span>

                <span class="booking-meta">
                  <span
                    ><span ng-icon="customer"></span
                    ><span ng-bind="booking.customer"></span
                  ></span>
                  <span
                    ><span ng-icon="ticket"></span
                    ><span ng-bind="booking.customerId"></span
                  ></span>
                  <span
                    ><span ng-icon="home"></span
                    ><span ng-bind="booking.cabin"></span
                  ></span>
                  <span
                    ><span ng-icon="luggage"></span
                    ><span ng-bind="booking.luggage"></span
                  ></span>
                  <span
                    ><span ng-icon="luggage"></span
                    ><span ng-bind="booking.allowance"></span
                  ></span>
                </span>
              </button>
            </article>

            <section ng-show="bookings.empty" class="booking-empty empty">
              <figure>
                <span ng-icon="search"></span>
              </figure>
              <h2>No bookings found</h2>
              <p>Try a different search or status.</p>
            </section>
          </div>
        </section>
      </main>
    </div>

    <section id="booking-detail-dialog" class="booking-dialog dialog">
      <dialog
        id="booking-detail-dialog-content"
        closedby="any"
        aria-labelledby="booking-dialog-title"
        aria-describedby="booking-dialog-description"
      >
        <header>
          <span
            class="booking-dialog-reference"
            ng-bind="bookings.selected.reference"
          ></span>
          <h2 id="booking-dialog-title">Booking details</h2>
          <p id="booking-dialog-description">
            <span ng-bind="bookings.selected.customer"></span> traveling from
            <span ng-bind="bookings.selected.origin"></span> to
            <span ng-bind="bookings.selected.destination"></span>.
          </p>
        </header>
        <dl class="booking-detail-grid">
          <div>
            <dt>Service</dt>
            <dd ng-bind="bookings.selected.service"></dd>
          </div>
          <div>
            <dt>Status</dt>
            <dd ng-bind="bookings.selected.status"></dd>
          </div>
          <div>
            <dt>Departure</dt>
            <dd ng-bind="bookings.selected.departure"></dd>
          </div>
          <div>
            <dt>Arrival</dt>
            <dd ng-bind="bookings.selected.arrival"></dd>
          </div>
          <div class="booking-detail-wide">
            <dt>Cabin</dt>
            <dd ng-bind="bookings.selected.cabin"></dd>
          </div>
        </dl>
        <footer>
          <button
            commandfor="booking-detail-dialog-content"
            command="close"
            variant="outline"
          >
            Close
          </button>
          <button>Open booking</button>
        </footer>
      </dialog>
    </section>
  </body>
</html>