開発情報・ナレッジ

投稿者: SPIRERS ナレッジ向上チーム 2022年7月5日 (火)

ウェビナー管理アプリ サイト設計・構築

最近ではWeb会議ツールを使用したセミナー、ウェビナーが主流となってきています。
参加する側は気軽に参加ができ、運営する側はWeb会議ツールを用意するだけでよく会場の手配などが不要なので、両者にメリットがありそうです。

そんなウェビナー管理ですが、SPIRALver.2では申込受付からウェビナー後の満足度アンケート、フォロー対応までを行うことができるウェビナー管理アプリの構築が可能です。
この記事は サイト設計・構築 のフェーズとなります。

関連記事はこちら
SPIRAL ver.2はプログラミング経験がなくても、オリジナルの業務アプリの制作・カスタマイズができるローコード開発プラットフォームです。
詳しくは SPIRAL ver.2 とはをご覧ください。

変更・改定履歴

  • 改定

    アップデートに対応し記事全般を再編集

サイト機能

SPIRAL ver.2 のサイト管理機能では、静的なWebページを作成したり、
データベースに対して登録・更新するフォーム や データベースの情報を一覧形式で表示させるページなどを作成できます。
詳細は、サイト機能の全体像を確認してください。
今回は、サイト機能を使って、「ウェビナーアプリ」を作成します。

注意

設定の説明部分にて、ソースコードを記載しております。
ソースコードに記載されている ブロックのID や 各種リンク や name値 含めて文言などは、デモの環境に合わせたものとなります。
実際に同様のものを作成する際は、変更が必要となる箇所がありますので、ご注意ください。
ソース内の「f0○○」と「record[○○]」について
ソース内の「f0○○」という箇所には、ブロックのフィールド一覧に記載されている識別名が入ります。
また、「record[○○]」という箇所には、フィールドID(name属性から「f0」を除いた数字)が入ります。

フロー・使用機能の整理

ウェビナーアプリの全体フローを整理し、認証エリア内で触れる画面と使用している機能をまとめました。
MKupdate vol.10 での内容を含んでいるため、ver.2.19 と ver.2.20 でのアップデート内容を含めて記載いたします。
全体のフロー
▼使用する機能
認証エリア 会員認証
ページ機能 公開ページなどの各ページ
ブロック機能 登録フォーム
会員登録・ウェビナー申込 で使用しています
ブロック機能 更新フォーム
アンケート で使用しています
ブロック機能 削除フォーム
申込キャンセル で使用しています
ブロック機能 レコードリスト
ウェビナー 一覧・アーカイブ動画一覧・申込済ウェビナー 一覧 で使用しています
ブロック機能 レコードアイテム
ウェビナー詳細・アーカイブ動画・申込済みウェビナー詳細で使用しています
ブロック機能 フリーコンテンツ
ヘッダ・フッタで使用しています
※ デモのため、会員情報変更・退会の画面は用意しておりません。
公開ページ
認証後ページ
全体のフォルダ構成
各機能の詳細に関しては、下記を参照ください。
ページ機能
ブロック機能
認証エリア

認証エリアと公開ページの作成

手順1:認証エリアを作成
ウェビナーアプリを作成するため、認証エリアのタブより認証エリアの作成を行います。
識別名がURLのディレクトリ名になるので、使用したいURLの階層に合わせて設定してください。
認証エリアの中でも認証が不要なページも作成できます。
今回は、認証エリア内に会員限定の認証ページと誰でも見ることができる非認証のページを作成します。
手順2:公開ページを作成
手順1で作成した認証エリアから「+」ボタンから新規ページを作成します。
公開ページを作成するため、認証はなしで設定します。
手順3:ヘッダ用ブロックを作成
手順2で作成したページのブロック設定(ページがソース設定の場合は、BODY) から「+」ボタンを押下し、フリーコンテンツブロックで共通となるヘッダを作成を作成します。

Header html
<header id="header">
    <div id="topVisual">
      <div class="mainTxt ">
        <h1><a th:href="${pages['p0xxx']?.path ?:'/404'}">
          <img src="/_media/webinar/logo.svg" alt="SPIRAL®" width="265">
          <span>デモ</span></a></h1>
      </div>
    </div>
    <div class="btnBlock">
        <a target="_blank" href="https://knowledge-search.spiral-site.com/bizpro_contact?category=demo" class="contact-btn"><span>お問い合わせ</span></a>
        <a th:href="${pages['p011185']?.path ?:'/404'}" class="login-btn"><span>ログイン</span></a>
    </div>
</header>
Header CSS
/*----------------------------
Header
-----------------------------*/
#header {
  position: fixed;
  height: auto;
  top: 0;
  left: 0;
  width: 100%;
  display: flex;
  padding-left: 20px;
  padding-right: 40px;
  align-items: center;
  justify-content: space-between;
  z-index: 100;
  box-shadow: 0 5px 1px -3px #cececf;
  background: #fff;
  opacity: 0.8;
}
#header #topVisual{
  background-size: 100%;
  height:100%;
  box-shadow: 0 5px 1px -3px #cececf;
  padding-bottom: 9px;
}

@media (max-width: 750px) {
  #header #topVisual .mainTxt {
    display: inline-block;
    margin-top: 12px;
  }
}
#header #topVisual .mainTxt {
  padding-top: 13px;
  height:100%;
  display: flex;
  align-items: flex-end;
  text-align: center;
  margin: auto;
}
#header #topVisual .loginHead {
  padding-left: 115px;
}

#header #topVisual .mainTxt h1 {
  margin: 0 auto;
  height:100%;
}

#header #topVisual .mainTxt h1 a{
  color: #333;
  display: flex;
  align-items: flex-end;
  margin: auto;
}

@media only screen and (max-width:1280px) {
  #header #topVisual .mainTxt {
    right: auto;
    float: none;
    padding-left: 0px;
    display: block;
  }
}
@media only screen and (max-width: 751px){
  #header #topVisual .mainTxt h1{
    padding-top: 7px;
    padding-left: 0px;
  }
}

@media (max-width: 750px) {
  #header #topVisual .mainTxt h1 img {
    width: 136px;
    max-width: 100%;
    margin-bottom: 2px;
  }
}
@media (min-width: 751px) and (max-width: 1200px) {
  #header #topVisual .mainTxt h1  img {
    width: 18.4027777778vw;
  }
}
@media (min-width: 1201px) and (max-width: 1920px) {
  #header #topVisual .mainTxt h1  img {
    width: 198.75px;
  }
}

#header #topVisual .mainTxt h1 span {
  font-size: 20px;
  color: #335477;
  font-weight: bold;
  display: block;
  margin-left: 7px;
  line-height: 1;
  margin-bottom: 13px;
  white-space: nowrap;
}
@media (max-width: 750px) {
  #header #topVisual .mainTxt h1  span {
    font-size: 10px;
    margin-left: 5px;
    margin-bottom: 0;
  }
}
@media (min-width: 751px) and (max-width: 1200px) {
  #header #topVisual .mainTxt h1  span {
    font-size: 1.3888888889vw;
    margin-bottom: 0.9027777778vw;
  }
}
@media (min-width: 1201px) and (max-width: 1920px) {
  #header #topVisual .mainTxt h1  span {
    margin-bottom: 3.75px;
  }
}


#header .btnBlock {
    margin-top: 8px;
}
#header a.contact-btn {
    background: #0064B1 0% 0% no-repeat padding-box;
    border: 1px solid #E0E0E0;
    border-radius: 21px;
    opacity: 1;
    width: 144px;
    text-align: center;
    font-size: 1.6rem;
    color: #fff;
    font-weight: bold;
    padding: 7px;
    position: relative;
    display: inline-block;
    overflow: hidden;
    margin-right: 15px;
}
#header a.contact-btn:hover {
    text-decoration: none;
    color: #fff;
    box-shadow: none;
    -webkit-transform: translateY(2.5px);
}

@media (max-width: 750px) {
  #header a.contact-btn,
  #header a.list-btn {
    margin-right: 2px;
  }
}

#header a.login-btn {
    background: #F6F6F6 0% 0% no-repeat padding-box;
    border: 1px solid #E0E0E0;
    border-radius: 21px;
    opacity: 1;
    width: 114px;
    text-align: center;
    font-size: 1.6rem;
    color: #333333;
    font-weight: bold;
    padding: 7px;
    position: relative;
    display: inline-block;
    overflow: hidden;
}
#header a.login-btn:hover {
    text-decoration: none;
    color: #333333;
    box-shadow: none;
    -webkit-transform: translateY(2.5px);
}
#header a.list-btn {
    background: #383081 0% 0% no-repeat padding-box;
    border: 1px solid #E0E0E0;
    border-radius: 21px;
    opacity: 1;
    width: 170px;
    text-align: center;
    font-size: 1.6rem;
    color: #fff;
    font-weight: bold;
    padding: 7px;
    position: relative;
    display: inline-block;
    overflow: hidden;
    margin-right: 15px;
}
#header a.list-btn:hover {
    text-decoration: none;
    color: #fff;
    box-shadow: none;
    -webkit-transform: translateY(2.5px);
}

@media (max-width: 750px) {
    #header .btnBlock {
        float: right;
        margin-top: 12px;
        border-radius: 15px;
        line-height: 30px;
        height: 30px;
    }
  #header a.login-btn,
  #header a.list-btn,
  #header a.contact-btn {
     font-size: 0.8rem;
     width: 80px;
     padding: 0;
  }
}
@media (min-width: 1201px) and (max-width: 1920px) {
  #header .btnBlock {
        font-size: 15px;
  }
}
ロゴ画像は、サイトファイルにアップロードしています。
※ サイトファイルは、ver.2.20 の新機能となります。

手順4:公開ページに埋め込むウェビナー 一覧を作成
レコードリストを作成しレコード情報を表示させるには、 レコード公開範囲の設定が必要となります。
ウェビナー 一覧では、一般公開とエリア認証時公開での出し分けはないので、条件なしで設定します。
レコード公開範囲の設定が完了しましたら、手順2で作成したページのブロック設定(ページがソース設定の場合は、BODY) から「+」ボタンを押下し、ウェビナー 一覧を作成を作成します。
ウェビナー 一覧では検索機能を使用しないので、レコードリストブロックを選択しウェビナーDB のレコードリストを作成します。
タイル型で表示させるため下記のようにHTMLおよびCSSを標準ソースより修正しています。
※ ver.2.19 で、レコードリスト・レコードアイテムでのファイル型フィールド対応しています。

HTML
<div class="sp-record-list-container">
    <div class="sp-record-list-parts">
        <div class="containerBox">
            <div class="webinar" th:each="record, stat : ${pageRecords}">
                <sp:record-data-field name="f02"></sp:record-data-field>
                <th:block th:with="files=${record['f02']}" th:remove="${files == null ? 'body' : 'none'}">
                    <img th:if="${files.size == 1}" th:with="file=${files[0]}" class="imgBox" th:src="${file.fileUrl}" alt="" />
                </th:block>
                <div class="textBox">
                    <!--/* セミナータイトル (title) */-->
                    <sp:record-data-field name="f03"></sp:record-data-field>
                    <p class="titleTxt" th:text="${record['f03']}">Example</p>
                    <!--/* 開催日 (date) */-->
                    <sp:record-data-field name="f04"></sp:record-data-field>
                    <sp:record-data-field name="f05"></sp:record-data-field>
                    <sp:record-data-field name="f06"></sp:record-data-field>
                    <p class="dateTxt" th:with="week=${ { '', '日', '月', '火', '水', '木', '金', '土' } }" th:text="${record['f04'] != null && record['f05'] != null && record['f06'] != null} ? '開催日:'+${record['f04'].format('yyyy/MM/dd')}+ |(${week[record['f04'].format('e')]})|+ ${record['f05'].format('HH:mm')}+' ~ '+${record['f06'].format('HH:mm')} : ''">2000/01/01 </p>
                    <p class="seminarTxt" ><span style="color:#afafaf;">開催概要</span><br />
                    <!--/* セミナー概要 (text) */-->
                    <sp:record-data-field name="f09"></sp:record-data-field>
                    <span th:text="${record['f09']}">Example</span>
                    </p><br />
                    <sp:record-data-field name="f_id"></sp:record-data-field>
                    <a th:if="!${cp.result.value['login']}" th:href="|${pages['p011233']?.path ?: '/404'}?${record.linkParam}|" class="webinarLink">詳細を見る</a>
                    <a th:if="${cp.result.value['login']}" th:href="|${pages['p011240']?.path ?: '/404'}?${record.linkParam}|" class="webinarLink">詳細を見る</a>
                </div>
            </div>
        </div>
        <div class="sp-record-list-no-records" th:if="${recordList.totalRecordCount == 0}">
            開催中のウェビナーはありません。
        </div>
    </div>
</div>
CSS
.webinar{
    border: solid;
    margin-bottom: 25px;
    display: flex;
    border-color: #eeeeee;
    border-width: 1px;
    overflow: hidden;
    border-radius: 10px;
}
.webinar .imgBox{
    display: inline-block;
    width: 512px;
    margin: 0;
}
.webinar .textBox {
    display: inline-block;
    margin-left: 15px;
    vertical-align: top;
    padding: 10px;
    font-size: 20px;
    width: 600px;
}

