色々低コストなHP制作

# 概要

Markdown と Pandoc を使用して、HTMLとCSSのみで構成されたお手軽運用ホームページを作成します。

CGIやCMSを使用しないので、格安のレンタルサーバーでも運用が可能と考えられます。

問い合わせとかについては他サービスを利用します。
それによって、全体の運用コストを削減します。

最後に使用したテンプレートを記載しておりますので、サイト作成の参考にして頂ければと思います。


# 検証環境

- OS: Ubuntu 22.04 LTS AMD64
    - LXDコンテナを作成してその中で構築
- Pandoc: 3.1.12.1

# インストール

最新のバージョンを使用するため、あらかじめ公式サイトからdebファイルをダウンロードしてインストールします。

debを直接入れるため、LXDコンテナを作ってその中で構築するのがオススメです。

```zsh:インストール
$ apt install pandoc-3.1.12.1-1-amd64.deb
```

# テンプレートの作成

表示を柔軟に変更するために、テンプレートファイルをエクスポートして改良します。

主に必要のない部分を削除したり、レイアウトを自分好みに変更します。

```zsh:標準テンプレートのエクスポート
$ pandoc -D html5 > template.html
```

# Markdownファイルを作る

コンテンツの情報をこちらに入れます。

## 変数の設定

まず、タイトル等の設定を入れます。

また、SNSアカウント等もこちらに入れて表示に使用します。

```markdown:変数部分
---
css:
- ./css/exclusive.css
- ./css/common.css
title: やわ音原ミキサー
subtitle: あなたの動画にソフトウェアトークを入れて、より魅力的に！
description-meta: やわ音原ミキサーの公式サイトです
author:
- 兎のあす
keywords:
- やわ音原ミキサー
- ニコニコ動画
sns:
- link: https://github.com/Usagno8su/YawaOngenMixer
  title: CUI版
  github: true
  icon: ./pic/github-mark-white.svg
- link: https://github.com/Usagno8su/YawaOngenMixer_doc
  title: CUI版ドキュメント
  github: true
  icon: ./pic/github-mark-white.svg
- link: https://www.nicovideo.jp/user/4448412
  title: ニコニコ動画
  niconico: true
  icon: ./pic//niconico-siro.png
- link: https://twitter.com/YawaOngenMixer
  title: 公式X（旧Twitter）
  twitter: true
  icon: ./pic/x-logo.svg
...
```

行った工夫としては、CSSを外部ファイルにしている点です。

CSSはHTMLファイル内に記載して一つのファイルにすることができるのですが、CSSに変更があった場合に毎回ビルドを行う必要があります。

その手間を削減するために、外部ファイルに記載してそのパスを記載しています。（画像ファイルについても同様）

また、SNSアカウントについてもこちらに記載し、後ほどそれぞれのアイコンをリンクにします。


# テンプレートの仕様について

冒頭で出力したPandocのテンプレートファイルの仕様について説明します。

## 変数

`$`マークで囲われた文字を変数と認識します。

```markdown:変数
$title$
```


## if文

if文により変数に値が入っている時のみ表示するような動作が可能です。

```markdown:if文
$if(title)$
<h1 class="title text-center title-color title-size">$title$</h1>
$endif$
```

```html:出力結果
<h1 class="title text-center title-color title-size">やわ音原ミキサー</h1>
```

## for文

for文により複数の値を入力できます。

冒頭の変数一覧について、CSSは複数ありますが、これは配列となっており、複数の値を指定できます。

それを一つずつ出力できます。

```markdown:for文
$for(css)$
  <link rel="stylesheet" href="$css$" />
$endfor$
```

```html:出力結果
<link rel="stylesheet" href="./css/exclusive.css">
<link rel="stylesheet" href="./css/common.css">
```


## 特殊な変数について

いくつかの変数については、ビルド時にコマンドでないようを指定できます。

- header-includes
    - `-H`オプションで指定されたHTMLファイル
- include-before
    - `-B`オプションで指定されたHTMLファイル
- include-after
    - `-A`オプションで指定されたHTMLファイル
- body
    - Markdownファイルの本文



## 本文へのCSS適用

本文内にCSSを適用させるには、以下のように適用させたい文章を囲みます。

```markdown:CSSの適用
::::{.item-justify-center}
この部分に適用させます。
::::
```
これで、`::::`の範囲を`<div>`タグで囲んで`item-justify-center`というCSSを適応することができます。

