画面のモックを作るツールはいろいろありますが、簡単にモックを作る方法としてChatGPTを利用する記事を見つけました。
参考 : ChatGPTを利用して画面モックを爆速で作成する - Taste of Tech Topics
「無料」で「インストールや環境構築不要」がよいので、無料版の「ChatGPT 3.5」を利用します。
また、モックツールを検索するとちょくちょく見かける「Bootstrap」も使ってみました。
ログイン画面
まずはシンプルに「Bootstrapを使ったログイン画面のhtmlを書いて」とGhatGPTに伝えるとこんな感じになりました。
GhatGPTの出力結果
Bootstrapを使用して作成したログイン画面のHTMLの例を以下に示します。
このHTMLコードでは、Bootstrapライブラリを使用してログインフォームを作成しています。フォームの入力フィールドとボタンはBootstrapのスタイルが適用され、レスポンシブデザインにも対応しています。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ログイン</title>
<!-- Bootstrap CSS -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
background-color: #f4f4f4;
}
.login-form {
max-width: 400px;
margin: 0 auto;
padding: 30px 20px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
margin-top: 100px;
}
.login-form h2 {
text-align: center;
margin-bottom: 30px;
}
.login-form input[type="text"],
.login-form input[type="password"] {
width: 100%;
padding: 10px;
margin-bottom: 20px;
border: 1px solid #ccc;
border-radius: 4px;
}
.login-form button {
width: 100%;
padding: 10px;
background-color: #007bff;
border: none;
border-radius: 4px;
color: #fff;
cursor: pointer;
}
.login-form button:hover {
background-color: #0056b3;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6 offset-md-3">
<div class="login-form">
<h2>ログイン</h2>
<form action="login.php" method="post">
<div class="form-group">
<label for="username">ユーザー名:</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="form-group">
<label for="password">パスワード:</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary">ログイン</button>
</form>
</div>
</div>
</div>
</div>
<!-- Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>
</html>
検索画面
まずは、「本を検索する画面のHTMLを作って」と頼むととてもシンプルな検索画面が出力されました。
GhatGPTの出力結果
以下は、本を検索する画面のHTMLの例です。
このHTMLコードでは、Bootstrapを使用して本を検索するためのフォームが作成されています。入力フィールドと検索ボタンがあり、ユーザーがキーワードを入力して検索することができます。デザインはBootstrapのスタイルが適用されており、レスポンシブに対応しています。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>本を検索する</title>
<!-- Bootstrap CSS -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
background-color: #f4f4f4;
}
.search-form {
max-width: 600px;
margin: 0 auto;
padding: 30px 20px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
margin-top: 50px;
}
.search-form h2 {
text-align: center;
margin-bottom: 30px;
}
.search-form input[type="text"] {
width: 100%;
padding: 10px;
margin-bottom: 20px;
border: 1px solid #ccc;
border-radius: 4px;
}
.search-form button {
width: 100%;
padding: 10px;
background-color: #007bff;
border: none;
border-radius: 4px;
color: #fff;
cursor: pointer;
}
.search-form button:hover {
background-color: #0056b3;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-8 offset-md-2">
<div class="search-form">
<h2>本を検索する</h2>
<form action="search.php" method="get">
<div class="form-group">
<label for="keyword">キーワード:</label>
<input type="text" class="form-control" id="keyword" name="keyword" required>
</div>
<button type="submit" class="btn btn-primary">検索</button>
</form>
</div>
</div>
</div>
</div>
<!-- Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>
</html>
次に「検索はタイトルと著者名にして」と検索項目を指定するとこんな感じになりました。
GhatGPTの出力結果
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>本を検索する</title>
<!-- Bootstrap CSS -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
background-color: #f4f4f4;
}
.search-form {
max-width: 600px;
margin: 0 auto;
padding: 30px 20px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
margin-top: 50px;
}
.search-form h2 {
text-align: center;
margin-bottom: 30px;
}
.search-form input[type="text"] {
width: 100%;
padding: 10px;
margin-bottom: 20px;
border: 1px solid #ccc;
border-radius: 4px;
}
.search-form button {
width: 100%;
padding: 10px;
background-color: #007bff;
border: none;
border-radius: 4px;
color: #fff;
cursor: pointer;
}
.search-form button:hover {
background-color: #0056b3;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-8 offset-md-2">
<div class="search-form">
<h2>本を検索する</h2>
<form action="search.php" method="get">
<div class="form-group">
<label for="title">タイトル:</label>
<input type="text" class="form-control" id="title" name="title" required>
</div>
<div class="form-group">
<label for="author">著者名:</label>
<input type="text" class="form-control" id="author" name="author" required>
</div>
<button type="submit" class="btn btn-primary">検索</button>
</form>
</div>
</div>
</div>
</div>
<!-- Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>
</html>
「検索項目は1つ以上入力」「国会図書館のAPIで検索」「検索結果を一覧表にする」などいろいろChatGPTに伝えて以下のような画面のHTMLを出力することができました。
GhatGPTの出力結果
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>国会図書館検索</title>
<!-- Bootstrap CSS -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h1 class="mt-5">国会図書館検索</h1>
<form id="searchForm" class="mt-4 mb-3" onsubmit="submitSearch(event);">
<div class="form-row">
<div class="col-md-4 mb-3">
<label for="title">タイトル:</label>
<input type="text" class="form-control" id="title" name="title">
</div>
<div class="col-md-4 mb-3">
<label for="author">著者名:</label>
<input type="text" class="form-control" id="author" name="author">
</div>
</div>
<div class="form-row text-right">
<div class="col-md-8 mb-3">
<button type="submit" class="btn btn-primary">検索</button>
<button type="button" class="btn btn-secondary ml-2" onclick="clearSearch()">クリア</button>
</div>
</div>
</form>
<div id="searchResults"></div>
</div>
<!-- Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<script>
function submitSearch(event) {
event.preventDefault();
var title = document.getElementById("title").value.trim();
var author = document.getElementById("author").value.trim();
// 検索条件のチェック
if (title === "" && author === "") {
alert("タイトルまたは著者名の少なくとも一つを入力してください。");
return;
}
// 国会図書館のAPIエンドポイント
var apiUrl = "https://ndlsearch.ndl.go.jp/api/opensearch";
// 検索クエリの構築
var query = "";
if (title !== "") {
query += "title=" + encodeURIComponent(title) + "&";
}
if (author !== "") {
query += "creator=" + encodeURIComponent(author) + "&";
}
query += "count=10"; // 最大検索結果数を指定
// APIリクエストを送信
fetch(apiUrl + "?" + query)
.then(response => response.text())
.then(data => {
// 検索結果を整形して表示
var searchResults = document.getElementById("searchResults");
searchResults.innerHTML = ""; // 一度中身をクリア
// テーブル要素を作成
var table = document.createElement("table");
table.classList.add("table", "table-striped", "mt-3");
// テーブルヘッダーを作成
var thead = document.createElement("thead");
thead.innerHTML = `
<tr>
<th>タイトル</th>
<th>著者名</th>
<th>出版日</th>
<th>ISBN</th>
</tr>
`;
table.appendChild(thead);
// テーブルボディーを作成
var tbody = document.createElement("tbody");
// XMLデータをパース
var parser = new DOMParser();
var xmlDoc = parser.parseFromString(data, "text/xml");
var items = xmlDoc.querySelectorAll("rss channel item");
items.forEach(item => {
var title = item.querySelector("title").textContent;
var author = item.querySelector("author").textContent;
var pubDate = item.querySelector("pubDate").textContent;
// ISBNを取得
var identifiers = item.querySelectorAll("identifier");
var isbn = "";
identifiers.forEach(identifier => {
var xsiType = identifier.getAttribute("xsi:type");
if (xsiType === "dcndl:ISBN") {
isbn = identifier.textContent;
}
});
var row = document.createElement("tr");
var titleCell = document.createElement("td");
titleCell.textContent = title;
var authorCell = document.createElement("td");
authorCell.textContent = author;
var pubDateCell = document.createElement("td");
pubDateCell.textContent = pubDate;
var isbnCell = document.createElement("td");
isbnCell.textContent = isbn;
row.appendChild(titleCell);
row.appendChild(authorCell);
row.appendChild(pubDateCell);
row.appendChild(isbnCell);
tbody.appendChild(row);
});
table.appendChild(tbody);
searchResults.appendChild(table);
})
.catch(error => {
console.error("検索エラー:", error);
});
}
function clearSearch() {
document.getElementById("title").value = "";
document.getElementById("author").value = "";
}
</script>
</body>
</html>
ファイルアップロード画面
ここでは要件をまとめてChatGPTに伝えてみました。
Bootstrapを使ってファイルアップロード画面をHTML出力して。
- ドラックアンドドロップでアップロードできるようにする
- アップロード後に「登録」ボタンでアップロード履歴に履歴を表示する
- 「登録」ボタンは右端に表示する
- 「登録」はファイルがアップロードされていない場合は非活性にする
- アップロード履歴を下に一覧で表示する
- アップロード履歴には「ファイル名」「アップロード日時」「状態」を表示する
- 状態には「アップロード中」「成功」「失敗」がある
- アップロード履歴にはサンプルデータを表示して
- アップロード欄には選択したファイル名を表示する
- 「登録」ボタンを押下したらアップロード欄のファイル名はクリアする
- アップロード履歴はアップロード日時の降順で表示する
- 「アップロード日時」の表示フォーマットは「YYYY-mm-dd HH:MM:DD」
GhatGPTの出力結果
以下は、要件に合わせてBootstrapを使用してファイルアップロード画面をHTMLで出力するコードです。このコードでは、ドラッグアンドドロップでファイルをアップロードし、アップロード後に「登録」ボタンを押すことでアップロード履歴にファイルの情報が表示されます。登録ボタンは右端に表示され、ファイルがアップロードされていない場合は非活性になります。アップロード履歴には「ファイル名」「アップロード日時」「状態」が表示され、状態には「アップロード中」「成功」「失敗」があります。アップロード履歴にはサンプルデータが表示され、アップロード欄には選択したファイル名が表示されます。また、「登録」ボタンを押すとアップロード欄のファイル名がクリアされ、アップロード履歴はアップロード日時の降順で表示されます。アップロード日時の表示フォーマットは「YYYY-mm-dd HH:MM:SS」です。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Upload</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
#file-upload {
border: 2px dashed #aaa;
border-radius: 10px;
padding: 20px;
cursor: pointer;
}
#register-btn {
float: right;
}
</style>
</head>
<body>
<div class="container mt-5">
<h1>File Upload</h1>
<div id="file-upload" class="mb-3">
<label for="file-input" class="form-label">ドラッグアンドドロップまたはクリックしてファイルをアップロード</label>
<input type="file" class="form-control-file" id="file-input" style="display: none;">
<div id="file-name" class="mt-2"></div>
</div>
<button id="register-btn" class="btn btn-primary mb-3" disabled>登録</button>
<div id="upload-history">
<h2>アップロード履歴</h2>
<table class="table">
<thead>
<tr>
<th scope="col">ファイル名</th>
<th scope="col">アップロード日時</th>
<th scope="col">状態</th>
</tr>
</thead>
<tbody id="upload-history-body">
<tr>
<td>sample_file.txt</td>
<td>2024-03-06 10:30:00</td>
<td>成功</td>
</tr>
<!-- Sample data row, replace with dynamic content -->
</tbody>
</table>
</div>
</div>
<script>
const fileInput = document.getElementById('file-input');
const registerBtn = document.getElementById('register-btn');
const fileNameDisplay = document.getElementById('file-name');
const uploadHistoryBody = document.getElementById('upload-history-body');
fileInput.addEventListener('change', function () {
if (fileInput.files.length > 0) {
registerBtn.disabled = false;
const fileName = fileInput.files[0].name;
fileNameDisplay.innerHTML = `選択したファイル: ${fileName}`;
} else {
registerBtn.disabled = true;
fileNameDisplay.innerHTML = '';
}
});
registerBtn.addEventListener('click', function () {
const fileName = fileInput.files[0].name;
const currentDate = new Date().toISOString().slice(0, 19).replace('T', ' ');
const newRow = document.createElement('tr');
newRow.innerHTML = `
<td>${fileName}</td>
<td>${currentDate}</td>
<td>アップロード中</td>
`;
uploadHistoryBody.insertBefore(newRow, uploadHistoryBody.firstChild);
fileNameDisplay.innerHTML = ''; // Clear file name display
fileInput.value = ''; // Clear file input value
registerBtn.disabled = true; // Disable register button
});
// ドラッグアンドドロップイベントの処理
const fileUpload = document.getElementById('file-upload');
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
fileUpload.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
['dragenter', 'dragover'].forEach(eventName => {
fileUpload.addEventListener(eventName, highlight, false);
});
['dragleave', 'drop'].forEach(eventName => {
fileUpload.addEventListener(eventName, unhighlight, false);
});
function highlight() {
fileUpload.classList.add('border-primary');
}
function unhighlight() {
fileUpload.classList.remove('border-primary');
}
fileUpload.addEventListener('drop', handleDrop, false);
function handleDrop(e) {
const dt = e.dataTransfer;
const files = dt.files;
fileInput.files = files;
const fileName = files[0].name;
fileNameDisplay.innerHTML = `選択したファイル: ${fileName}`;
const registerBtn = document.getElementById('register-btn');
registerBtn.disabled = false;
}
</script>
</body>
</html>
ポイント
初めてChatGPTでモックのHTMLを作ってみて「ここがポイント」と思ったことは以下です。
- コードが長いと途中でChatGPTの出力が止まることがあるので、そんな時は「続きは?」と問いかけると続きが出力される
- モックの要件をまとめてからChatGPTに問いかける
- 「検索画面」は「本を検索する画面のHTMLを作って」からひたすらChatGPTと会話して追加の要望を伝えて何度も何度もHTMLを出力しました。その過程で前に伝えたことが漏れたり、ずれたりしました。
- なので、「要件をエディタなどにまとめる」「ChatGPTにHTMLを出力してもらう」「モック(HTML)を確認する」「要件を追記する」を繰り返すほうが良いと感じました。
- ある程度希望のモック画面ができたら自分で微調整する
- 細かい部分はChatGPTに伝える言葉を考えるより、JavaScriptやCSSを書いてしまったほうが早そうでした。
さいごに
ChatGPTでHTMLを出力するのは思っていたよりも簡単でした。
ただ、「要件を文字にする能力」が問われました(というか苦戦しました)。
とはいえ、ゼロからHTMLを書くことを考えれば、かなり簡単にモックのHTMLが作成できます。
この後の試行錯誤