@media (max-width: 1201px) {
  .webinar{
    display: block;
    overflow: hidden;
  }
  .webinar .imgBox{
    width: 100%;
    margin:0 auto;
  }
  .webinar .textBox {
      width:100%;
      margin:0;
  }
}


.webinar .textBox p.titleTxt{
    font-weight: bold;
    margin: 0 0 8px;
}

.webinar .textBox p.dateTxt,
.webinar .textBox p.seminarTxt{
    font-size:16px;
}
.webinar .textBox span{
    font-size:14px;
}
.webinar .textBox a{
    font-size:14px;
    text-decoration: underline;
    color:#0064B1;
    text-underline-offset: 0.15em;
}
ウェビナー 一覧は認証後ページでも使用します。
ログイン前の画面とログイン後の詳細をページを分岐するための処理を追加しております。
分岐処理は後程ポイントで解説します。
次にリスト設定を行います。
表示されるウェビナーは、開催日が明日以降で公開フラグがたっているものを表示させるため、
「フィルタ」を下記の内容で設定します。
最後に初期ソートを開催日昇順に変更し、初期表示を20件に設定してブロック作成が完了となります。
ウェビナー 一覧では、ページャーをつけていないので、初期表示を20件にしています。
手順5:公開ページに埋め込むアーカイブ一覧を作成
アーカイブ一覧では、ウェビナー 一覧と同じウェビナーDBから作成する一覧になります。
検索機能を使用しないので、レコードリストブロックを選択しウェビナーDB のレコードリストを作成します。
アーカイブ一覧もタイル型で表示させるため下記のようにHTMLおよびCSSを標準ソースより修正しています。
※ ver.2.19 で、レコードリスト・レコードアイテムでのファイル型フィールド対応しています。

HTML
<div class="sp-record-list-container"> 
    <div class="containerBox">
        <div class="archiveBox">
            <div class="archiveList" th:each="record, stat : ${pageRecords}">
                <sp:record-data-field name="f_id"></sp:record-data-field> 
                <sp:record-data-field name="f0xx"></sp:record-data-field>
                <sp:record-data-field name="f0xx"></sp:record-data-field> 
                <sp:record-data-field name="f0xx"></sp:record-data-field> 
                <sp:record-data-field name="f0xx"></sp:record-data-field> 
                <a th:href="|${pages['p0xxx']?.path ?: '/404'}?${record.linkParam}|" class="archiveLink">
                    <th:block th:with="files=${record['f0xx']}" th:remove="${files == null ? 'body' : 'none'}"> 
                        <img class="archiveImg" th:if="${files.size == 1}" th:with="file=${files[0]}" th:src="${file.fileUrl}" width="540px;" alt="" />
                    </th:block>
                    <span class="archiveDate" th:with="week=${ { '', '日', '月', '火', '水', '木', '金', '土' } }" th:text="${record['f0xx'] != null} ? '開催日:' + ${record['f0xx'].format('yyyy/MM/dd')} + |(${week[record['f0xx'].format('e')]})| : ''">2000/01/01</span>
                    <p class="archiveTitle" th:text="${record['f03']}">Example</p>
                </a>
            </div>
        </div>
        <div class="sp-record-list-no-records" th:if="${recordList.totalRecordCount == 0}">
            公開中のアーカイブはありません。
        </div> 
    </div>   
    <div class="sp-record-list-parts sp-record-list-pagination"> 
        <div class="sp-record-list-pagination-left"></div> 
        <div class="sp-record-list-pagination-center"> 
        <ul class="sp-page-navs" th:with="pageNavItemSize = 5" th:if="${recordList.totalRecordCount != 0}"> 
            <li class="sp-page-nav-item" th:if="!${pagination.isFirstPage}">
            <a th:href="${pagination.firstPageLink}"><i class="fa fa-angle-double-left"></i></a>
            </li> 
            <li class="sp-page-nav-item" th:if="!${pagination.isFirstPage}">
            <a th:href="${pagination.prevPageLink}"><i class="fa fa-angle-left"></i></a>
            </li> 
            <li class="sp-page-nav-item" th:each="item : ${pagination.getPrevPageNavItems(pageNavItemSize)}">
            <a th:text="${item.pageNum}" th:href="${item.link}">Page Number</a>
            </li> 
            <li class="sp-page-nav-item sp-page-nav-current">
            <span th:text="${pagination.currentPageNum}">Page Number</span>
            </li> 
            <li class="sp-page-nav-item" th:each="item : ${pagination.getNextPageNavItems(pageNavItemSize)}">
            <a th:text="${item.pageNum}" th:href="${item.link}">Page Number</a>
            </li> 
            <li class="sp-page-nav-more" th:if="${pagination.showEllipsis}">...</li> 
            <li class="sp-page-nav-item" th:if="!${pagination.isLastPage}">
            <a th:href="${pagination.nextPageLink}"><i class="fa fa-angle-right"></i></a>
            </li> 
            <li class="sp-page-nav-item" th:if="!${pagination.isLastPage} and !${recordList.recordCountLimitExceeded}">
            <a th:href="${pagination.lastPageLink}"><i class="fa fa-angle-double-right"></i></a>
            </li> 
        </ul> 
        </div> 
        <div class="sp-record-list-pagination-right"></div> 
    </div> 
</div>
CSS
@media (max-width: 750px) {
    .containerBox .archiveBox {
      padding-left: 38px;
      padding-right: 38px;
      margin-bottom: 40px;
    }
  }
  @media (min-width: 751px) {
    .containerBox .archiveBox {
      display: flex;
      align-items: stretch;
      justify-content: flex-start;
      margin-bottom: 48px;
      flex-flow: row wrap;
    }
  }
  @media (min-width: 751px) and (max-width: 1920px) {
    .containerBox .archiveBox {
      margin-bottom: 0;
    }
  }
  .containerBox .archiveBox .archiveList {
    transition: box-shadow 0.3s;
  }
  @media (max-width: 750px) {
    .containerBox .archiveBox .archiveList {
      width: 100%;
      border-radius: 8px;
      box-shadow: 0 0 6px rgba(0, 0, 0, 0.16);
      overflow: hidden;
      padding-bottom: 28px;
      background: #FFF;
      margin-bottom: 40px;
    }
  }
  @media (min-width: 751px) {
    .containerBox .archiveBox .archiveList {
      flex: 0 0 30.67%;
      width: 30.67%;
      margin-right: 3.995%;
      display: block;
      background: #FFF;
      border-radius: 15px;
      overflow: hidden;
      box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
      padding-bottom: 32px;
      margin-bottom: 53px;
    }
  }
  @media (min-width: 751px) and (max-width: 1920px) {
    .containerBox .archiveBox .archiveList {
      border-radius: 5.5px;
      padding-bottom: 0;
      margin-bottom: 40.5px;
    }
  }
  .containerBox .archiveBox .archiveList:hover {
    box-shadow: 0 0 20px rgba(84, 143, 164, 0.4);
  }
  @media (max-width: 750px) {
    .containerBox .archiveBox .archiveList:hover {
      box-shadow: 0 0 12px rgba(84, 143, 164, 0.4);
    }
  }
  .containerBox .archiveBox .archiveList:nth-child(3n) {
    margin-right: 0;
  }
  .containerBox .archiveBox .archiveList .archiveLink {
    display: block;
  }
  .containerBox .archiveBox .archiveList .archiveLink:hover {
    opacity: 1;
  }
  .containerBox .archiveBox .archiveList .archiveLink .archiveImg {
    display: block;
    width: 100%;
    margin-bottom: 10px;
  }

  .containerBox .archiveBox .archiveList .archiveLink .archiveDate {
    display: block;
    padding: 0 36px;
    font-size: 1.6rem;
    letter-spacing: 0.1em;
    color: #000;
    margin-bottom: 0;
  }
  @media (max-width: 750px) {
    .containerBox .archiveBox .archiveList .archiveLink .archiveDate {
      font-size: 1.2rem;
      padding: 0 20px;
    }
  }
  @media (min-width: 751px) and (max-width: 1920px) {
    .containerBox .archiveBox .archiveList .archiveLink .archiveDate {
      padding-left: 13px;
      font-size: 1.2rem;
    }
  }
  .containerBox .archiveBox .archiveList .archiveLink .archiveTitle {
    font-weight: bold;
    color: #000;
    letter-spacing: 0.1em;
    line-height: 0.2;
    padding: 0 36px;
  }
  @media (max-width: 750px) {
    .containerBox .archiveBox .archiveList .archiveLink .archiveTitle {
      padding: 0 20px;
      font-size: 1.5rem;
      line-height: 1.47;
    }
  }
  @media (min-width: 751px) and (max-width: 1920px) {
    .containerBox .archiveBox .archiveList .archiveLink .archiveTitle {
        font-size: 1.5rem; 
        padding-left: 13px;
        padding-bottom: 10px;
        line-height: 1.25;
    }
  }


