2022年7月31日日曜日

Cozy Web/レイアウト

前回「Cozy Web/Bootstrap」ではBootstrapのテンプレートを使用するためにレイアウト機能を使用しました。

今回は、このCozy Webのレイアウト機能について少し詳しく説明します。

HelloLayout

まず、レイアウト機能を使ったHelloLayoutアプリケーションを作成します。

準備

cozyを起動するディレクトリのwebappsディレクトリに、アプリケーションのホームとなるディレクトリHelloLayoutを作成します。このディレクトリHelloLayoutをアプリケーションのホームディレクトリとなります。

共通テンプレート

Webページで共有されるテンプレートとして以下のものをWEB-INF/layouts/default.jadeに作成します。

-@val model: ViewModel
!!! 5
html(lang="ja")
  head
    =model.pageTitle
  body
    =model.header
    =model.navigation
    =model.sidebar
    =model.content
    =model.footer

headに以下の設定があります。

    =model.pageTitle

ページのタイトルをhead要素の配下に追加する指定になります。

またbodyに以下の設定があります。

    =model.header
    =model.navigation
    =model.sidebar
    =model.content
    =model.footer

それぞれ以下の部品をbody要素の配下に追加する指定です。

model.header
ページのヘッダー
model.navigation
ナビゲーション・バー
model.sidebar
サイド・バー
model.content
ページの本文
model.footer
ページのフッター

ヘッダー、フッター、ナビゲーション・バー、サイド・バーで構成される固定レイアウト内に本文を埋め込む構成になっています。

部品ページ

Webページの部品はWEB-INF/partialsに格納します。

partialsに格納する部品は、header.htmlやheader.jadeのようにファイル名本体を部品名とします。サフィックスは部品の記述を行う言語になります。

ヘッダー

ヘッダーとして以下のheader.jadeをWEB-INF/partialsに格納しました。

div Header

ナビゲーション・バー

ナビゲーション・バーとして以下のnavigation.jadeをWEB-INF/partialsに格納しました。

div Navigation

フッター

フッターとして以下のfooter.jadeをWEB-INF/partialsに格納しました。

div Footer

サイド・バー

フッターとして以下のsidebar.jadeをWEB-INF/partialsに格納しました。

div Sidebar

Webページ

WebアプリケーションのWebページとしてindex.htmlを用意します。

後述のBootstrap版との比較のために、Bootstrapのクラスを用いた同じWebページを用いています。この版ではBootstrapの設定は行っていないので、画面表示に影響しません。

<!doctype html>
<html>
    <head>
	<title>HelloLayout</title>
    </head>
    <body>
	<h1>HelloLayout</h1>
	<table class="table">
	    <thead>
		<tr>
		    <th scope="col">#</th>
		    <th scope="col">First</th>
		    <th scope="col">Last</th>
		    <th scope="col">Handle</th>
		</tr>
	    </thead>
	    <tbody>
		<tr>
		    <th scope="row">1</th>
		    <td>Mark</td>
		    <td>Otto</td>
		    <td>@mdo</td>
		</tr>
		<tr>
		    <th scope="row">2</th>
		    <td>Jacob</td>
		    <td>Thornton</td>
		    <td>@fat</td>
		</tr>
		<tr>
		    <th scope="row">3</th>
		    <td colspan="2">Larry the Bird</td>
		    <td>@twitter</td>
		</tr>
	    </tbody>
	</table>
    </body>
</html>

実行

curlコマンドによってローカルホストの8080ポート上の/web/HelloLayout/を取得します。

/web はCozy上のWebアプリケーションのホームです。その配下のHelloLayoutが、先程作成したディレクトリHelloLayoutに対応するもので、ディレクトリ名がアプリケーション名になっています。

$ curl http://localhost:8080/web/HelloLayout/

取得結果は以下になります。無事登録したHTML文書を取得することができました。

HTML文書には期待通りLayoutの各種設定が自動的に行われています。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <title>HelloLayout</title>
  </head>
  <body>
    <div>Header</div>
    <div>Navigation</div>
    <div>Sidebar</div>
    
    	<h1>HelloLayout</h1>
    	<table class="table">
    	    <thead>
    		<tr>
    		    <th scope="col">#</th>
    		    <th scope="col">First</th>
    		    <th scope="col">Last</th>
    		    <th scope="col">Handle</th>
    		</tr>
    	    </thead>
    	    <tbody>
    		<tr>
    		    <th scope="row">1</th>
    		    <td>Mark</td>
    		    <td>Otto</td>
    		    <td>@mdo</td>
    		</tr>
    		<tr>
    		    <th scope="row">2</th>
    		    <td>Jacob</td>
    		    <td>Thornton</td>
    		    <td>@fat</td>
    		</tr>
    		<tr>
    		    <th scope="row">3</th>
    		    <td colspan="2">Larry the Bird</td>
    		    <td>@twitter</td>
    		</tr>
    	    </tbody>
    	</table>
        
    <div>Footer</div>
  </body>