```html:出力結果
<div class="item-justify-center">
  <p>この部分に適用させます。</p>
</div>
```


また、出力されるタグに直接CSSを適用することも出来ます。

```markdown:CSSをタグに適用

## この部分に適用させます。１ {.item-justify-center}

`この部分に適用させます。２`{.item-justify-center}

```

出力結果は下記のようになります。

```html:出力結果
<h2 class="item-justify-center">
  この部分に適用させます。１ 
</h2>
<code class="item-justify-center">
  この部分に適用させます。２
</code>
```


# テンプレートの分割

テンプレートを分割し、ヘッダーとフッターを別々に分けます。

これは、将来的に複数ページのサイトにする場合、それぞれを使い回せるようにするためです。

テンプレートに`body`の変数を入れなければ本文は出力されないので、元になるMarkdownファイルはメインのものと同じものを使用できます。

分割したファイルは最後にメインページを作成する際に結合します。



# SNSアカウント

SNSアカウントについては増えたり変わったりする場合もあるため、それに柔軟に対応できるようにします。

まず、各SNSアカウントの公式アイコンを予め取得しておきます。

そして冒頭の`sns`変数にそれぞれ設定します。

連想配列を配列化しており、各項目の設定は以下となっています。

- link: SNSアカウントのリンク
- title: アカウントの説明
- icon: アイコンファイルのURL
- github: アカウントのタイプとなります

最後のアカウントのタイプについてですが、
本当は`type: github`といった形にしたかったのですが、Pandocのif文を`$if(sns.type==='github')$`という形にできなかったため、このような形にしています。

これにより、githubアカウントのみ表示したい場合は`$if(sns.github)$`で判別できます。

すべてのアカウントを表示したい場合は下記のようにすればできます。

```markdown:SNSアカウント表示
$if(sns)$
$for(sns)$
<a href="$sns.link$" target="_blank" rel="noopener noreferrer">
  <img src="$sns.icon$" alt="$sns.title$" title="$sns.title$" width="30" height="30" class="margin-icon-r" />
</a>
$endfor$
$endif$
```



# デザインについて

これについては用途によって色々と差異があるかと思います。
私は簡単なシングルページのサイトにするため、内容をまとめたポスターを作るようなイメージで作成しました。


# デイレクトリ構成

使いやすや等も考えて、以下のようにしてみました。


- bin: ビルド用のスクリプト等
- component: ヘッダーやフッターのHTMLファイル
- outHTML:　レンタル鯖へアップするファイル(HTMLファイルの出力先)
  - css: cssファイル
  - pic: 画像素材とか
- src:　元となるMarkdownファイル
- template:　Pandocのテンプレートファイル




# ビルドの実行

まずヘッダーとフッターをビルドします。

```bash:コマンド
# ヘッダーを作成
$ pandoc src/top.md -s -o component/header.html --template=template/header-template.html

# フッターを作成
$ pandoc src/top.md -s -o component/footer.html --template=template/footer-template.html
```


その後それらをあわせてビルドしてファイルを完成させます。


```bash:コマンド
$ pandoc src/top.md -s -o outHTML/top.html -B component/header.html -A component/footer.html --template=template/top-template.html
```

これらをシェルスクリプトとして作成して、コマンド１回ですべてをビルドできるようにしています。

`-B`で指定したファイルはの下記の所に入ります。（複数指定可能）

```markdown:ヘッダー
$for(include-before)$
$include-before$
$endfor$
```

`-A`で指定したファイルはの下記の所に入ります。（こちらも複数指定可能）
```markdown:ヘッダー
$for(include-after)$
$include-after$
$endfor$
```


# 参考URL