.sp-record-list-container {
    color:#333333;
    background-color:#ffffff;
  }
  
  .sp-record-list-container .sp-html-parts p { margin:0; }
  
  .sp-record-list-container .sp-record-list-parts { margin-bottom:.5rem; }
  
  .sp-record-list-container .sp-record-list-table {
    line-height:1.15;
    border-collapse:collapse;
    width:100%;
    margin-bottom:1rem;
    color:#333333;
  }
  
  .sp-record-list-container .sp-record-list-table caption {
    padding-top:0.75rem;
    padding-bottom:0.75rem;
    color:#6c757d;
    text-align:left;
    caption-side:bottom;
  }
  
  .sp-record-list-container .sp-record-list-table a { text-decoration:none; }
  
  .sp-record-list-container .sp-record-list-table a:hover { text-decoration:underline; }
  
  .sp-record-list-container .sp-record-list-table th { text-align:inherit; }
  
  .sp-record-list-container .sp-record-list-table th,
  .sp-record-list-container .sp-record-list-table td {
    padding:0.75rem;
    vertical-align:top;
    border-top:1px solid #dddddd;
  }
  
  .sp-record-list-container .sp-record-list-table thead th {
    color:#555555;
    font-weight:bold;
    vertical-align:top;
    border-bottom:1px solid #dddddd;
    text-align:left;
  }
  
  .sp-record-list-container .sp-record-list-table thead th.sp-nowrap { white-space:nowrap; }
  
  .sp-record-list-container .sp-record-list-table thead th.sp-nowrap-truncate { white-space:nowrap; }
  
  .sp-record-list-container .sp-record-list-table thead th.sp-nowrap-truncate a>span:first-child {
    display:inline-block;
    vertical-align:middle;
    max-width:12rem;
    overflow:hidden;
    text-overflow:ellipsis;
  }
  
  .sp-record-list-container .sp-record-list-table thead th a {
    color:inherit;
    text-decoration:none;
  }
  
  .sp-record-list-container .sp-record-list-table thead th a .sp-sorting-asc,
  .sp-record-list-container .sp-record-list-table thead th a .sp-sorting-desc { color:#808080; }
  
  .sp-record-list-container .sp-record-list-table thead th a .sp-sorting-asc .fa,
  .sp-record-list-container .sp-record-list-table thead th a .sp-sorting-desc .fa { font-weight:bold; }
  
  .sp-record-list-container .sp-record-list-table thead th a .sp-sorting-desc { visibility:hidden; }
  
  .sp-record-list-container .sp-record-list-table thead th a .sp-sorting-asc { display:none; }
  
  .sp-record-list-container .sp-record-list-table thead th a.sp-desc-sorted .sp-sorting-desc { visibility:visible; }
  
  .sp-record-list-container .sp-record-list-table thead th a.sp-asc-sorted .sp-sorting-asc { display:inline; }
  
  .sp-record-list-container .sp-record-list-table thead th a.sp-asc-sorted .sp-sorting-desc { display:none; }
  
  .sp-record-list-container .sp-record-list-table thead th a:hover {
    color:#333333;
    text-decoration:none;
  }
  
  .sp-record-list-container .sp-record-list-table thead th a:hover:not(.sp-sorted) .sp-sorting-desc { visibility:visible; }
  
  .sp-record-list-container .sp-record-list-table tbody+tbody { border-top:2px solid #dddddd; }
  
  .sp-record-list-container .sp-record-list-table tr:first-child th,
  .sp-record-list-container .sp-record-list-table tr:first-child td { border-top:0; }
  
  .sp-record-list-container .sp-record-list-table td a {
    color:#3b7e9b !important;
    font-weight:bold;
  }
  
  .sp-record-list-container .sp-record-list-table td span:nth-child(n+2) { margin-left:.1rem; }
  
  .sp-record-list-container .sp-record-list-table a.sp-form-file-bold-link {
    text-decoration:none !important;
    color:#3b7e9b;
    cursor:pointer;
    font-weight:bold;
  }
  
  .sp-form-file-text-label { color:#6c757d; }
  
  .sp-record-list-container .sp-table-sm th,
  .sp-record-list-container .sp-table-sm td { padding:0.3rem; }
  
  .sp-record-list-container .sp-table-bordered { border:1px solid #dddddd; }
  
  .sp-record-list-container .sp-table-bordered th,
  .sp-record-list-container .sp-table-bordered td { border:1px solid #dddddd; }
  
  .sp-record-list-container .sp-table-bordered thead th,
  .sp-record-list-container .sp-table-bordered thead td { border-bottom-width:2px; }
  
  .sp-record-list-container .sp-table-borderless th,
  .sp-record-list-container .sp-table-borderless td,
  .sp-record-list-container .sp-table-borderless tbody+tbody { border:0; }
  
  .sp-record-list-container .sp-table-striped tbody tr:nth-of-type(odd) { background-color:rgba(0,0,0,0.025); }
  
  .sp-record-list-container .sp-table-hover tbody tr:hover {
    color:#333333;
    background-color:rgba(0,0,0,0.05);
  }
  
  .sp-record-list-container .sp-record-list-no-records {
    margin:6.25rem auto;
    text-align:center;
    color:#808080;
  }
  
  .sp-record-list-pagination {
    display:-webkit-box;
    display:-ms-flexbox;
    display:flex;
    -webkit-box-pack:justify;
    -ms-flex-pack:justify;
    justify-content:space-between;
    -webkit-box-align:center;
    -ms-flex-align:center;
    align-items:center;
  }
  
  .sp-record-list-pagination .sp-record-list-pagination-left,
  .sp-record-list-pagination .sp-record-list-pagination-center,
  .sp-record-list-pagination .sp-record-list-pagination-right {
    display:-webkit-box;
    display:-ms-flexbox;
    display:flex;
    -webkit-box-align:center;
    -ms-flex-align:center;
    align-items:center;
  }
  
  .sp-record-list-pagination .sp-record-list-pagination-left>*,
  .sp-record-list-pagination .sp-record-list-pagination-center>*,
  .sp-record-list-pagination .sp-record-list-pagination-right>* { margin:0 .5rem; }
  
  .sp-record-list-pagination .sp-record-list-pagination-left {
    -webkit-box-pack:start;
    -ms-flex-pack:start;
    justify-content:flex-start;
  }
  
  .sp-record-list-pagination .sp-record-list-pagination-center {
    -webkit-box-pack:center;
    -ms-flex-pack:center;
    justify-content:center;
  }
  
  .sp-record-list-pagination .sp-record-list-pagination-right {
    -webkit-box-pack:end;
    -ms-flex-pack:end;
    justify-content:flex-end;
  }
  
  .sp-record-list-pagination .sp-form-control {
    -webkit-appearance:none;
    -moz-appearance:none;
    appearance:none;
    font-family:inherit;
    font-size:1rem;
    line-height:1.5;
    padding:.3rem .7rem;
    color:#333333;
    -webkit-box-sizing:border-box;
    box-sizing:border-box;
    width:100%;
    margin-bottom:0.2rem;
    border:1px solid #dddddd;
    border-radius:.25rem;
  }
  
  .sp-record-list-pagination .sp-form-inline .sp-form-control {
    display:inline-block;
    width:auto;
    vertical-align:middle;
  }
  
  .sp-record-list-pagination select.sp-form-control,
  .sp-record-list-pagination option.sp-form-control {
    -webkit-appearance:none;
    -moz-appearance:none;
    appearance:none;
    padding-right:1.5rem;
  }
  
  .sp-record-list-pagination select.sp-form-control::-ms-expand { display:none; }
  
  .sp-record-list-pagination .sp-form-dropdown { position:relative; }
  
  .sp-record-list-pagination .sp-form-dropdown-inline {
    position:relative;
    display:inline-block;
  }
  
  .sp-record-list-pagination .sp-form-dropdown-icon {
    display:block;
    position:absolute;
    top:1rem;
    right:.5rem;
    line-height:0;
    pointer-events:none;
  }
  
  .sp-record-list-pagination .sp-form-dropdown-icon:after {
    content:"";
    display:block;
    border-top:.333rem solid #888888;
    border-right:.333rem solid transparent;
    border-left:.333rem solid transparent;
  }
  
  .sp-record-list-pagination ul.sp-page-navs {
    display:-webkit-box;
    display:-ms-flexbox;
    display:flex;
    padding-left:0;
    list-style:none;
  }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item {
    line-height:1.25rem;
    text-align:center;
    -webkit-user-select:none;
    -moz-user-select:none;
    -ms-user-select:none;
    user-select:none;
    white-space:nowrap;
  }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item a,
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item span {
    display:inline-block;
    margin:0 0.2rem;
    border-radius:.25rem;
    border:1px solid #a0a0a0;
    color:#333333;
    padding: 8px;
  }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item a .fa,
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item span .fa {
    font-size: 1.2em;
    width: 1rem;
    line-height: 0;
  }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item a { text-decoration:none; }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item a:hover { background-color:rgba(0,0,0,0.075); }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item span {
    background-color:#b2b2b2;
    color:#DBDBDB;
  }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item.sp-page-nav-current span {
      background-color:#b2b2b2;
      border-color:#a0a0a0;
      color:#f9f9f9;
      padding: 8px;
    }
    
    .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-more {
      line-height:1rem;
      text-align:center;
      margin:0 .2rem;
      padding:.375rem .3rem;
    }
    
アーカイブ一覧は、認証後ページでも使用します。
最後にアーカイブフラグが公開のフィルタを作成し、初期表示を6件に設定してブロック作成が完了となります。
アーカイブ一覧は、3件ずつの横並びのデザインのため、初期表示6件に設定しています。
また、数が増えていくのでページャーをつけています。
手順6:公開ページのブロック埋め込みとデザイン反映
手順2で作成した公開ページに手順3/手順4で作成したレコードリストを埋め込み、デザインを反映します。

HTML
<div class="wrapper">
    <!-- ヘッダ-->
    <sp:block name="fcb0xxx"></sp:block>
    <div class="mainVisual">
        <img src="/_media/webinar/maiVisual.jpg" alt="maiVisual.jpg">
        <h1>ウェビナーアプリ デモ</h1>
    </div>        
    <div class="contents inner-1200 inner-sp mt00">
        <div class="webinarArea">
            <h2 class="title">開催予定のウェビナー</h2>
            <sp:block name="rlb0xxx"></sp:block>
            <h2 class="title">ウェビナーアーカイブ</h2>
            <P class="cautionNote">※ アーカイブ動画を視聴するためには、会員登録が必要です。</P>
            <sp:block name="rlb0xxx"></sp:block>
        </div>
    </div>
    <!-- フッタ-->
</div>
公開ページで使用しています、メインビジュアルは、サイトファイルにしています。
メインビジュアル:
また、ページのCSSは共通となるので、page.css ファイルを作成し、サイトファイルにアップロードします。

page.css
@charset "UTF-8";
html {
  font-size: 62.5%;
  scroll-padding-top: 110px;
  overflow-x: hidden;
}
@media (max-width: 750px) {
  html {
    scroll-padding-top: 120px;
  }
}

* {
  box-sizing: border-box;
}

img {
  max-width: 100%;
  height: auto;
}

body {
  font-family: 'M PLUS 1', sans-serif;
  font-size: 1rem;
  margin: 0;
  padding: 0;
  overflow-x: hidden;
  position: relative;
}
@media screen and (min-width: 751px) {
  body {
    font-size: 1.8rem;
  }
}

ul, ol, dl {
  font-size: 1em;
}

ul li ul, ul li ol {
  margin: 0;
}

a, button {
  text-decoration: none;
  transition: opacity 0.3s ease;
}
a:hover, button:hover {
  opacity: 0.7;
}

.flex {
  display: flex;
}

.flex--space {
  justify-content: space-between;
}

.flex--wrap {
  flex-wrap: wrap;
}

@media (max-width: 750px) {
  .pc_only {
    display: none !important;
  }
}
@media screen and (min-width: 751px) {
  .sp_only {
    display: none !important;
  }
}
.inner-1200 {
  width: calc(100% - 80px);
  max-width: 1200px;
  margin-left: auto;
  margin-right: auto;
}
/* Margin
--------------------------------------------- */
/* Top */
.mt00 {margin-top: 0 !important;}
.mt05 {margin-top: 5px !important;}
.mt10 {margin-top: 10px !important;}
.mt15 {margin-top: 15px !important;}
.mt20 {margin-top: 20px !important;}
.mt25 {margin-top: 25px !important;}
.mt30 {margin-top: 30px !important;}
.mt35 {margin-top: 35px !important;}
.mt40 {margin-top: 40px !important;}
.mt45 {margin-top: 45px !important;}
.mt50 {margin-top: 50px !important;}
.mt10 {margin-top: 1.0em !important;}
.mt06 {margin-top: 0.6em !important;}
/* Right */
.mr05 {margin-right: 5px !important;}
.mr10 {margin-right: 10px !important;}
.mr15 {margin-right: 15px !important;}
.mr20 {margin-right: 20px !important;}
.mr25 {margin-right: 25px !important;}
.mr30 {margin-right: 30px !important;}
.mr35 {margin-right: 35px !important;}
.mr40 {margin-right: 40px !important;}
.mr45 {margin-right: 45px !important;}
.mr50 {margin-right: 50px !important;}
/* Bottom */
.mb00 {margin-bottom: 0px !important;}
.mb05 {margin-bottom: 5px !important;}
.mb10 {margin-bottom: 10px !important;}
.mb15 {margin-bottom: 15px !important;}
.mb20 {margin-bottom: 20px !important;}
.mb25 {margin-bottom: 25px !important;}
.mb30 {margin-bottom: 30px !important;}
.mb35 {margin-bottom: 35px !important;}
.mb40 {margin-bottom: 40px !important;}
.mb45 {margin-bottom: 45px !important;}
.mb50 {margin-bottom: 50px !important;}
/* Left */
.ml05 {margin-left: 5px !important;}
.ml10 {margin-left: 10px !important;}
.ml15 {margin-left: 15px !important;}
.ml20 {margin-left: 20px !important;}
.ml25 {margin-left: 25px !important;}
.ml30 {margin-left: 30px !important;}
.ml35 {margin-left: 35px !important;}
.ml40 {margin-left: 40px !important;}
.ml45 {margin-left: 45px !important;}
.ml50 {margin-left: 50px !important;}


/*----------------------------
下層ページ
-----------------------------*/
.wrapper .contents {
    min-height: calc(100vh - 298px);
    margin-top: 75px;
    margin-bottom: 50px;
}
.wrapper .mainVisual{
    margin-top: 60px;
    margin-bottom: 0;
    padding: 0;
    position: relative
}
.wrapper .mainVisual img{
    height: 320px;
    width: 100%;
}
.wrapper  .mainVisual h1{
    color: #fff;
    text-align: center;
    font-size: 42px;
    position: absolute;
    top: 50%;
    left: 50%;
    -ms-transform: translate(-50%,-50%);
    -webkit-transform: translate(-50%,-50%);
    transform: translate(-50%,-50%);
    margin: 0;
    padding: 0;
    width: 80%;
}
@media screen and (max-width: 1000px) {
  .wrapper  .mainVisual h1{
    font-size: 32px;
  }
}

.wrapper .contents .webinarDetail{
  margin: 120px auto;
  max-width: 900px;
}
.wrapper .contents .webinarDetail .webinarDetailBox{
  background: #FFFFFF 0% 0% no-repeat padding-box;
  border: 1px solid #707070;
}
.wrapper .contents h2.title{
  color: #333333;
  font-size: 3.5rem;
  font-weight: bold;
  text-align: center;
  margin-bottom: 15px;
  margin-top: 0;
  padding-top: 20px;
}
.wrapper .contents p.cautionNote{
    margin-bottom: 8px;
    font-size: 0.9em;
    color: #afafaf;
}
head は、全ページ共通で下記で設定します。

head
<title th:text="${page.title}"></title>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v6.1.1/css/all.css">
<!-- 	Font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=M+PLUS+1:wght@500;700&display=swap" rel="stylesheet">
<!-- 	/Font -->
<!-- ページ共通のCSS -->
<link rel="stylesheet" media="all" href="/_media/webinar/pages.css">
<!-- ページ共通のCSS -->
公開ページで読み込んでいるブロックか認証後ページで読み込んでいるブロックを判定するためにPHPを記載しております。

PHP
<?php
$SPIRAL->setTHValue("login",false);
設定が完了しデザイン崩れなく公開ページのページが表示されれば、公開ページの作成完了となります。

ポイント①
レコードリストの詳細リンク出し分け
公開ページで読み込んでいるブロックか認証後ページで読み込んでいるブロックで詳細画面のページを出し分けています。
PHPで 公開ページは、false , 認証後ページでは、true の値を渡して、リンク先を出し分けています。

PHP
<?php
$SPIRAL->setTHValue("login",false);
Thymeleaf 抜粋
<sp:record-data-field name="f_id"></sp:record-data-field>
<a th:if="!${cp.result.value['login']}" th:href="|${pages['p0xxx']?.path ?: '/404'}?${record.linkParam}|" class="webinarLink">詳細を見る</a>
<a th:if="${cp.result.value['login']}" th:href="|${pages['p0yyy']?.path ?: '/404'}?${record.linkParam}|" class="webinarLink">詳細を見る</a>
ポイント②
日付フィールドから曜日を表示
日付フィールドから曜日を表示しております。
曜日表示は、日時フィールド・日付フィールドで可能です。
デモでは、開始時間・終了時間も表示しています。

Thymeleaf 抜粋
<p class="dateTxt" th:with="week=${ { '', '日', '月', '火', '水', '木', '金', '土' } }" th:text="${record['f0xx'] != null && record['f0yy'] != null && record['f0zz'] != null} ? '開催日:'+${record['f0xx'].format('yyyy/MM/dd')}+ |(${week[record['f0xx'].format('e')]})|+ ${record['f0yy'].format('HH:mm')}+' ~ '+${record['f0zz'].format('HH:mm')} : ''">2000/01/01 </p>
ポイント③
サイトファイルを使って複数アプリのファイルを管理

SPIRERS ナレッジ向上チームでは、スターターデモ で1サイト内に複数アプリを作成しています。
フォルダ管理を行うことで、複数アプリのファイルをわかりやすく管理できます。
ポイント④
無料で利用可能なWebフォントgoogle fontsを使用

どの OS、ブラウザ でも同じフォントで表示させるため、google fonts を読み込んでいます。
ウェビナー管理アプリ デモでは、「M PLUS 1」を使用しています。
設定方法は こちら を参考にしてください。
手順7:ウェビナーのレコードアイテム ブロックを作成
ウェビナー 一覧作成時に、ページとレコードアイテムブロックが自動生成されます。
自動生成されたページとブロックは、任意の識別名がついているので、使用したい名称に変更しています。
ウェビナー詳細にもデザインをあてるため下記のようにHTMLおよびCSSを標準ソースより修正しています。
※ ログイン前とログイン後、申込画面など 複数ページで使用するため、分岐処理が多数入っています。

HTML
<div class="backBtnBox">
  <a th:if="${cp.result.value['login'] && !cp.result.value['appPage']}" th:href="|${pages['p0xxx']?.path ?: '/404'}|" class="backBtn">戻る</a>
  <a th:if="${!cp.result.value['login'] && !cp.result.value['appPage']}" th:href="|${pages['p0xxx']?.path ?: '/404'}|" class="backBtn">戻る</a>
</div>
<div class="sp-record-item-container" th:if="${record != null}"> 
  <!--/* メインビジュアル(mainVisual) */-->
  <div class="webinarDetailBox">
    <div class="contantMainVisual">
      <sp:record-item-field name="f0xx"></sp:record-item-field>
      <th:block th:with="files=${record['f0xx']}" th:remove="${files == null ? 'body' : 'none'}"> 
          <img class="imgBox sp-form-file-bold-link" th:if="${files.size == 1}" th:with="file=${files[0]}" th:src="${file.fileUrl}" alt="" />
      </th:block>
    </div>
    <div class="mainContents">
      <!--/* セミナータイトル (title) */--> 
      <sp:record-item-field name="f0xx"></sp:record-item-field> 
      <h3 class="titleTxt" th:text="${record['f0xx']}">Example</h3>
      <!--/* 開催日 (date) */--> 
      <sp:record-item-field name="f0xx"></sp:record-item-field> 
      <sp:record-item-field name="f0xx"></sp:record-item-field> 
      <sp:record-item-field name="f0xx"></sp:record-item-field> 
      <div class="sp-record-item-data">
        <span class="sp-record-item-embedded" th:with="week=${ { '', '日', '月', '火', '水', '木', '金', '土' } }" th:text="${record['f0xx'] != null && record['f0xx'] != null && record['f0xx'] != null} ? '開催日:'+${record['f0xx'].format('yyyy/MM/dd')}+ |(${week[record['f0xx'].format('e')]})|+ ${record['f0xx'].format('HH:mm')}+' ~ '+${record['f0xx'].format('HH:mm')} : ''">2000/01/01 00:00</span>
      </div> 
      <!--/* 申込ボタン */--> 
      <div th:if="${cp.result.isSuccess}">
          <p th:if="${cp.result.value['app']}" class="btnPre">申込済み</p>
          <a th:if="!${cp.result.value['app']}" th:href="|${pages['p0xx']?.path ?: '/404'}?${record.linkParam}|" class="btnJoin">お申込みはこちら</a>
      </div>
      <div th:if="${!cp.result.isSuccess}">
          <p th:text="${cp.result.errorMessage}">error message</p>
      </div>
      <!--/* セミナー概要(text) */-->
      <p class="seminarTxt"><span style="color:#999999;">開催概要</span><br>
        <sp:record-item-field name="p0xx"></sp:record-item-field>
        <span class="sp-record-item-embedded" th:if="${record['p0xx'] != null}">
          <th:block th:each="line, stat : ${record['p0xx'].lines}">
            <th:block th:text="${line}"/>
            <br th:unless="${stat.last}">
          </th:block>
        </span>
      </p>
    </div>
  </div>
  <div class="backBtnBox">
      <a th:if="${cp.result.value['login'] && cp.result.value['appPage']}" th:href="|${pages['p0xx']?.path ?: '/404'}|" class="backBtn">戻る</a>
  </div>
</div>

<div class="sp-record-item-container" th:if="${record == null}"> 
  <div class="sp-record-item-no-item">
    ウェビナーが存在しません。<br /><br />
    <div class="backBtnBok">
      <a th:if="${cp.result.value['login']}" th:href="|${pages['p0xx']?.path ?: '/404'}|" class="backBtn">戻る</a>
      <a th:if="!${cp.result.value['login']}" th:href="|${pages['p0xx']?.path ?: '/404'}|" class="backBtn">戻る</a>
    </div>
  </div> 
</div>
CSS
/*----------------------------
Header
-----------------------------*/
#header {
  position: fixed;
  height: auto;
  top: 0;
  left: 0;
  width: 100%;
  display: flex;
  padding-left: 20px;
  padding-right: 40px;
  align-items: center;
  justify-content: space-between;
  z-index: 100;
  box-shadow: 0 5px 1px -3px #cececf;
  background: #fff;
  opacity: 0.8;
}
#header #topVisual{
  background-size: 100%;
  height:100%;
  box-shadow: 0 5px 1px -3px #cececf;
  padding-bottom: 9px;
}

@media (max-width: 750px) {
  #header #topVisual .mainTxt {
    display: inline-block;
    margin-top: 12px;
  }
}
#header #topVisual .mainTxt {
  padding-top: 13px;
  height:100%;
  display: flex;
  align-items: flex-end;
  text-align: center;
  margin: auto;
}
#header #topVisual .loginHead {
  padding-left: 115px;
}