</html>

このページは以下のように表示されます。

LayoutBootstrap

レイアウト機能を使うと、定形のWebページ内に定義した部品を差し込める事が分かりました。

このレイアウト機能を使って、Bootstrapベースの定形ページを作ってみます。

準備

cozyを起動するディレクトリのwebappsディレクトリに、アプリケーションのホームとなるディレクトリLayoutBootstrapを作成します。このディレクトリLayoutBootstrapをアプリケーションのホームディレクトリとなります。

共通テンプレート

Webページで共有されるテンプレートとして以下のものをWEB-INF/layouts/default.jadeに作成します。このテンプレートページでBootstrapに必要な設定を行っています。

-@val model: ViewModel
!!! 5
html(lang="ja")
  head
    meta(charset="utf-8")
    meta(name="viewport" content="width=device-width, initial-scale=1")
    link(href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous")
    =model.pageTitle
  body
    script(src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous")
    header
      =model.header
      =model.navigation
    div(class="container-fluid pb-3 flex-grow-1 d-flex flex-column flex-sm-row overflow-auto")
      div(class="row flex-grow-sm-1 flex-grow-0")
        aside(class="col-sm-3 flex-grow-sm-1 flex-shrink-1 flex-grow-0 sticky-top pb-sm-0 pb-3")
          div(class="bg-light border p-1 h-100 sticky-top")
            =model.sidebar
        main(class="col overflow-auto h-100")
          =model.content
    footer	
      =model.footer

部品ページ

Webページの部品はWEB-INF/partialsに格納します。

ヘッダー

ヘッダーとして以下のheader.jadeをWEB-INF/partialsに格納しました。

Bootstrapのクラスを設定しています。

nav(class="navbar navbar-light bg-primary")
  div(class="container-fluid")
    span(class="navbar-brand mb-0 h1") Cozy Web

ナビゲーション・バー

ナビゲーション・バーとして以下のnavigation.jadeをWEB-INF/partialsに格納しました。

Bootstrapの機能を用いてナビゲーション・バーを実現しています。

nav(class="navbar navbar-expand-lg navbar-light bg-light")
  div(class="container-fluid")
    a(class="navbar-brand" href="#") Navbar
    button(class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation")
      span(class="navbar-toggler-icon")
    div(class="collapse navbar-collapse" id="navbarNav")
      ul(class="navbar-nav")
        li(class="nav-item")
          a(class="nav-link active" aria-current="page" href="#") Home
        li(class="nav-item")
          a(class="nav-link" href="#") Features
        li(class="nav-item")
          a(class="nav-link" href="#") Pricing
        li(class="nav-item")
          a(class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true") Disabled

フッター

フッターとして以下のfooter.jadeをWEB-INF/partialsに格納しました。

Bootstrapのクラスを設定しています。

nav(class="navbar navbar-light bg-secondary")
  span Cozy Web

サイド・バー

サイド・バーとして以下のsidebar.jadeをWEB-INF/partialsに格納しました。

Bootstrapの機能を用いてサイド・バーを実現しています。

ul(class="nav nav-pills flex-sm-column flex-row mb-auto justify-content-between text-truncate")
  li(class="nav-item")
    a(href="#" class="nav-link px-2 text-truncate")
      i(class="bi bi-house fs-5")
      span(class="d-none d-sm-inline") Home
  li
    a(href="#" class="nav-link px-2 text-truncate")
      i(class="bi bi-speedometer fs-5")
      span(class="d-none d-sm-inline") Dashboard
  li
    a(href="#" class="nav-link px-2 text-truncate")
      i(class="bi bi-card-text fs-5")
      span(class="d-none d-sm-inline") Orders
  li
    a(href="#" class="nav-link px-2 text-truncate")
      i(class="bi bi-bricks fs-5")
      span(class="d-none d-sm-inline") Products
  li
    a(href="#" class="nav-link px-2 text-truncate")
      i(class="bi bi-people fs-5")
      span(class="d-none d-sm-inline") Customers

Webページ

表示したい本文を記述したページをindex.htmlとして用意します。

これは前出のHelloLayout版と基本的に同じ内容です。(タイトルだけ変更しています)今度はBootstrapのクラス指定が活きてくるはずです。

<!doctype html>
<html>
    <head>
	<title>LayoutBootstrap</title>
    </head>
    <body>
	<h1>LayoutBootstrap</h1>
	<table class="table">
	    <thead>
		<tr>
		    <th scope="col">#</th>
		    <th scope="col">First</th>
		    <th scope="col">Last</th>
		    <th scope="col">Handle</th>
		</tr>
	    </thead>
	    <tbody>
		<tr>
		    <th scope="row">1</th>
		    <td>Mark</td>
		    <td>Otto</td>
		    <td>@mdo</td>
		</tr>
		<tr>
		    <th scope="row">2</th>
		    <td>Jacob</td>
		    <td>Thornton</td>
		    <td>@fat</td>
		</tr>
		<tr>
		    <th scope="row">3</th>
		    <td colspan="2">Larry the Bird</td>
		    <td>@twitter</td>
		</tr>
	    </tbody>
	</table>
    </body>
</html>

実行

curlコマンドによってローカルホストの8080ポート上の/web/LayoutBootstrap を取得します。

$ curl http://localhost:8080/web/LayoutBootstrap/

取得結果は以下になります。無事、登録したHTML文書にBootstrapの各種設定を行ったHTML文書を取得することができました。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <meta content="width=device-width, initial-scale=1" name="viewport" />
    <link crossorigin="anonymous" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" />
    <title>LayoutBootstrap</title>
  </head>
  <body>
    <script crossorigin="anonymous" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
    <header>
      <nav class="navbar navbar-light bg-primary">
        <div class="container-fluid">
          <span class="navbar-brand mb-0 h1">Cozy Web</span>
        </div>
      </nav>
      <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <div class="container-fluid">
          <a class="navbar-brand" href="#">Navbar</a>
          <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
          </button>
          <div class="collapse navbar-collapse" id="navbarNav">
            <ul class="navbar-nav">
              <li class="nav-item">
                <a class="nav-link active" aria-current="page" href="#">Home</a>
              </li>
              <li class="nav-item">
                <a class="nav-link" href="#">Features</a>
              </li>
              <li class="nav-item">
                <a class="nav-link" href="#">Pricing</a>
              </li>
              <li class="nav-item">
                <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
              </li>
            </ul>
          </div>
        </div>
      </nav>
    </header>
    <div class="container-fluid pb-3 flex-grow-1 d-flex flex-column flex-sm-row overflow-auto">
      <div class="row flex-grow-sm-1 flex-grow-0">
        <aside class="col-sm-3 flex-grow-sm-1 flex-shrink-1 flex-grow-0 sticky-top pb-sm-0 pb-3">
          <div class="bg-light border p-1 h-100 sticky-top">
            <ul class="nav nav-pills flex-sm-column flex-row mb-auto justify-content-between text-truncate">
              <li class="nav-item">
                <a href="#" class="nav-link px-2 text-truncate">
                  <i class="bi bi-house fs-5"></i>
                  <span class="d-none d-sm-inline">Home</span>
                </a>
              </li>
              <li>
                <a href="#" class="nav-link px-2 text-truncate">
                  <i class="bi bi-speedometer fs-5"></i>
                  <span class="d-none d-sm-inline">Dashboard</span>
                </a>
              </li>
              <li>
                <a href="#" class="nav-link px-2 text-truncate">
                  <i class="bi bi-card-text fs-5"></i>
                  <span class="d-none d-sm-inline">Orders</span>
                </a>
              </li>
              <li>
                <a href="#" class="nav-link px-2 text-truncate">
                  <i class="bi bi-bricks fs-5"></i>
                  <span class="d-none d-sm-inline">Products</span>
                </a>
              </li>
              <li>
                <a href="#" class="nav-link px-2 text-truncate">
                  <i class="bi bi-people fs-5"></i>
                  <span class="d-none d-sm-inline">Customers</span>
                </a>
              </li>
            </ul>
          </div>
        </aside>
        <main class="col overflow-auto h-100">
          
          	    <h1>LayoutBootstrap</h1>
          	    <table class="table">
          		<thead>
          		    <tr>
          			<th scope="col">#</th>
          			<th scope="col">First</th>
          			<th scope="col">Last</th>
          			<th scope="col">Handle</th>
          		    </tr>
          		</thead>
          		<tbody>
          		    <tr>
          			<th scope="row">1</th>
          			<td>Mark</td>
          			<td>Otto</td>
          			<td>@mdo</td>
          		    </tr>
          		    <tr>
          			<th scope="row">2</th>
          			<td>Jacob</td>
          			<td>Thornton</td>
          			<td>@fat</td>
          		    </tr>
          		    <tr>
          			<th scope="row">3</th>
          			<td colspan="2">Larry the Bird</td>
          			<td>@twitter</td>
          		    </tr>
          		</tbody>
          	</table>
              
        </main>
      </div>
    </div>
    <footer>
      <nav class="navbar navbar-light bg-secondary">
        <span>Cozy Web</span>
      </nav>
    </footer>
  </body>
</html>

このページは以下のように表示されます。

Bootstrapの機能を活かしたレイアウト、カラーコーディネーションになっています。

小さな画面で表示すると、以下のようにメニューが折り畳まれて表示されます。Bootstrapのレシポンシブデザインが効いていることが分かります。

まとめ

Cozy Webのレイアウト機能について説明しました。

BootstrapのようなWebフレームワークの定形テンプレートを容易に作成することができます。

次回は、定形テンプレートをさらに部品化する方法について説明します。

諸元

Cozy
0.0.6