- [Pandoc公式マニュアル](https://pandoc.org/MANUAL.html)
- [Pandoc User’s Guide 日本語版](https://pandoc-doc-ja.readthedocs.io/ja/latest/users-guide.html)
- [footerを最下部に固定する：CSSのプロパティ4行でOK](https://rilaks.jp/wordpress/footer-bottom-of-page/)
- [【HTML】基本のリンク＆別タブでリンクを開くコードと注意点](https://sukimanosukima.com/2021/02/09/html-6/)
- [PandocのHTML出力でGFMとカスタムテンプレートを使う](https://babooshka-innerjourneys.blogspot.com/2015/05/pandochtmlgfm.html)
- [Pandoc Markdownで任意の要素にクラス/IDを指定する](https://chienomi.org/archives/livewithlinux/1500)
- [markdownでHTMLのidやクラスなどの属性を指定 - 愚鈍人](http://ichitcltk.hustle.ne.jp/gudon2/index.php?pageType=file&id=markdown_PHP_Extra_Attributes.md)




# テンプレート一覧

```html:header-template.html
$-- ヘッダー
<header id="main-header" class="header-sta position-fixed item-justify-between bg-transparent">
  <div class="item-width-25pt"></div>
  <div class="item-width-50pt item-justify-center">
  </div>
  <div class="item-width-25pt item-justify-end">
    $if(sns)$
    $for(sns)$
    $if(sns.github)$
    <a href="$sns.link$" target="_blank" rel="noopener noreferrer">
      <img src="$sns.icon$" alt="$sns.title$" title="$sns.title$" width="30" height="30" class="margin-icon-r main-coloer round-9999 padding-1px" />
    </a>
    $endif$
    $endfor$
    $endif$
  </div>
</header>
```

```html:footer-template.html

$-- 下のリンク一覧等
<footer class="linkkist-position bar-color">
  <div class="item-justify-between">
    <div>
  
    </div>
    <div class="item-width-50pt item-justify-center">
    </div>
    <div class="margin-icon-r item-width-25pt item-justify-end">
      $if(sns)$
      $for(sns)$
      <a href="$sns.link$" target="_blank" rel="noopener noreferrer">
        <img src="$sns.icon$" alt="$sns.title$" title="$sns.title$" width="30" height="30" class="margin-icon-r" />
      </a>
      $endfor$
      $endif$
    </div>
  </div>
  <div class="item-justify-center">
    <div class="copy-light">
      copyright © $for(author-meta)$ $author-meta$. $endfor$ All Rights Reserved.
    </div>
  </div>
</footer>
```


```html:top-template.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
$for(author-meta)$
  <meta name="author" content="$author-meta$" />
$endfor$
$if(date-meta)$
  <meta name="dcterms.date" content="$date-meta$" />
$endif$
$if(keywords)$
  <meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" />
$endif$
$if(description-meta)$
  <meta name="description" content="$description-meta$" />
$endif$
  <title>$if(title-prefix)$$title-prefix$ - $endif$$pagetitle$</title>
$for(css)$
  <link rel="stylesheet" href="$css$" />
$endfor$
$for(header-includes)$
  $header-includes$
$endfor$
</head>
<body class="body-st">
$for(include-before)$
$include-before$
$endfor$

$-- タイトル
$if(title)$
<div id="title-block-header" class="main-coloer main-title-position">
<h1 class="title text-center title-color title-size">$title$</h1>
$if(subtitle)$
<p class="subtitle text-center title-color">$subtitle$</p>
$endif$
</div>
$endif$

$-- メインコンテンツ
<div class="main-con"> 
  $body$
</div>

$for(include-after)$
$include-after$
$endfor$
</body>
</html>
```


```css:common.css

/* 汎用的に使用するCSS */

.text-center{
  text-align: center;
}

.title-size{
  font-size: 64px;
}

.title-color{
  color: #e8ecef;
}

.bar-color {
  background-color: #185790;
}

.bg-transparent{
  background-color: transparent;
}

.round-9999{
  border-radius: 9999px;
}

.position-fixed{
  position: fixed;
}

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

.item-justify-center{
  display: flex;
  justify-content: center;
}

.item-justify-end{
  display: flex;
  justify-content: end;
}

.item-width-25pt{
  width: 25%;
}

.item-width-50pt{
  width: 50%;
}

.margin-icon-r{
  margin-right: 6px;
}

```


```css:exclusive.css

/* 各要所の専用CSSを入れる */

.body-st{
  margin: 0;
  display: flex;
  flex-flow: column;
  min-height: 100vh;
  background-color: #e9e9e9;
  color: #203354;
}

.main-title-position{
  margin: 0 calc(50% - 50vw);
  padding-top: 16px;
  padding-bottom: 8px;
  width: 100vw;
}

.main-coloer{
  background-color:#185790;
}

.header-sta{
  margin-top: 0px;
  padding-top: 2px;
  padding-bottom: 3px;
  width: 100vw;
  border-color: black;
  border:2px;
}

.linkkist-position{
  margin-bottom: 0;
  margin-right: 0;
  margin-left: 0;
  padding-top: 16px;
  padding-bottom: 12px;
  width: 100vw;
}

.main-con {
  flex: 1;
  margin-left: 10px;
  margin-right: 10px;
}

.copy-light{
  color: #e8ecef;
}
```