#header #topVisual .mainTxt h1 {
  margin: 0 auto;
  height:100%;
}

#header #topVisual .mainTxt h1 a{
  color: #333;
  display: flex;
  align-items: flex-end;
  margin: auto;
}

@media only screen and (max-width:1280px) {
  #header #topVisual .mainTxt {
    right: auto;
    float: none;
    padding-left: 0px;
    display: block;
  }
}
@media only screen and (max-width: 751px){
  #header #topVisual .mainTxt h1{
    padding-top: 7px;
    padding-left: 0px;
  }
}

@media (max-width: 750px) {
  #header #topVisual .mainTxt h1 img {
    width: 136px;
    max-width: 100%;
    margin-bottom: 2px;
  }
}
@media (min-width: 751px) and (max-width: 1200px) {
  #header #topVisual .mainTxt h1  img {
    width: 18.4027777778vw;
  }
}
@media (min-width: 1201px) and (max-width: 1920px) {
  #header #topVisual .mainTxt h1  img {
    width: 198.75px;
  }
}

#header #topVisual .mainTxt h1 span {
  font-size: 20px;
  color: #335477;
  font-weight: bold;
  display: block;
  margin-left: 7px;
  line-height: 1;
  margin-bottom: 13px;
  white-space: nowrap;
}
@media (max-width: 750px) {
  #header #topVisual .mainTxt h1  span {
    font-size: 10px;
    margin-left: 5px;
    margin-bottom: 0;
  }
}
@media (min-width: 751px) and (max-width: 1200px) {
  #header #topVisual .mainTxt h1  span {
    font-size: 1.3888888889vw;
    margin-bottom: 0.9027777778vw;
  }
}
@media (min-width: 1201px) and (max-width: 1920px) {
  #header #topVisual .mainTxt h1  span {
    margin-bottom: 3.75px;
  }
}


#header .btnBlock {
    margin-top: 8px;
}
#header a.contact-btn {
    background: #0064B1 0% 0% no-repeat padding-box;
    border: 1px solid #E0E0E0;
    border-radius: 21px;
    opacity: 1;
    width: 144px;
    text-align: center;
    font-size: 1.6rem;
    color: #fff;
    font-weight: bold;
    padding: 7px;
    position: relative;
    display: inline-block;
    overflow: hidden;
    margin-right: 15px;
}
#header a.contact-btn:hover {
    text-decoration: none;
    color: #fff;
    box-shadow: none;
    -webkit-transform: translateY(2.5px);
}

@media (max-width: 750px) {
  #header a.contact-btn,
  #header a.list-btn {
    margin-right: 2px;
  }
}

#header a.login-btn {
    background: #F6F6F6 0% 0% no-repeat padding-box;
    border: 1px solid #E0E0E0;
    border-radius: 21px;
    opacity: 1;
    width: 114px;
    text-align: center;
    font-size: 1.6rem;
    color: #333333;
    font-weight: bold;
    padding: 7px;
    position: relative;
    display: inline-block;
    overflow: hidden;
}
#header a.login-btn:hover {
    text-decoration: none;
    color: #333333;
    box-shadow: none;
    -webkit-transform: translateY(2.5px);
}
#header a.list-btn {
    background: #383081 0% 0% no-repeat padding-box;
    border: 1px solid #E0E0E0;
    border-radius: 21px;
    opacity: 1;
    width: 170px;
    text-align: center;
    font-size: 1.6rem;
    color: #fff;
    font-weight: bold;
    padding: 7px;
    position: relative;
    display: inline-block;
    overflow: hidden;
    margin-right: 15px;
}
#header a.list-btn:hover {
    text-decoration: none;
    color: #fff;
    box-shadow: none;
    -webkit-transform: translateY(2.5px);
}

@media (max-width: 750px) {
    #header .btnBlock {
        float: right;
        margin-top: 12px;
        border-radius: 15px;
        line-height: 30px;
        height: 30px;
    }
  #header a.login-btn,
  #header a.list-btn,
  #header a.contact-btn {
     font-size: 0.8rem;
     width: 80px;
     padding: 0;
  }
}
@media (min-width: 1201px) and (max-width: 1920px) {
  #header .btnBlock {
        font-size: 15px;
  }
}
手順8:ウェビナーページを作成
認証エリア内にページを作成しますが、公開ページになるので「認証なし」で詳細用のページを作成します。
デザインをあてるため下記のようにHTMLおよびCSSを標準ソースより修正しています。

HTML
<div class="wrapper">
    <!-- ヘッダ-->
    <sp:block name="fcb0xx"></sp:block>
    <div class="contents inner-1200 inner-sp">
        <div class="webinarDetail">
            <sp:block name="rib0xx"></sp:block>
        </div>
    </div>
</div>
公開ページで読み込んでいるブロックか認証後ページで読み込んでいるブロックの出し分けと
申込済みボタン表示非表示制御のため以下のPHPを設定しています。

PHP
<?php
$SPIRAL->setTHValue("app", false);
$SPIRAL->setTHValue("login",false);

head は、全ページ共通で下記で設定します。

head
<title th:text="${page.title}"></title>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v6.1.1/css/all.css">
<!-- 	Font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=M+PLUS+1:wght@500;700&display=swap" rel="stylesheet">
<!-- 	/Font -->
<!-- ページ共通のCSS -->
<link rel="stylesheet" media="all" href="/_media/webinar/pages.css">
<!-- ページ共通のCSS -->
手順9:新規会員登録ページを作成
認証エリアから「+」ボタンから新規会員登録ページ を作成します。
新規会員登録ページも非会員がアクセスできるため、「認証なし」で設定します。
ページの作成を行いましたら、そのまま登録ブロックを作成します。
登録ブロックは、ビジュアル設定で作成しても問題ありません。
フィールドは下記となります。

▼ 使用フィールド
フィールド 使用状況
メールアドレス 入力項目
パスワード 入力項目
誕生日 入力項目
登録ブロックが作成完了したら、ブロックを埋め込み、CSSを記載して作成完了となります。
ヘッダブロックと今回作成した登録ブロックを埋め込みます。
その他ページでも同様の構成でページ作成を行います。

HTML
<div class="wrapper">
    <!-- header -->
    <sp:block name="ifbxxxx"></sp:block>
    <!-- header -->
    <div class="contents inner-1200 inner-sp">
        <sp:block name="ifbxxxx"></sp:block>
    </div>
</div>
ポイント⑤
コピペCSS 「シンプルモダン」を使用

今回使用するフォームに関しては、コピペCSS 「シンプルモダン」を使用しています。
コピペCSSはビジュアル設定でも使用できるため、登録ブロックはビジュアル設定のまま作成できます。
登録ブロック、ログインフォームブロック でコピペCSSを使用しています。
ポイント⑥
日付フィールド入力欄が自由に

ver.2.20 のアップデートで日時系フィールドの入力欄がカスタマイズできるようになっています。
従来は、[年][月][日][時][分][秒]を分割する形の入力欄となっていましたが、
[年][月][日]で1つの入力欄とできるようになりました。
入力欄が1つになったことで、カレンダー表示 や javascript による制御が楽になりました。

認証エリア内のページ作成

手順1:ヘッダ をフリーコンテンツを作成
認証後ページ共通で ヘッダ を利用するため、フリーコンテンツブロックに作成します。
こちらもデザインをあてるために、「ソース設定」で設定を行います。
デモのHTMLとCSSを公開します。
リンク部分にデモのURL等が記載されているので、使用する場合は適宜修正をお願いします。

