手順書管理Webアプリ作成

# はじめに
手順書が色々散らばってしまっているため、一括管理するためのWebアプリを作成する。
手順書はマークダウン記法で記述する。
将来的にはサーバーも立ち上げたいが自分には少し難易度があり時間がかかると思うので、とりあえずそれなりに形にするためにフロントエンドで完結する形で作成する。
手順書はデータベースを活用して管理したいが、とりあえずjsonファイルにべた書きで管理する。
個人利用のアプリであり、初心者が手探りで作っているため至らない点があると思うがメモとして使っていると思ってください。

・使用するライブラリ
jquery-1.8.0.js
marked.js

# 開発
### ディレクトリ構成
```
/procedure-site
│
├── /src
    ├── /main
        ├── /webapp                     # ウェブアプリケーションのリソース
        │   ├── /static                 # 静的ファイル (CSS, JS, 画像など)
        │   │   ├── /css                # CSSファイル
        │   │   ├── /js                 # JSファイル
        │   │   ├── /data               # jsonファイル
        │   │   └── /images             # 画像ファイル
        │   ├── /html                   # HTMLファイル
        │   ├── /md                     # mdファイル(手順書)
        └── application.properties      # アプリケーションの設定

```

### ホーム画面

```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>手順書一覧</title>
    <link rel="stylesheet" href="/src/main/webapp/static/css/style.css">
    <script src="/src/main/webapp/static/js/jquery-1.8.0.js"></script>
    <script src="/src/main/webapp/static/js/index.js"></script>
</head>
<body>
    <h1>手順書一覧</h1>
    <div id="search-box">
        <input type="text" id="search-input" placeholder="検索...">
        <button id="search-btn">検索</button>
    </div>
    <ul id="procedure-list">
        <!-- 手順書の一覧がここに動的に挿入される -->
    </ul>
    <button onclick="window.location.href='/src/main/webapp/html/rule.html'">手順書記載ルール</button>
</body>
</html>
```

```index.js
$(function() {
    // 手順書一覧のデータを格納する変数
    var procedures = [];

    // 手順書一覧を取得して表示
    $.getJSON('/src/main/webapp/static/data/procedures.json', function(data) {
        procedures = data;
        renderList(procedures);
    });

    $('#search-btn').on('click', function() {
        var query = $('#search-input').val().toLowerCase();
        if (query) {
            var filtered = procedures.filter(function(procedure) {
                return procedure.title.toLowerCase().includes(query);
            });
            renderList(filtered);
        } else {
            renderList(procedures);
        }
    });

    function renderList(data) {
        var $list = $('#procedure-list');
        $list.empty();
        
        data.forEach(function(procedure) {
            var $item = $('<li>').append(
                $('<a>')
                    .attr('href', '/src/main/webapp/html/procedure-view.html?file=' + procedure.filename)
                    .text(procedure.title + ' (更新年月日：' + procedure.date + ')')
            );
            $list.append($item);
        });
    }
});


```

### 手順書表示画面
```procedure-view.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>手順書詳細</title>
    <link rel="stylesheet" href="/src/main/webapp/static/css/style.css">
    <script src="/src/main/webapp/static/js/jquery-1.8.0.js"></script>
    <script src="/src/main/webapp/static/js/marked.min.js"></script>
    <script src="/src/main/webapp/static/js/procedure-view.js"></script>
</head>
<body>
    <button onclick="window.location.href='/src/main/webapp/html/index.html'">トップページに戻る</button>
    <h1>手順書詳細</h1>
    <div id="procedure-content">
        <!-- 手順書の内容がここに動的に挿入される -->
    </div>
</body>
</html>

```
```procedure-view.js
$(function() {
    // URLのクエリパラメータから.mdファイルの名前を取得
    var filename = getParameterByName('file');
    
    if (filename) {
        $.get('/src/main/webapp/static/md/' + filename, function(data) {
            var htmlContent = marked(data);
            $('#procedure-content').html(htmlContent);
        });
    }

    function getParameterByName(name, url) {
        if (!url) url = window.location.href;
        name = name.replace(/[\[\]]/g, '\\$&');
        var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
            results = regex.exec(url);
        if (!results) return null;
        if (!results[2]) return '';
        return decodeURIComponent(results[2].replace(/\+/g, ' '));
    }
});

```

### CSSファイル
```style.css
body {
    font-family: 'Arial', sans-serif;
}

#container {
    width: 80%;
    margin: auto;
}

#search {
    margin-bottom: 20px;
}

#procedure-list {
    list-style-type: none;
    padding: 0;
}

#procedure-content {
    margin-top: 20px;
}

pre {
    background-color: #f8f8f8;
    padding: 10px;
    border: 1px solid #ccc;
}
```


### 手順書サンプル
```procedure1.md
# H1タイトル
## H2タイトル
### H3タイトル
#### H4タイトル
##### H5タイトル
###### H6タイトル

**太字**
__太字__

*斜体*
_斜体_


- リスト1
- リスト2

1. リスト1
2. リスト2


| ヘッダ1 | ヘッダ2 |
|--------|--------|
| データ1 | データ2 |

- [ ] チェックボックス1
- [x] チェックボックス2

![代替テキスト](URL)

- アイテム1
  - サブアイテム1-1
    - サブサブアイテム1-1-1

```
コードブロック
```

[外部リンク](http://example.com)
```

### 手順書管理用jsonファイル
```
[
    {
      "filename": "procedure1.md",
      "title": "サンプル1",
      "date": "2023-09-26"
    },
    {
      "filename": "procedure2.md",
      "title": "サンプル2",
      "date": "2023-09-25"
    }

]
```


# 終わりに
随時改善していこうと思う。