Header html
<header id="header">
    <div id="topVisual">
        <div class="mainTxt ">
        <h1><a th:href="${pages['p0xxx']?.path ?:'/404'}">
            <img src="/_media/webinar/logo.svg" alt="SPIRAL®" width="265">
            <span>デモ</span></a></h1>
        </div>
    </div>
    <div class="btnBlock">
        <a target="_blank" href="https://knowledge-search.spiral-site.com/bizpro_contact?category=demo" class="contact-btn"><span>お問い合わせ</span></a>
        <a href="#" data-logout class="login-btn"><span>ログアウト</span></a>
    </div>
</header> 
Header CSS
/*----------------------------
Header
-----------------------------*/
#header {
  position: fixed;
  height: auto;
  top: 0;
  left: 0;
  width: 100%;
  display: flex;
  padding-left: 20px;
  padding-right: 40px;
  align-items: center;
  justify-content: space-between;
  z-index: 100;
  box-shadow: 0 5px 1px -3px #cececf;
  background: #fff;
  opacity: 0.8;
}
#header #topVisual{
  background-size: 100%;
  height:100%;
  box-shadow: 0 5px 1px -3px #cececf;
  padding-bottom: 9px;
}

@media (max-width: 750px) {
  #header #topVisual .mainTxt {
    display: inline-block;
    margin-top: 12px;
  }
}
#header #topVisual .mainTxt {
  padding-top: 13px;
  height:100%;
  display: flex;
  align-items: flex-end;
  text-align: center;
  margin: auto;
}
#header #topVisual .loginHead {
  padding-left: 115px;
}

#header #topVisual .mainTxt h1 {
  margin: 0 auto;
  height:100%;
}

#header #topVisual .mainTxt h1 a{
  color: #333;
  display: flex;
  align-items: flex-end;
  margin: auto;
}

@media only screen and (max-width:1280px) {
  #header #topVisual .mainTxt {
    right: auto;
    float: none;
    padding-left: 0px;
    display: block;
  }
}
@media only screen and (max-width: 751px){
  #header #topVisual .mainTxt h1{
    padding-top: 7px;
    padding-left: 0px;
  }
}

@media (max-width: 750px) {
  #header #topVisual .mainTxt h1 img {
    width: 136px;
    max-width: 100%;
    margin-bottom: 2px;
  }
}
@media (min-width: 751px) and (max-width: 1200px) {
  #header #topVisual .mainTxt h1  img {
    width: 18.4027777778vw;
  }
}
@media (min-width: 1201px) and (max-width: 1920px) {
  #header #topVisual .mainTxt h1  img {
    width: 198.75px;
  }
}

#header #topVisual .mainTxt h1 span {
  font-size: 20px;
  color: #335477;
  font-weight: bold;
  display: block;
  margin-left: 7px;
  line-height: 1;
  margin-bottom: 13px;
  white-space: nowrap;
}
@media (max-width: 750px) {
  #header #topVisual .mainTxt h1  span {
    font-size: 10px;
    margin-left: 5px;
    margin-bottom: 0;
  }
}
@media (min-width: 751px) and (max-width: 1200px) {
  #header #topVisual .mainTxt h1  span {
    font-size: 1.3888888889vw;
    margin-bottom: 0.9027777778vw;
  }
}
@media (min-width: 1201px) and (max-width: 1920px) {
  #header #topVisual .mainTxt h1  span {
    margin-bottom: 3.75px;
  }
}


#header .btnBlock {
    margin-top: 8px;
}
#header a.contact-btn {
    background: #0064B1 0% 0% no-repeat padding-box;
    border: 1px solid #E0E0E0;
    border-radius: 21px;
    opacity: 1;
    width: 144px;
    text-align: center;
    font-size: 1.6rem;
    color: #fff;
    font-weight: bold;
    padding: 7px;
    position: relative;
    display: inline-block;
    overflow: hidden;
    margin-right: 15px;
}
#header a.contact-btn:hover {
    text-decoration: none;
    color: #fff;
    box-shadow: none;
    -webkit-transform: translateY(2.5px);
}

@media (max-width: 750px) {
  #header a.contact-btn,
  #header a.list-btn {
    margin-right: 2px;
  }
}

#header a.login-btn {
    background: #F6F6F6 0% 0% no-repeat padding-box;
    border: 1px solid #E0E0E0;
    border-radius: 21px;
    opacity: 1;
    width: 114px;
    text-align: center;
    font-size: 1.6rem;
    color: #333333;
    font-weight: bold;
    padding: 7px;
    position: relative;
    display: inline-block;
    overflow: hidden;
}
#header a.login-btn:hover {
    text-decoration: none;
    color: #333333;
    box-shadow: none;
    -webkit-transform: translateY(2.5px);
}
#header a.list-btn {
    background: #383081 0% 0% no-repeat padding-box;
    border: 1px solid #E0E0E0;
    border-radius: 21px;
    opacity: 1;
    width: 170px;
    text-align: center;
    font-size: 1.6rem;
    color: #fff;
    font-weight: bold;
    padding: 7px;
    position: relative;
    display: inline-block;
    overflow: hidden;
    margin-right: 15px;
}
#header a.list-btn:hover {
    text-decoration: none;
    color: #fff;
    box-shadow: none;
    -webkit-transform: translateY(2.5px);
}

@media (max-width: 750px) {
    #header .btnBlock {
        float: right;
        margin-top: 12px;
        border-radius: 15px;
        line-height: 30px;
        height: 30px;
    }
  #header a.login-btn,
  #header a.list-btn,
  #header a.contact-btn {
     font-size: 0.8rem;
     width: 80px;
     padding: 0;
  }
}
@media (min-width: 1201px) and (max-width: 1920px) {
  #header .btnBlock {
        font-size: 15px;
  }
}
手順2:アーカイブ詳細ブロックを作成
ウェビナー 一覧作成時に、レコードアイテムブロックが自動生成されます。
自動生成されたブロックは、任意の識別名がついているので、使用したい名称に変更しています。
アーカイブ詳細にもデザインをあてるため下記のようにHTMLおよびCSSを標準ソースより修正しています。

HTML
<div class="backBtnBox">
  <a th:if="${record != null}" th:href="|${pages['p0xx']?.path ?: '/404'}|" class="backBtn">戻る</a>
</div>
<div class="sp-record-item-container" th:if="${record != null}"> 
  <!--/* メインビジュアル(mainVisual) */-->
  <div class="webinarDetailBox">
    <div class="contantMainVideo">
      <sp:record-item-field name="f0xx"></sp:record-item-field>
      <iframe class="imgBox"  width="900" height="540" th:src="${record['f0xx']}" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
    </div>
    <div class="mainContents">
      <!--/* セミナータイトル (title) */--> 
      <sp:record-item-field name="f0xx"></sp:record-item-field> 
      <h3 class="titleTxt" th:text="${record['f03']}">Example</h3>
      <!--/* 開催日 (date) */--> 
      <sp:record-item-field name="f0xx"></sp:record-item-field> 
      <sp:record-item-field name="f0xx"></sp:record-item-field> 
      <sp:record-item-field name="f0xx"></sp:record-item-field> 
      <div class="sp-record-item-data">
        <span class="sp-record-item-embedded" th:with="week=${ { '', '日', '月', '火', '水', '木', '金', '土' } }" th:text="${record['f0xx'] != null && record['f0xx'] != null && record['f0xx'] != null} ? '開催日:'+${record['f0xx'].format('yyyy/MM/dd')}+ |(${week[record['f0xx'].format('e')]})|+ ${record['f0xx'].format('HH:mm')}+' ~ '+${record['f0xx'].format('HH:mm')} : ''">2000/01/01 00:00</span>
      </div>       
      <!--/* ウェビナー概要(text) */-->
      <p class="seminarTxt"><span style="color:#999999;">開催概要</span><br>
        <sp:record-item-field name="f0xx"></sp:record-item-field>
        <span class="sp-record-item-embedded" th:if="${record['f0xx'] != null}">
          <th:block th:each="line, stat : ${record['f0xx'].lines}">
            <th:block th:text="${line}"/>
            <br th:unless="${stat.last}">
          </th:block>
        </span>
      </p>
    </div>
  </div>
</div>

<div class="sp-record-item-container" th:if="${record == null}"> 
  <div class="sp-record-item-no-item">
    データが見つかりません<br /><br />
    <div class="backBtnBok">
      <a th:href="|${pages['p0xx']?.path ?: '/404'}|" class="backBtn">戻る</a>
    </div>
  </div> 
</div>
CSS
.webinarDetailBox{
  background: #FFFFFF 0% 0% no-repeat padding-box;
  border: 1px solid #707070;
  opacity: 1;
}
.contantMainVisual .imgBox{
  text-align:center;
  width: 100%;
  height: 100%;
  border: solid;
  border-color: #a6a6a6;
  border-width: 1px;
}
.cautionBox{
  text-align: center;
  padding: 25px 0;
  font-size: 22px;
  font-weight: bold;
}

a.btnJoin{
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 25px auto 20px;
  font-size: 16px;
  width: 208px;
  height: 54px;
  line-height: 37.5px;
  text-align: center;
  color: #FFF;
  font-weight: bold;
  background: #335477 0% 0% no-repeat padding-box;
  border-radius: 4px;
  opacity: 1;
}
a.btnCancel{
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 25px auto 20px;
  font-size: 16px;
  width: 208px;
  height: 54px;
  line-height: 37.5px;
  text-align: center;
  color: #FFF;
  font-weight: bold;
  background: #4f5861 0% 0% no-repeat padding-box;
  border-radius: 4px;
  opacity: 1;
}
p.btnPre{
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 25px auto 20px;
  font-size: 16px;
  width: 208px;
  height: 54px;
  line-height: 37.5px;
  text-align: center;
  color: #FFF;
  font-weight: bold;
  background: #cdcdcd 0% 0% no-repeat padding-box;
  border-radius: 4px;
  opacity: 1;
}
p.cautionTxt{
  text-align:center;
  font-size: 12px;
}
div.backBtnBox{
  margin:5px 0px;
}

div.backBtnBox a.backBtn{
  text-decoration: underline;
  color: #0064B1;
  text-underline-offset: 0.15em;
}  
.sp-record-item-container .mainContents{
  padding:20px 40px;
}
.sp-record-item-container .mainContents h3.titleTxt{
  font-size:28px
}

.sp-record-item-container .mainContents span{
  font-size:16px;
}
  
  .sp-record-list-container .sp-record-list-no-records {
    margin:6.25rem auto;
    text-align:center;
    color:#808080;
  }
  
  .sp-record-list-pagination {
    display:-webkit-box;
    display:-ms-flexbox;
    display:flex;
    -webkit-box-pack:justify;
    -ms-flex-pack:justify;
    justify-content:space-between;
    -webkit-box-align:center;
    -ms-flex-align:center;
    align-items:center;
  }
  
  .sp-record-list-pagination .sp-record-list-pagination-left,
  .sp-record-list-pagination .sp-record-list-pagination-center,
  .sp-record-list-pagination .sp-record-list-pagination-right {
    display:-webkit-box;
    display:-ms-flexbox;
    display:flex;
    -webkit-box-align:center;
    -ms-flex-align:center;
    align-items:center;
  }
  
  .sp-record-list-pagination .sp-record-list-pagination-left>*,
  .sp-record-list-pagination .sp-record-list-pagination-center>*,
  .sp-record-list-pagination .sp-record-list-pagination-right>* { margin:0 .5rem; }
  
  .sp-record-list-pagination .sp-record-list-pagination-left {
    -webkit-box-pack:start;
    -ms-flex-pack:start;
    justify-content:flex-start;
  }
  
  .sp-record-list-pagination .sp-record-list-pagination-center {
    -webkit-box-pack:center;
    -ms-flex-pack:center;
    justify-content:center;
  }
  
  .sp-record-list-pagination .sp-record-list-pagination-right {
    -webkit-box-pack:end;
    -ms-flex-pack:end;
    justify-content:flex-end;
  }
  
  .sp-record-list-pagination .sp-form-control {
    -webkit-appearance:none;
    -moz-appearance:none;
    appearance:none;
    font-family:inherit;
    font-size:1rem;
    line-height:1.5;
    padding:.3rem .7rem;
    color:#333333;
    -webkit-box-sizing:border-box;
    box-sizing:border-box;
    width:100%;
    margin-bottom:0.2rem;
    border:1px solid #dddddd;
    border-radius:.25rem;
  }
  
  .sp-record-list-pagination .sp-form-inline .sp-form-control {
    display:inline-block;
    width:auto;
    vertical-align:middle;
  }
  
  .sp-record-list-pagination select.sp-form-control,
  .sp-record-list-pagination option.sp-form-control {
    -webkit-appearance:none;
    -moz-appearance:none;
    appearance:none;
    padding-right:1.5rem;
  }
  
  .sp-record-list-pagination select.sp-form-control::-ms-expand { display:none; }
  
  .sp-record-list-pagination .sp-form-dropdown { position:relative; }
  
  .sp-record-list-pagination .sp-form-dropdown-inline {
    position:relative;
    display:inline-block;
  }
  
  .sp-record-list-pagination .sp-form-dropdown-icon {
    display:block;
    position:absolute;
    top:1rem;
    right:.5rem;
    line-height:0;
    pointer-events:none;
  }
  
  .sp-record-list-pagination .sp-form-dropdown-icon:after {
    content:"";
    display:block;
    border-top:.333rem solid #888888;
    border-right:.333rem solid transparent;
    border-left:.333rem solid transparent;
  }
  
  .sp-record-list-pagination ul.sp-page-navs {
    display:-webkit-box;
    display:-ms-flexbox;
    display:flex;
    padding-left:0;
    list-style:none;
  }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item {
    line-height:1.25rem;
    text-align:center;
    -webkit-user-select:none;
    -moz-user-select:none;
    -ms-user-select:none;
    user-select:none;
    white-space:nowrap;
  }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item a,
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item span {
    display:inline-block;
    margin:0 0.2rem;
    padding:.375rem .75rem;
    border-radius:.25rem;
    border:1px solid #dddddd;
    color:#333333;
    padding: 8px;
  }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item a .fa,
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item span .fa {
    font-size: 1.2em;
    width: 1rem;
    line-height: 0;
  }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item a { text-decoration:none; }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item a:hover { background-color:rgba(0,0,0,0.075); }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item span {
    background-color:rgba(0,0,0,0.075);
    color:#DBDBDB;
  }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item.sp-page-nav-current span {
    background-color:#DBDBDB;
    border-color:#DBDBDB;
    color:#ffffff;
    padding: 8px;
  }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-more {
    line-height:1rem;
    text-align:center;
    margin:0 .2rem;
    padding:.375rem .3rem;
  }
  .wrapper .contents .sp-record-item-container h3.title {
    position: relative;
    padding-bottom: 0;
    text-align: center;
    color: #333;
    font-size: 1.5em;
}
.wrapper .contents .sp-record-item-container .sp-form-message{
  text-align: center;
}
.wrapper .contents .sp-record-item-container .sp-form-message a{
  color: #217599;
}
.sp-record-item-container {
  color:#333333;
  background-color:#ffffff;
}

.sp-record-item-container .sp-record-item-parts {
  margin-bottom:0.5rem;
  padding-bottom:0.5rem;
}

.sp-record-item-container .sp-record-item-field {
  display:-webkit-box;
  display:-ms-flexbox;
  display:flex;
  -webkit-box-orient:vertical;
  -webkit-box-direction:normal;
  -ms-flex-direction:column;
  flex-direction:column;
  border-bottom:1px solid #dddddd;
}

.sp-record-item-container .sp-record-item-field>.sp-record-item-label {
  font-size:2.15rem;
  font-weight:bold;
  padding:.25rem .5rem;
  word-break:break-all;
  -webkit-box-sizing:border-box;
  box-sizing:border-box;
  color:#555555;
}

.sp-record-item-container .sp-record-item-field>.sp-record-item-data {
  display:-webkit-box;
  display:-ms-flexbox;
  display:flex;
  -webkit-box-orient:vertical;
  -webkit-box-direction:normal;
  -ms-flex-direction:column;
  flex-direction:column;
  padding:1rem;
  -webkit-box-sizing:border-box;
  box-sizing:border-box;
}

.sp-record-item-container .sp-record-item-field .sp-record-item-embedded { padding-left:.25rem; }

.sp-record-item-container .sp-record-item-data-selection {
  display:block;
  margin:.25rem 0;
  padding:.5rem .8rem .5rem 0;
  border-radius:0.25rem;
}

.sp-record-item-container .sp-html-parts p { margin:0; }

.sp-record-item-container .sp-record-item-no-item {
  margin:6.25rem auto;
  text-align:center;
  color:#808080;
}

.sp-record-item-field:first-child,
.sp-record-item-field-ie:first-child { padding-top:0 !important; }



.sp-file-info {
  padding-top:1em;
  padding-bottom:1em;
  line-height:1.5;
}

.sp-file-info:last-child { padding-bottom:0; }

.sp-form-file-bold-link {
  text-decoration:none !important;
  color:#3b7e9b;
  cursor:pointer;
  font-weight:bold;
}

.sp-form-file-size-label { color:#6c757d; }

.sp-text-truncate {
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
}

@media (min-width:768px) {
  .sp-record-item-container .sp-record-item-container {
    font-size:initial;
    padding:3rem;
    margin:0 auto;
    width:80.0%;
  }

  .sp-record-item-container .sp-record-item-field {
    -webkit-box-orient:horizontal;
    -webkit-box-direction:normal;
    -ms-flex-flow:row nowrap;
    flex-flow:row nowrap;
  }

  .sp-record-item-container .sp-record-item-field>.sp-record-item-label {
    font-size:2rem;
    width:30%;
    padding:1rem;
  }

  .sp-record-item-container .sp-record-item-field>.sp-record-item-data {
    font-size:2rem;
    width:70%;
  }

  .sp-record-item-container .sp-record-item-field .sp-record-item-embedded { font-size:2rem; }

  .sp-record-item-container .sp-record-item-data-selection {
    font-size:.9rem;
    margin:0 1rem 0 0;
    padding:0;
  }

  .sp-record-item-container .sp-record-item-data-selection-vertical {
    display:-webkit-box;
    display:-ms-flexbox;
    display:flex;
    -webkit-box-orient:vertical;
    -webkit-box-direction:normal;
    -ms-flex-direction:column;
    flex-direction:column;
  }
  .sp-record-item-container .sp-record-item-data-selection-horizontal {
    display:-webkit-box;
    display:-ms-flexbox;
    display:flex;
    -webkit-box-orient:horizontal;
    -webkit-box-direction:normal;
    -ms-flex-flow:row wrap;
    flex-flow:row wrap;
  }
}
手順3:アーカイブページを作成
認証エリア内に「認証あり」でアーカイブページ詳細用のページを作成します。
デザインをあてるため下記のようにHTMLおよびCSSを標準ソースより修正しています。

HTML
<div class="wrapper">
    <!-- ヘッダ-->
    <sp:block name="fcb0xx"></sp:block>
    <div class="contents inner-1200 inner-sp">
        <div class="webinarDetail">
            <sp:block name="rib0xx"></sp:block>
        </div>
    </div>
</div>
head に関しては全ページ共通となります。
head
<title th:text="${page.title}"></title>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v6.1.1/css/all.css">
<!-- 	Font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=M+PLUS+1:wght@500;700&display=swap" rel="stylesheet">
<!-- 	/Font -->
<!-- ページ共通のCSS -->
<link rel="stylesheet" media="all" href="/_media/webinar/pages.css">
<!-- ページ共通のCSS -->
設定が完了しましたら、アーカイブ一覧のリンク先を作成したページに変更してください。
手順4:申込フォーム作成
申込ページの作成を行い、登録フォームの作成を行います。
申込ページは、認証エリア内に作成するため、「認証あり」で設定してください。
デザインは、ブロックのCSSに会員登録で使用したコピペCSS 「シンプルモダン」と同一のCSSをコピペします。
登録フォームでは、メールアドレスをのみ表示させ、必要データは自動登録で設定します。
入力項目がなしでは登録フォームを保存することができないため、NULL更新用の定義タグを設定します。

HTML
<sp:input-field name="f0xx"></sp:input-field>
申込フォームのメールアクションに③申込完了メール、④申込通知メールを設定ください。
▼メールアクション
配信名 配信条件・配信先 配信タイミング
③申込完了メール 配信指定方法:レコード(メールアドレス) 常時配信
④申込通知メール 配信指定方法:レコード(ウェビナーマスタDB参照 > 登壇部署メールアドレス) 常時配信

申込フォームでは、自動登録の設定を行っております。
▼自動登録 設定
フィールド 値タイプ
会員DB参照 引用(認証レコード値) 引用元: 【デモ】ウェビナーアプリ( 会員DB )
ウェビナーDB参照 引用(任意レコード値) 引用元: ウェビナーマスタDB
ウェビナーID 固定 webinar_id
※登録トリガにてIDに変更されます。
会員ID 引用(認証レコード値) 引用元: 【デモ】ウェビナーアプリ( 会員DB ) 会員ID

申込画面で申込済みかを判定するためにPHPでチェックしています。

PHP
<?php
//------------------------------
// 設定値用モジュール
//------------------------------
define("API_URL", "https://api.spiral-platform.com/v1");
define("API_KEY", $SPIRAL->getEnvValue("API_KEY"));
define("API_ROLE_ID", $SPIRAL->getEnvValue("webinar_ROLE_ID"));

//------------------------------
// 設定値用モジュール
//------------------------------
$commonBase = CommonBase::getInstance();
// ステップのセット
$registForm = $SPIRAL->getRegistrationForm("webinarApp");
$SPIRAL->setTHValue("step", $registForm->getStep());
// パラメータの取得
if($SPIRAL->getParam("record")){
	$SPIRAL->setTHValue("paramError", true);
	$param = explode(".", $SPIRAL->getParam("record"));
	$SPIRAL->setTHValue("recordID", $param[1]);
	// ページ情報セット
	$SPIRAL->setTHValue("login", true);
	$SPIRAL->setTHValue("appPage", true);
	// 入力画面での処理
	$SPIRAL->setTHValue("app", false);
	if($registForm->getStep() == 1){
		$query = urlencode($param[1].':'.$SPIRAL->getAuthRecordByFieldId("_id"));
		$appCheck = $commonBase->apiCurlAction("GET","/apps/".$SPIRAL->getEnvValue("webinar_APP_ID")."/dbs/".$SPIRAL->getEnvValue("webinarDB_ID")."/records?where=@originalKey='".$query."'");
		if(isset($appCheck['items'][0]['_id'])){
			$SPIRAL->setTHValue("app", true);
		}
	}
}else{
	$SPIRAL->setTHValue("login", false);
	$SPIRAL->setTHValue("appPage", false);
	$SPIRAL->setTHValue("paramError", false);
}


//------------------------------
// 共通用モジュール
//------------------------------

class CommonBase
{
	/**
	 * シングルトンインスタンス
	 * @var UserManager
	 */
	protected static $singleton;
    

	public function __construct()
	{
		if (self::$singleton) {
			throw new Exception('must be singleton');
		}
		self::$singleton = $this;
	}

	/**
	 * シングルトンインスタンスを返す
	 * @return UserManager
	 */
	public static function getInstance()
	{
		if (!self::$singleton) {
			return new CommonBase();
		} else {
			return self::$singleton;
		}
	}

    
	/**
	 * V2用 API送信ロジック
	 * @return Result
	 */
	function apiCurlAction($method, $addUrlPass, $data = null)
	{
        
		$header = array(
			"Authorization:Bearer " . API_KEY,
			"Content-Type:application/json",
			"X-Spiral-Api-Version: 1.1",
		);
		if(API_ROLE_ID){
			$header = array_merge($header,array("X-Spiral-App-Role: ".API_ROLE_ID));
		}

		// curl
		$curl = curl_init();
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($curl, CURLOPT_URL, API_URL . $addUrlPass);
		curl_setopt($curl, CURLOPT_HTTPHEADER, $header);

		if ($method == "POST") {
			curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data));
			curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
		}
		if ($method == "PATCH") {
			curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data));
			curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
		}
		if ($method == "DELETE") {
			curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
		}
		if ($method == "GET") {
			curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
		}
		$response = curl_exec($curl);
		if (curl_errno($curl)) echo curl_error($curl);
		curl_close($curl);

		return json_decode($response, true);
	}
}

また、レコードIDが不正ない場合、申込ブロックを表示させいないための JavaScript 処理を入れております。

JavaScript
function firstscript() {
    const record = document.getElementById('webinarRecord');
    if(record.dataset.record == 'false'){
        document.getElementById("webinarApp").style.display = 'none';
    }
} 
window.onload = firstscript;
ポイント①
自動登録で参照フィールドを登録

ver.2.22 にて参照フィールドを自動登録で使用することができます。
申し込み時に、会員DBとウェビナーDBのIDを参照フィールドに追加しています。
参照フィールドは、登録フォームブロックのソース設定のみの対応となるため、ご注意ください。
ポイント②
PHP環境設定でページ共通のキーを共有

APIキー や アプリID,DBIDなどは PHP環境設定 で管理することで、複数ページで値を使いまわすことができます。
デザインをあてるため下記のようにHTMLおよびCSSを標準ソースより修正しています。

HTML
<div class="wrapper">
    <!-- ヘッダ-->
    <sp:block name="fcb0xx"></sp:block>
    <div class="contents inner-1200 inner-sp">
        <div class="webinarDetail" th:if="${cp.result.isSuccess}">
            <div class="appArea">
                <sp:block name="ifb0xx"></sp:block>
            </div>            
            <!-- 入力時のみ表示-->
            <th:block th:if="${cp.result.value['step']} == 1">
                <sp:block name="rib0xx"></sp:block>
            </th:block>
        </div>
        <div th:if="${!cp.result.isSuccess}">
            <p th:text="${cp.result.errorMessage}">error message</p>
        </div>
    </div>
</div>
head に関しては全ページ共通となります。

head
<title th:text="${page.title}"></title>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v6.1.1/css/all.css">
<!-- 	Font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=M+PLUS+1:wght@500;700&display=swap" rel="stylesheet">
<!-- 	/Font -->
<!-- ページ共通のCSS -->
<link rel="stylesheet" media="all" href="/_media/webinar/pages.css">
<!-- ページ共通のCSS -->
手順4:ログイン画面のデザイン反映
認証エリアを作成するとログインページ・ログインブロックが自動生成されます。
デザインは、ブロックのCSSに会員登録で使用したコピペCSS 「シンプルモダン」と同一のCSSをコピペします。
手順5:申込済一覧作成
ウェビナー申込DBのレコードリストを作成します。
自身の申込済の情報を絞り込んで表示させるには、レコード公開範囲を設定する必要があります。
エリア認証時公開のみ表示を行い、ログインフィルタにて会員DBと連携で設定します。
レコード公開範囲の設定が完了しましたら、申込済み一覧となるレコードリストを作成を作成します。
申込済み一覧では検索機能を使用しないので、レコードリストブロックを選択しウェビナーDB のレコードリストを作成します。
タイル型で表示させるため下記のようにHTMLおよびCSSを標準ソースより修正しています。

head
<div class="sp-record-list-container">
    <div class="sp-record-list-parts">
        <div class="containerBox">
            <div class="webinar" th:each="record, stat : ${pageRecords}">
                <sp:record-data-field name="f0xx"></sp:record-data-field>
                <div th:class="${record['f0xx'].format('yyyy-MM-dd') lt cp.result.value['newDate'] } ? 'closeWebinar' : ''">
                    <div class="textBox">
                        <!--/* 開催日 (date) */-->
                        <sp:record-data-field name="f0xx"></sp:record-data-field>
                        <sp:record-data-field name="f0xx"></sp:record-data-field>
                        <p class="dateTxt" th:with="week=${ { '', '日', '月', '火', '水', '木', '金', '土' } }" th:text="${record['f0xx'] != null && record['f0xx'] != null && record['f0xx'] != null} ? '開催日:'+${record['f0xx'].format('yyyy/MM/dd')}+ |(${week[record['f0xx'].format('e')]})|+ ${record['f0xx'].format('HH:mm')}+' ~ '+${record['f0xx'].format('HH:mm')} : ''">2000/01/01 </p>
                        <!--/* セミナータイトル (title) */-->
                        <sp:record-data-field name="f0xx"></sp:record-data-field>
                        <p class="titleTxt" th:text="${record['f0xx']}">Example</p>
                        <sp:record-data-field name="f_id"></sp:record-data-field>
                        <a th:if="${record['f0xx'].format('yyyy-MM-dd') ge cp.result.value['newDate']}" th:href="|${pages['p0xxx']?.path ?: '/404'}?${record.linkParam}|" class="webinarLink">詳細を見る</a>
                        <!--/* アンケート回答フラグ (anserFlg) */-->
                        <sp:record-data-field name="f0xx"></sp:record-data-field>
                        <a th:if="${record['f0xx'].format('yyyy-MM-dd') lt cp.result.value['newDate'] && record['f0xx'].id ne 2}" th:href="|${pages['p0xxx']?.path ?: '/404'}?${record.linkParam}|" class="questionLink">アンケート回答</a>
                    </div>

                </div>
            </div>
        </div>
        <div class="sp-record-list-no-records" th:if="${recordList.totalRecordCount == 0}">
            申込み済みのウェビナーは、ありません。
        </div>
    </div>
</div>
ポイント①
日時やステータスで一覧のデザイン出し分け

Thymeleaf でアクセス日と開設日を比較して class の付け替えや ボタンの出し分けを行っています。 アクセス日は、PHP からデータを渡しているので、下記のPHPを追加しています。
$SPIRAL->setTHValue("newDate",date("Y-m-d"));
手順6:申込済み詳細ページ作成
申込済みウェビナーの詳細を表示されるページを作成します。
詳細部分のデザインは、ウェビナー詳細画面と同一ですが、
上部にボタンを設置し、開催日・終了時刻によっての出しわけを実施しています。
HTMLおよびCSSは、下記になります。
HTML
<th:block th:if="${cp.result.isSuccess}">
  <div class="backBtnBox" th:if="!${cp.result.value['cancel']}">
    <a th:if="${record != null}" th:href="|${pages['p0xxx']?.path ?: '/404'}|" class="backBtn">戻る</a>
  </div>
  <div class="cautionBox" th:if="${cp.result.value['cancel']}">
    以下のセミナーをキャンセルします。
  </div>

  <div class="sp-record-item-container" th:if="${record != null}"> 
    <!--/* メインビジュアル(mainVisual) */-->
    <div class="webinarDetailBox">
      <!--/* ボタン出しわけ。 */--> 
      <sp:record-item-field name="f0xx.x"></sp:record-item-field> 
      <sp:record-item-field name="f0xx.x"></sp:record-item-field> 
      <sp:record-item-field name="f0xx.x"></sp:record-item-field> 
      <th:block th:if="${cp.result.value['cancel'] eq false}">
        <th:block th:if="${cp.result.value['today'] eq record['f0xx']['f0xx'].format('yyyy-MM-dd')}">
            <th:block th:if="${cp.result.value['nowTime'] lt record['f0xx']['f0xx'].format('HH:mm:ss')}">
              <sp:record-item-field name="f0xx.x"></sp:record-item-field> 
              <a target="_blank" th:href="${record['f0xx']['f0xx']}" class="btnJoin mb00">参加</a>
              <p class="cautionTxt">時間になりましたら、上記よりご参加ください。</p>
            </th:block>
            <th:block th:unless="${cp.result.value['nowTime'] lt record['f0xx']['f0xx'].format('HH:mm:ss')}">
              <p class="btnPre mb00">終了</p>
              <p class="cautionTxt">ウェビナーは、終了いたしました。</p>
            </th:block>
        </th:block>
        <th:block th:if="${cp.result.value['today'] lt record['f0xx']['f0xx'].format('yyyy-MM-dd')}">
            <a th:href="|${pages['p0xx']?.path ?: '/404'}?${record.linkParam}|" class="btnCancel mb00">キャンセル</a>
            <p class="cautionTxt">前日までキャンセル可能となります。</p>
            <p class="cautionTxt">開催日になりましたら、参加用のボタンが表示されます。</p>
        </th:block>
        <th:block th:if="${cp.result.value['today'] gt record['f0xx']['f0xx'].format('yyyy-MM-dd')}">
            <p class="btnPre mb00">終了</p>
            <p class="cautionTxt">ウェビナーは、終了いたしました。</p>
        </th:block>
      </th:block>

      <div class="mainContents">
        <!--/* セミナータイトル (title) */--> 
        <sp:record-item-field name="f0xx.xx"></sp:record-item-field> 
        <h3 class="titleTxt" th:text="${record['f0xx']['f0xx'] != null} ? (${record['f0xx']['f0xx']} ?: '値なし')">Example</h3>
        <!--/* 開催日 (date) */--> 
        <div class="sp-record-item-data">
          <span class="sp-record-item-embedded" th:with="week=${ { '', '日', '月', '火', '水', '木', '金', '土' } }" th:text="${record['f0xx']['f0xx'] != null} ? '開催日:'+${record['f0xx']['f0xx'].format('yyyy/MM/dd')}+ |(${week[record['f0xx']['f0xx'].format('e')]})| : ''">2000/01/01 </span>
          <span class="sp-record-item-embedded" th:text="${record['f0xx']['f0xx'] != null && record['f0xx']['f0xx'] != null} ? ${record['f0xx']['f0xx'].format('HH:mm')}+' ~ '+${record['f0xx']['f0xx'].format('HH:mm')} : ''">12:00:00</span>
        </div> 
        <!--/* セミナー概要(text) */-->
        <p class="seminarTxt"><span style="color:#999999;">開催概要</span><br>
          <sp:record-item-field name="f0xx.x"></sp:record-item-field>
          <span class="sp-record-item-embedded" th:if="${record['f0xx']['f0xx'] != null}">
            <th:block th:each="line, stat : ${record['f0xx']['f0xx'].lines}">
              <th:block th:text="${line}"/>
              <br th:unless="${stat.last}">
            </th:block>
          </span>
        </p>
      </div>

    </div>
    <div class="backBtnBox" th:if="${cp.result.value['cancel']}">
      <a th:if="${record != null}" th:href="|${pages['p0xxx']?.path ?: '/404'}|" class="backBtn">戻る</a>
    </div>
  </div>

  <div class="sp-record-item-container" th:if="${record == null}"> 
    <div class="sp-record-item-no-item">
      データが見つかりません<br /><br />
      <div class="backBtnBok">
        <a th:href="|${pages['p0xxx']?.path ?: '/404'}|" class="backBtn">戻る</a>
      </div>
    </div> 
  </div>
</th:block>

<th:block th:if="${!cp.result.isSuccess}">
    <p th:text="${cp.result.errorMessage}">error message</p>
</th:block>
CSS
.webinarDetailBox{
  background: #FFFFFF 0% 0% no-repeat padding-box;
  border: 1px solid #707070;
  opacity: 1;
}
.contantMainVisual .imgBox{
  text-align:center;
  width: 100%;
  height: 100%;
  border: solid;
  border-color: #a6a6a6;
  border-width: 1px;
}
.cautionBox{
  text-align: center;
  padding: 25px 0;
  font-size: 22px;
  font-weight: bold;
}

a.btnJoin{
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 25px auto 20px;
  font-size: 16px;
  width: 208px;
  height: 54px;
  line-height: 37.5px;
  text-align: center;
  color: #FFF;
  font-weight: bold;
  background: #335477 0% 0% no-repeat padding-box;
  border-radius: 4px;
  opacity: 1;
}
a.btnCancel{
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 25px auto 20px;
  font-size: 16px;
  width: 208px;
  height: 54px;
  line-height: 37.5px;
  text-align: center;
  color: #FFF;
  font-weight: bold;
  background: #4f5861 0% 0% no-repeat padding-box;
  border-radius: 4px;
  opacity: 1;
}
p.btnPre{
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 25px auto 20px;
  font-size: 16px;
  width: 208px;
  height: 54px;
  line-height: 37.5px;
  text-align: center;
  color: #FFF;
  font-weight: bold;
  background: #cdcdcd 0% 0% no-repeat padding-box;
  border-radius: 4px;
  opacity: 1;
}
p.cautionTxt{
  text-align:center;
  font-size: 12px;
}
div.backBtnBox{
  margin:5px 0px;
}

div.backBtnBox a.backBtn{
  text-decoration: underline;
  color: #0064B1;
  text-underline-offset: 0.15em;
}  
.sp-record-item-container .mainContents{
  padding:20px 40px;
}
.sp-record-item-container .mainContents h3.titleTxt{
  font-size:28px
}

.sp-record-item-container .mainContents span{
  font-size:16px;
}
  
  .sp-record-list-container .sp-record-list-no-records {
    margin:6.25rem auto;
    text-align:center;
    color:#808080;
  }
  
  .sp-record-list-pagination {
    display:-webkit-box;
    display:-ms-flexbox;
    display:flex;
    -webkit-box-pack:justify;
    -ms-flex-pack:justify;
    justify-content:space-between;
    -webkit-box-align:center;
    -ms-flex-align:center;
    align-items:center;
  }
  
  .sp-record-list-pagination .sp-record-list-pagination-left,
  .sp-record-list-pagination .sp-record-list-pagination-center,
  .sp-record-list-pagination .sp-record-list-pagination-right {
    display:-webkit-box;
    display:-ms-flexbox;
    display:flex;
    -webkit-box-align:center;
    -ms-flex-align:center;
    align-items:center;
  }
  
  .sp-record-list-pagination .sp-record-list-pagination-left>*,
  .sp-record-list-pagination .sp-record-list-pagination-center>*,
  .sp-record-list-pagination .sp-record-list-pagination-right>* { margin:0 .5rem; }
  
  .sp-record-list-pagination .sp-record-list-pagination-left {
    -webkit-box-pack:start;
    -ms-flex-pack:start;
    justify-content:flex-start;
  }
  
  .sp-record-list-pagination .sp-record-list-pagination-center {
    -webkit-box-pack:center;
    -ms-flex-pack:center;
    justify-content:center;
  }
  
  .sp-record-list-pagination .sp-record-list-pagination-right {
    -webkit-box-pack:end;
    -ms-flex-pack:end;
    justify-content:flex-end;
  }
  
  .sp-record-list-pagination .sp-form-control {
    -webkit-appearance:none;
    -moz-appearance:none;
    appearance:none;
    font-family:inherit;
    font-size:1rem;
    line-height:1.5;
    padding:.3rem .7rem;
    color:#333333;
    -webkit-box-sizing:border-box;
    box-sizing:border-box;
    width:100%;
    margin-bottom:0.2rem;
    border:1px solid #dddddd;
    border-radius:.25rem;
  }
  
  .sp-record-list-pagination .sp-form-inline .sp-form-control {
    display:inline-block;
    width:auto;
    vertical-align:middle;
  }
  
  .sp-record-list-pagination select.sp-form-control,
  .sp-record-list-pagination option.sp-form-control {
    -webkit-appearance:none;
    -moz-appearance:none;
    appearance:none;
    padding-right:1.5rem;
  }
  
  .sp-record-list-pagination select.sp-form-control::-ms-expand { display:none; }
  
  .sp-record-list-pagination .sp-form-dropdown { position:relative; }
  
  .sp-record-list-pagination .sp-form-dropdown-inline {
    position:relative;
    display:inline-block;
  }
  
  .sp-record-list-pagination .sp-form-dropdown-icon {
    display:block;
    position:absolute;
    top:1rem;
    right:.5rem;
    line-height:0;
    pointer-events:none;
  }
  
  .sp-record-list-pagination .sp-form-dropdown-icon:after {
    content:"";
    display:block;
    border-top:.333rem solid #888888;
    border-right:.333rem solid transparent;
    border-left:.333rem solid transparent;
  }
  
  .sp-record-list-pagination ul.sp-page-navs {
    display:-webkit-box;
    display:-ms-flexbox;
    display:flex;
    padding-left:0;
    list-style:none;
  }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item {
    line-height:1.25rem;
    text-align:center;
    -webkit-user-select:none;
    -moz-user-select:none;
    -ms-user-select:none;
    user-select:none;
    white-space:nowrap;
  }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item a,
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item span {
    display:inline-block;
    margin:0 0.2rem;
    padding:.375rem .75rem;
    border-radius:.25rem;
    border:1px solid #dddddd;
    color:#333333;
    padding: 8px;
  }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item a .fa,
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item span .fa {
    font-size: 1.2em;
    width: 1rem;
    line-height: 0;
  }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item a { text-decoration:none; }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item a:hover { background-color:rgba(0,0,0,0.075); }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item span {
    background-color:rgba(0,0,0,0.075);
    color:#DBDBDB;
  }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-item.sp-page-nav-current span {
    background-color:#DBDBDB;
    border-color:#DBDBDB;
    color:#ffffff;
    padding: 8px;
  }
  
  .sp-record-list-pagination ul.sp-page-navs li.sp-page-nav-more {
    line-height:1rem;
    text-align:center;
    margin:0 .2rem;
    padding:.375rem .3rem;
  }
  .wrapper .contents .sp-record-item-container h3.title {
    position: relative;
    padding-bottom: 0;
    text-align: center;
    color: #333;
    font-size: 1.5em;
}
.wrapper .contents .sp-record-item-container .sp-form-message{
  text-align: center;
}
.wrapper .contents .sp-record-item-container .sp-form-message a{
  color: #217599;
}
.sp-record-item-container {
  color:#333333;
  background-color:#ffffff;
}

.sp-record-item-container .sp-record-item-parts {
  margin-bottom:0.5rem;
  padding-bottom:0.5rem;
}

.sp-record-item-container .sp-record-item-field {
  display:-webkit-box;
  display:-ms-flexbox;
  display:flex;
  -webkit-box-orient:vertical;
  -webkit-box-direction:normal;
  -ms-flex-direction:column;
  flex-direction:column;
  border-bottom:1px solid #dddddd;
}

.sp-record-item-container .sp-record-item-field>.sp-record-item-label {
  font-size:2.15rem;
  font-weight:bold;
  padding:.25rem .5rem;
  word-break:break-all;
  -webkit-box-sizing:border-box;
  box-sizing:border-box;
  color:#555555;
}

.sp-record-item-container .sp-record-item-field>.sp-record-item-data {
  display:-webkit-box;
  display:-ms-flexbox;
  display:flex;
  -webkit-box-orient:vertical;
  -webkit-box-direction:normal;
  -ms-flex-direction:column;
  flex-direction:column;
  padding:1rem;
  -webkit-box-sizing:border-box;
  box-sizing:border-box;
}

.sp-record-item-container .sp-record-item-field .sp-record-item-embedded { padding-left:.25rem; }

.sp-record-item-container .sp-record-item-data-selection {
  display:block;
  margin:.25rem 0;
  padding:.5rem .8rem .5rem 0;
  border-radius:0.25rem;
}

.sp-record-item-container .sp-html-parts p { margin:0; }

.sp-record-item-container .sp-record-item-no-item {
  margin:6.25rem auto;
  text-align:center;
  color:#808080;
}

.sp-record-item-field:first-child,
.sp-record-item-field-ie:first-child { padding-top:0 !important; }



.sp-file-info {
  padding-top:1em;
  padding-bottom:1em;
  line-height:1.5;
}

.sp-file-info:last-child { padding-bottom:0; }

.sp-form-file-bold-link {
  text-decoration:none !important;
  color:#3b7e9b;
  cursor:pointer;
  font-weight:bold;
}

.sp-form-file-size-label { color:#6c757d; }

.sp-text-truncate {
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
}

@media (min-width:768px) {
  .sp-record-item-container .sp-record-item-container {
    font-size:initial;
    padding:3rem;
    margin:0 auto;
    width:80.0%;
  }

  .sp-record-item-container .sp-record-item-field {
    -webkit-box-orient:horizontal;
    -webkit-box-direction:normal;
    -ms-flex-flow:row nowrap;
    flex-flow:row nowrap;
  }

  .sp-record-item-container .sp-record-item-field>.sp-record-item-label {
    font-size:2rem;
    width:30%;
    padding:1rem;
  }

  .sp-record-item-container .sp-record-item-field>.sp-record-item-data {
    font-size:2rem;
    width:70%;
  }

  .sp-record-item-container .sp-record-item-field .sp-record-item-embedded { font-size:2rem; }

  .sp-record-item-container .sp-record-item-data-selection {
    font-size:.9rem;
    margin:0 1rem 0 0;
    padding:0;
  }

  .sp-record-item-container .sp-record-item-data-selection-vertical {
    display:-webkit-box;
    display:-ms-flexbox;
    display:flex;
    -webkit-box-orient:vertical;
    -webkit-box-direction:normal;
    -ms-flex-direction:column;
    flex-direction:column;
  }
  .sp-record-item-container .sp-record-item-data-selection-horizontal {
    display:-webkit-box;
    display:-ms-flexbox;
    display:flex;
    -webkit-box-orient:horizontal;
    -webkit-box-direction:normal;
    -ms-flex-flow:row wrap;
    flex-flow:row wrap;
  }
}
手順7:認証後トップページの作成
申込済み一覧が作成完了しましたら、認証後トップページを作成します。 認証後トップページでは、手順5で作成した「申込済み一覧」と公開ページで共通で使用する「ウェビナー 一覧」「アーカイブ一覧」を埋め込みます。
ポイント②
ウェビナー 一覧から詳細のリンク先を分岐させる

ウェビナー 一覧は、公開ページと認証後ページの両方で使われています。
両ページで詳細を出し分けるために下記のように作っています。
公開ページ PHP
$SPIRAL->setTHValue("login",false);
認証後ページ PHP
$SPIRAL->setTHValue("login",true);
ウェビナー 出し分け
<a th:if="!${cp.result.value['login']}" th:href="|${pages['p0xx']?.path ?: '/404'}?${record.linkParam}|" class="webinarLink">詳細を見る</a>

<a th:if="${cp.result.value['login']}" th:href="|${pages['p0xx']?.path ?: '/404'}?${record.linkParam}|" class="webinarLink">詳細を見る</a>
手順8:申込キャンセルフォーム作成
申込キャンセルフォームは、標準の削除フォームのブロックを使用します。
こちらも会員登録で使用したコピペCSS 「シンプルモダン」と同一のCSSをコピペします。
ページを作成する際は、どのウェビナー申込キャンセルするかわかるように申込詳細のブロックも一緒に埋め込みます。
HTML
<div class="wrapper">
    <!-- ヘッダ-->
    <sp:block name="fcbxxxx"></sp:block>
    <div class="contents inner-1200 inner-sp">
        <div class="webinarDetail">
            <div class="appArea">
                <sp:block name="dfbxxxx"></sp:block>
            </div>
            <!-- 入力時のみ表示-->
            <th:block th:if="!${cp.result.value['step']}">
                <sp:block name="ribxxx"></sp:block>
            </th:block>
        </div>
    </div>
</div>
ウェビナー詳細画面は複数で使用しています。
キャンセル画面で参加ボタンやキャンセルボタンを表示させないように下記値をPHPで渡しています。
PHP
<?php
$SPIRAL->setTHValue("cancel",true);
// ステップのセット
$getDeleteForm = $SPIRAL->getDeleteForm("appCancel");
$SPIRAL->setTHValue("step", $getDeleteForm->isCompletedStep());
手順9:アンケートフォーム作成
アンケートフォームは、ウェビナー申込DBのカラムとして追加しています。
ウェビナー後に一斉配信にてアンケートを送ることもできますが、今回はセミナー翌日にアンケートボタンが表示される作りになっています。
通常の更新フォームをベースに作成しておりますが、満足度は CSS と Jquery を利用し、星型のレーティング形式の回答欄を作成しております。
コピペCSSを使用しておりますが、星型のレーティング形式の箇所は独自にデザインをあてているので、抜粋して記載いたします。

HTML
<sp:input-field name="f0xx"></sp:input-field> 
<div class="sp-form-item sp-form-field"> 
    <div class="sp-form-label"> 
    <th:block th:text="${fields['f0xx'].label}">
        Label
    </th:block> 
    <span class="sp-form-required" th:if="${fields['f0xx'].required}" th:text="${fields['f0xx'].requiredIndicator}">*</span>
    </div> 
    <div class="sp-form-data"> 
    <div class="assessment">
        <input id="assessment5" class="starRadio" type="radio" name="f0xx" value="5" th:checked="${inputs['f0xx']} eq 5">
        <label class="inputRadio" for="assessment5" data-val="5">★</label>
        <input id="assessment4" class="starRadio" type="radio" name="f0xx" value="4" th:checked="${inputs['f0xx']} eq 4">
        <label class="inputRadio" for="assessment4" data-val="4">★</label>
        <input id="assessment3" class="starRadio" type="radio" name="f0xx" value="3"  th:checked="${inputs['f0xx']} eq 3">
        <label class="inputRadio" for="assessment3" data-val="3">★</label>
        <input id="assessment2" class="starRadio" type="radio" name="f0xx" value="2" th:checked="${inputs['f0xx']} eq 2">
        <label class="inputRadio" for="assessment2" data-val="2">★</label>
        <input id="assessment1" class="starRadio" type="radio" name="f0xx" value="1" th:checked="${inputs['f0xx']} eq 1">
        <label class="inputRadio" for="assessment1" data-val="1">★</label>
    </div>
    <p id="assessmentTxt"></p>
    <span class="sp-form-noted" th:if="${fields['f0xx'].help != null}" th:text="${fields['f0xx'].help}">Help text</span>
    <span class="sp-form-error" th:if="${errors['f0xx'] != null}" th:text="${errors['f0xx'].message}">Error message</span>
    </div> 
</div> 
CSS
#assessmentTxt{
    font-size: 1.2em;
    font-weight: bold;
    color: #7a7171;
    padding-left: 10px;
    margin-top: -10px;
}
.assessment{
display: -ms-flex;
    display: -webkit-flex;
    display: -moz-flex;
    display: -o-flex;
    display: flex;
    flex-direction: -ms-row-reverse;
    flex-direction: -webkit-row-reverse;
    flex-direction: -moz-row-reverse;
    flex-direction: -o-row-reverse; 
    flex-direction: row-reverse;
    justify-content: -ms-left;
    justify-content: -webkit-left;
    justify-content: -moz-left;
    justify-content: -o-left;
    justify-content: left;
}
.assessment input[type='radio']{
    display: none;
}
.assessment input[type='radio']{
    display: none;
}
.assessment label{
    position: relative;
    color: #bbb;
    cursor: pointer;
    font-size: 3.5em;
    padding: 0;
}
.assessment label.inputRadio:hover,
.assessment label.inputRadio:hover ~ label,
.assessment input[type='radio']:checked ~ label{
    color: #FDD500;
    margin: 0;
}
JavaScript
$(function () {
    var assessmentTxt = {1:"全く参考にならなかった",2:"参考にならなかった",3:"どちらでもない",4:"参考になった",5:"大変参考になった"};
    
    if( $('input[name="f012"]:checked').val()) {
        $("#assessmentTxt").text((assessmentTxt[$('input[name="f012"]:checked').val()]));
    }
    
    $(document).ready(function(){
        $("label.inputRadio").hover(
            function() {
                $("#assessmentTxt").text((assessmentTxt[$(this).data("val")]));
            },
            function() {
                if( $('input[name="f012"]:checked').val() === undefined ) {
                $("#assessmentTxt").text("");
                }else{
                $("#assessmentTxt").text((assessmentTxt[$('input[name="f012"]:checked').val()]));
                }
            }
        );
        
    });
    
    $('label').click(function() {
        $("#assessmentTxt").text((assessmentTxt[$(this).data("val")]));
    })
})
星型のレーティング形式の JavaScript は、Jquery の形式で記載しております。
アンケートページのみ head で Jquery を読み込んでください。
head
<!-- jquery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
ポイント③
お礼メールの再送信

アンケートのメールアクションでお礼メールを送っています。
ver.2.20 よりフォームからのメールアクションを手動で再送信できるようになっています。
登録・更新フォームをトリガにしたメールアクションでも届かないなどの問題が解消されます。
以上で設定は完了となります。
デモのソースコードのため、name値 や リンク先などをマスクしております。
登録やリンクが正しくつながっていない箇所がないか等は、テストの実施をお願いします。

最後に

設定後は動作確認を必ず行い、動作に問題がないか確認をしてください。
また、不具合やほかのやり方が知りたい等あれば、下記の「コンテンツに関しての要望はこちら」からご連絡ください。
サイト設計・構築が完了したので次はユーザ・アプリロール・グループ設定に進みます。

関連記事はこちら
解決しない場合はこちら コンテンツに関しての
要望はこちら