<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ねこねこ動画 - 動画共有サイト</title>
<style>
/* ベーススタイル */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f4f4f4;
}
header {
background-color: #333;
color: white;
padding: 10px;
text-align: center;
position: fixed;
width: 100%;
top: 0;
z-index: 100;
}
header h1 {
margin: 0;
font-size: 24px;
}
nav ul {
list-style-type: none;
padding: 0;
margin: 10px 0 0 0;
text-align: center;
}
nav ul li {
display: inline-block;
margin-right: 15px;
}
nav ul li a {
color: white;
text-decoration: none;
font-size: 16px;
}
#searchBar {
margin-top: 10px;
padding: 5px;
width: 300px;
max-width: 80%;
border: none;
border-radius: 4px;
}
.container {
margin-top: 100px;
padding: 20px;
max-width: 1200px;
margin-left: auto;
margin-right: auto;
}
.upload-container, .video-info, .description, .comments, .related-videos, .gallery {
background-color: white;
padding: 20px;
margin-top: 20px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.upload-container h2, .video-info h2, .description h2, .comments h2, .related-videos h2, .gallery h2 {
margin-top: 0;
}
.upload-container form input[type="file"],
.upload-container form input[type="text"],
.upload-container form textarea,
.upload-container form select {
width: 100%;
padding: 10px;
margin-bottom: 10px;
border-radius: 4px;
border: 1px solid #ccc;
}
.upload-container form button {
padding: 10px 20px;
background-color: #333;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.upload-container form button:hover {
background-color: #555;
}
.video-container {
position: relative;
text-align: center;
width: 100%;
max-width: 800px;
margin: 0 auto;
}
.video-container video {
width: 100%;
height: auto;
border-radius: 10px;
}
.comment-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 10;
}
.comment {
position: absolute;
white-space: nowrap;
font-size: 20px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
animation: moveComment linear forwards;
}
@keyframes moveComment {
from {
left: 100%;
}
to {
left: -100%;
}
}
.description p, .comments p, .gallery p {
margin: 10px 0;
}
.comments form textarea {
width: 100%;
padding: 10px;
border-radius: 4px;
border: 1px solid #ccc;
resize: vertical;
margin-bottom: 10px;
}
.comments form select {
width: 100%;
padding: 10px;
margin-bottom: 10px;
border-radius: 4px;
}
.comments form button {
padding: 10px 20px;
background-color: #333;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.comments form button:hover {
background-color: #555;
}
.comment-list .comment {
background-color: #f9f9f9;
padding: 10px;
margin-bottom: 10px;
border-radius: 5px;
}
.like-button, .dislike-button {
background-color: #333;
color: white;
border: none;
padding: 5px 10px;
margin: 5px;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.like-button:hover, .dislike-button:hover {
background-color: #555;
}
footer {
background-color: #333;
color: white;
text-align: center;
padding: 20px;
margin-top: 40px;
}
footer p {
margin: 0;
}
@media (max-width: 768px) {
nav ul li {
display: block;
margin: 10px 0;
}
#searchBar {
width: 80%;
}
.video-container {
max-width: 100%;
}
}
</style>
</head>
<body>
<!-- ヘッダー開始 -->
<header>
<h1>ねこねこ動画</h1>
<nav>
<ul>
<li><a href="#">ホーム</a></li>
<li><a href="#">人気動画</a></li>
<li><a href="#">カテゴリ</a></li>
<li><a href="#">ログイン</a></li>
</ul>
</nav>
<input type="text" id="searchBar" placeholder="動画を検索..." />
</header>
<!-- ヘッダー終了 -->
<div class="container">
<!-- 動画アップロードエリア -->
<div class="upload-container">
<h2>動画をアップロード</h2>
<form id="uploadForm" enctype="multipart/form-data">
<input type="file" id="videoFile" name="video" accept="video/*" required><br>
<input type="text" id="videoTitle" name="title" placeholder="動画タイトル" required><br>
<textarea id="videoDescription" name="description" rows="4" placeholder="動画の説明" required></textarea><br>
<button type="submit">アップロード</button>
</form>
<div id="uploadStatus"></div>
</div>
<!-- プレビューエリア -->
<div class="video-container" id="previewContainer" style="display: none;">
<h2 id="previewTitle">プレビュー: 動画タイトル</h2>
<video controls id="videoPreview"></video>
<div class="comment-overlay" id="commentOverlay"></div>
<p id="previewDescription">プレビュー: 動画の説明</p>
</div>
<!-- コメント投稿エリア -->
<div class="comments">
<h2>コメントを投稿</h2>
<form id="commentForm">
<textarea id="commentText" rows="4" cols="50" placeholder="コメントを追加..." required></textarea><br>
<label for="commentTime">表示タイミング (秒):</label>
<input type="number" id="commentTime" placeholder="0" min="0" required><br>
<label for="commentColor">コメントの色:</label>
<select id="commentColor">
<option value="white">白</option>
<option value="red">赤</option>
<option value="blue">青</option>
<option value="green">緑</option>
<option value="yellow">黄色</option>
</select><br>
<label for="commentFontSize">フォントサイズ:</label>
<select id="commentFontSize">
<option value="20px">小</option>
<option value="24px">中</option>
<option value="28px">大</option>
</select><br>
<label for="commentSpeed">表示速度 (秒):</label>
<input type="number" id="commentSpeed" placeholder="10" min="5" max="20" required><br>
<button type="submit">投稿</button>
</form>
<div id="commentList" class="comment-list"></div>
</div>
<!-- 評価機能 -->
<div class="rating">
<button class="like-button" id="likeButton">👍 いいね</button>
<span id="likeCount">0</span>
<button class="dislike-button" id="dislikeButton">👎 バッド</button>
<span id="dislikeCount">0</span>
</div>
</div>
<!-- フッター開始 -->
<footer>
<p>© 2023 ねこねこ動画. All Rights Reserved.</p>
</footer>
<!-- フッター終了 -->
<script>
let comments = [];
// 動画のアップロードとプレビュー処理
document.getElementById("uploadForm").addEventListener("submit", function(event) {
event.preventDefault();
const fileInput = document.getElementById("videoFile");
const file = fileInput.files[0];
const title = document.getElementById("videoTitle").value;
const description = document.getElementById("videoDescription").value;
if (!file) {
alert("動画ファイルを選択してください。");
return;
}
const reader = new FileReader();
reader.onload = function(e) {
const videoData = e.target.result;
document.getElementById("previewContainer").style.display = "block";
document.getElementById("videoPreview").src = videoData;
document.getElementById("previewTitle").textContent = "プレビュー: " + title;
document.getElementById("previewDescription").textContent = "プレビュー: " + description;
};
reader.readAsDataURL(file);
});
// コメント投稿処理
document.getElementById("commentForm").addEventListener("submit", function(event) {
event.preventDefault();
const commentText = document.getElementById("commentText").value;
const commentTime = parseInt(document.getElementById("commentTime").value);
const commentColor = document.getElementById("commentColor").value;
const commentFontSize = document.getElementById("commentFontSize").value;
const commentSpeed = parseInt(document.getElementById("commentSpeed").value);
if (commentText && commentTime >= 0) {
const comment = {
text: commentText,
time: commentTime,
color: commentColor,
fontSize: commentFontSize,
speed: commentSpeed
};
comments.push(comment);
displayCommentInList(comment);
document.getElementById("commentForm").reset();
}
});
// コメントリストに表示
function displayCommentInList(comment) {
const commentList = document.getElementById("commentList");
const commentDiv = document.createElement("div");
commentDiv.classList.add("comment");
commentDiv.textContent = `タイミング: ${comment.time}秒 - ${comment.text}`;
commentList.appendChild(commentDiv);
}
// 動画の再生に合わせてコメントを表示
const videoElement = document.getElementById("videoPreview");
videoElement.addEventListener("timeupdate", function() {
const currentTime = Math.floor(videoElement.currentTime);
comments.forEach(comment => {
if (comment.time === currentTime) {
displayCommentOnVideo(comment);
}
});
});
// 動画上にコメントを流す
function displayCommentOnVideo(comment) {
const overlay = document.getElementById("commentOverlay");
const commentElement = document.createElement("div");
commentElement.classList.add("comment");
commentElement.textContent = comment.text;
commentElement.style.color = comment.color;
commentElement.style.fontSize = comment.fontSize;
commentElement.style.animationDuration = `${comment.speed}s`;
commentElement.style.top = Math.random() * 80 + "%"; // ランダムな位置
overlay.appendChild(commentElement);
// 一定時間後にコメントを削除
setTimeout(() => {
commentElement.remove();
}, comment.speed * 1000);
}
// いいね・バッド機能
document.getElementById("likeButton").addEventListener("click", function() {
let likeCount = parseInt(document.getElementById("likeCount").textContent);
likeCount++;
document.getElementById("likeCount").textContent = likeCount;
});
document.getElementById("dislikeButton").addEventListener("click", function() {
let dislikeCount = parseInt(document.getElementById("dislikeCount").textContent);
dislikeCount++;
document.getElementById("dislikeCount").textContent = dislikeCount;
});
</script>
</body>
</html>
カテゴリー: HTML
ELDER.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ELDER - ソーシャルネットワーキングサービス</title>
<!-- CSSファイルの読み込み -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet">
<!-- RiTa.jsライブラリの読み込み -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/rita/1.3.63/rita-full.min.js"></script>
<style>
/* 既存のスタイルシート */
body {
padding-top: 20px;
background: linear-gradient(to right, #f8f9fa, #e9ecef);
font-family: 'Arial', sans-serif;
color: #343a40;
}
.navbar {
background-color: #007bff;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.navbar-brand,
.nav-link {
color: #fff !important;
font-weight: bold;
}
.navbar-toggler {
border: none;
}
.card {
border-radius: 12px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
transition: transform 0.3s, box-shadow 0.3s;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
}
.card-body {
padding: 30px;
}
.form-control {
border-radius: 20px;
border: 1px solid #ced4da;
padding: 15px;
transition: border-color 0.3s;
}
.form-control:focus {
border-color: #007bff;
box-shadow: none;
}
.btn-primary {
background-color: #007bff;
border: none;
border-radius: 20px;
padding: 10px 20px;
font-weight: bold;
transition: background-color 0.3s, transform 0.3s;
}
.btn-primary:hover {
background-color: #0056b3;
transform: translateY(-3px);
}
.btn-secondary {
border-radius: 20px;
padding: 10px 20px;
font-weight: bold;
transition: background-color 0.3s, transform 0.3s;
}
.btn-secondary:hover {
background-color: #6c757d;
transform: translateY(-3px);
}
.profile-img {
width: 80px;
height: 80px;
object-fit: cover;
border-radius: 50%;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}
.text-center h1 {
font-weight: 700;
font-size: 2.5em;
margin-bottom: 20px;
color: #007bff;
}
.comment-section {
margin-top: 20px;
padding: 20px;
background-color: #f1f3f5;
border-radius: 8px;
}
.comment-section .card {
border: none;
background: #ffffff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.modal-content {
border-radius: 15px;
overflow: hidden;
}
.modal-header {
background-color: #007bff;
color: white;
border-bottom: none;
}
.modal-footer {
border-top: none;
}
.form-error {
color: red;
font-size: 0.9em;
}
/* タイムラインのデザイン */
#timeline {
margin-top: 20px;
}
#timeline .card {
border-radius: 15px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
overflow: hidden;
background-color: #fff;
}
#timeline .card-body {
padding: 20px;
}
#timeline .btn {
border-radius: 20px;
}
/* 投稿のシェアボタン */
.btn-share {
background-color: #ff9800;
border: none;
border-radius: 20px;
padding: 5px 10px;
color: #fff;
font-weight: bold;
transition: background-color 0.3s;
}
.btn-share:hover {
background-color: #e68900;
}
/* X(旧Twitter)シェアボタン */
.btn-share-twitter {
background-color: #1da1f2;
border: none;
border-radius: 20px;
padding: 5px 10px;
color: #fff;
font-weight: bold;
transition: background-color 0.3s;
}
.btn-share-twitter:hover {
background-color: #1480bf;
}
/* 通知エリア */
#notificationArea {
position: fixed;
top: 80px;
right: 20px;
z-index: 1000;
max-width: 300px;
}
/* FEEDアイコンをRSSの文字に変更 */
.nav-item .rss-icon {
font-weight: bold;
color: #fff;
}
</style>
</head>
<body>
<!-- ナビゲーションバー -->
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">ELDER</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="ナビゲーションの切り替え">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="#" onclick="showLoginForm()">ログイン</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" onclick="showRegisterForm()">登録</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" onclick="showProfile()" style="display: none;" id="navProfile">プロフィール</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" onclick="logout()" style="display: none;" id="navLogout">ログアウト</a>
</li>
<!-- FEEDアイコンをRSSの文字に変更 -->
<li class="nav-item" id="navFeed" style="display: none;">
<a class="nav-link rss-icon" href="#" onclick="showFeedForm()">RSS</a>
</li>
</ul>
</div>
</nav>
<div class="container">
<!-- ログインフォーム -->
<div id="loginForm" class="card w-50 mx-auto">
<div class="card-body">
<h2 class="card-title text-center mb-4">ログイン</h2>
<div class="form-group">
<input type="text" id="loginUsername" class="form-control" placeholder="ユーザー名">
<span id="loginUsernameError" class="form-error" style="display: none;">ユーザー名を入力してください</span>
</div>
<div class="form-group">
<input type="password" id="loginPassword" class="form-control" placeholder="パスワード">
<span id="loginPasswordError" class="form-error" style="display: none;">パスワードを入力してください</span>
</div>
<button onclick="login()" class="btn btn-primary btn-block">ログイン</button>
<button onclick="showRegisterForm()" class="btn btn-secondary btn-block">登録</button>
</div>
</div>
<!-- 登録フォーム -->
<div id="registerForm" class="card w-50 mx-auto" style="display: none;">
<div class="card-body">
<h2 class="card-title text-center mb-4">登録</h2>
<div class="form-group">
<input type="text" id="registerName" class="form-control" placeholder="氏名">
<span id="registerNameError" class="form-error" style="display: none;">氏名を入力してください</span>
</div>
<div class="form-group">
<input type="text" id="registerUsername" class="form-control" placeholder="ユーザー名">
<span id="registerUsernameError" class="form-error" style="display: none;">ユーザー名を入力してください</span>
</div>
<div class="form-group">
<input type="password" id="registerPassword" class="form-control" placeholder="パスワード">
<span id="registerPasswordError" class="form-error" style="display: none;">パスワードを入力してください</span>
</div>
<div class="form-group">
<input type="password" id="registerConfirmPassword" class="form-control" placeholder="パスワードを確認">
<span id="registerConfirmPasswordError" class="form-error" style="display: none;">パスワードが一致しません</span>
</div>
<button onclick="register()" class="btn btn-primary btn-block">登録</button>
<button onclick="showLoginForm()" class="btn btn-secondary btn-block">ログインに戻る</button>
</div>
</div>
<!-- プロフィール -->
<div id="profile" class="card w-50 mx-auto" style="display: none;">
<div class="card-body">
<h2 class="card-title text-center mb-4">プロフィール</h2>
<div class="text-center mb-3">
<img id="profileImg" class="profile-img" src="default_profile_img.jpg" alt="プロフィール画像">
</div>
<p class="text-center mb-2"><strong>氏名:</strong> <span id="profileName"></span></p>
<p class="text-center mb-4"><strong>ユーザー名:</strong> <span id="profileUsername"></span></p>
<div class="form-group">
<input type="file" id="profileImageInput" accept="image/*" class="form-control-file">
</div>
<button onclick="uploadProfileImage()" class="btn btn-primary btn-block"><i class="fas fa-upload"></i> プロフィール画像をアップロード</button>
<button onclick="logout()" class="btn btn-danger btn-block"><i class="fas fa-sign-out-alt"></i> ログアウト</button>
</div>
</div>
<!-- 投稿フォーム -->
<div id="postForm" class="card w-75 mx-auto" style="display: none;">
<div class="card-body">
<h2 class="card-title text-center mb-4">投稿を作成</h2>
<div class="form-group">
<textarea id="postContent" class="form-control" rows="3" placeholder="今何を考えていますか?"></textarea>
</div>
<button onclick="createPost()" class="btn btn-primary btn-block">投稿</button>
</div>
</div>
<!-- FEED登録フォーム -->
<div id="feedForm" class="card w-75 mx-auto" style="display: none;">
<div class="card-body">
<h2 class="card-title text-center mb-4">FEEDを登録</h2>
<div class="form-group">
<input type="text" id="feedUrl" class="form-control" placeholder="RSSフィードのURL">
<span id="feedUrlError" class="form-error" style="display: none;">RSSフィードのURLを入力してください</span>
</div>
<button onclick="registerFeed()" class="btn btn-primary btn-block">登録</button>
<div class="form-group mt-4">
<label for="feedInterval">自動投稿の間隔(秒):</label>
<input type="number" id="feedInterval" class="form-control" placeholder="例:60" min="1">
</div>
<button onclick="setFeedInterval()" class="btn btn-secondary btn-block">間隔を設定</button>
</div>
</div>
<!-- AIBOT投稿登録フォーム -->
<div id="aiBotForm" class="card w-75 mx-auto" style="display: none;">
<div class="card-body">
<h2 class="card-title text-center mb-4">BOT投稿を登録</h2>
<div class="form-group">
<textarea id="aiBotContent" class="form-control" rows="3" placeholder="BOTに投稿させたい内容を入力してください"></textarea>
</div>
<button onclick="registerAiBotPost()" class="btn btn-primary btn-block">BOT投稿を登録</button>
</div>
</div>
<!-- タイムライン -->
<div id="timeline" class="w-75 mx-auto mt-4"></div>
<!-- 通知エリア -->
<div id="notificationArea" class="alert alert-info" style="display: none;"></div>
</div>
<!-- リプライモーダル -->
<div class="modal fade" id="replyModal" tabindex="-1" role="dialog" aria-labelledby="replyModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<!-- モーダルの内容は後ほどJavaScriptで制御します -->
<div class="modal-header">
<h5 class="modal-title" id="replyModalLabel">投稿に返信</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="閉じる">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<textarea id="replyContent" class="form-control" rows="3" placeholder="返信をここに書いてください..."></textarea>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">閉じる</button>
<button type="button" onclick="postReply()" class="btn btn-primary">返信</button>
</div>
</div>
</div>
</div>
<!-- スクリプトの読み込み -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<!-- BootstrapのJavaScript -->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<!-- RiTa.jsライブラリの読み込み(既にhead内で読み込み済み) -->
<script>
// ユーザー、投稿、フィード、チャット関連のデータ
let currentUser = null;
let users = [];
let posts = [];
let feeds = [];
let notifications = [];
let aiBotPosts = [];
let feedFetchInterval = 60000; // デフォルトは60,000ミリ秒(60秒)
let feedFetchTimer;
let markovBotInterval = 60000; // マルコフ連鎖BOTの投稿間隔
// ローカルストレージの読み込み・保存関連の関数
function saveUsersToLocalStorage() {
localStorage.setItem('users', JSON.stringify(users));
}
function savePostsToLocalStorage() {
localStorage.setItem('posts', JSON.stringify(posts));
}
function saveFeedsToLocalStorage() {
localStorage.setItem('feeds', JSON.stringify(feeds));
}
function saveAiBotPostsToLocalStorage() {
localStorage.setItem('aiBotPosts', JSON.stringify(aiBotPosts));
}
function saveCurrentUserToLocalStorage() {
if (currentUser) {
localStorage.setItem('currentUser', JSON.stringify(currentUser));
} else {
localStorage.removeItem('currentUser');
}
}
function loadUsersFromLocalStorage() {
const storedUsers = localStorage.getItem('users');
if (storedUsers) {
users = JSON.parse(storedUsers);
}
}
function loadPostsFromLocalStorage() {
const storedPosts = localStorage.getItem('posts');
if (storedPosts) {
posts = JSON.parse(storedPosts);
}
}
function loadFeedsFromLocalStorage() {
const storedFeeds = localStorage.getItem('feeds');
if (storedFeeds) {
feeds = JSON.parse(storedFeeds);
}
}
function loadAiBotPostsFromLocalStorage() {
const storedAiBotPosts = localStorage.getItem('aiBotPosts');
if (storedAiBotPosts) {
aiBotPosts = JSON.parse(storedAiBotPosts);
}
}
function loadCurrentUserFromLocalStorage() {
const storedCurrentUser = localStorage.getItem('currentUser');
if (storedCurrentUser) {
currentUser = JSON.parse(storedCurrentUser);
}
}
// フォームの表示・非表示
function hideAll() {
document.getElementById('loginForm').style.display = 'none';
document.getElementById('registerForm').style.display = 'none';
document.getElementById('profile').style.display = 'none';
document.getElementById('postForm').style.display = 'none';
document.getElementById('feedForm').style.display = 'none';
document.getElementById('aiBotForm').style.display = 'none';
}
function showLoginForm() {
hideAll();
document.getElementById('loginForm').style.display = 'block';
document.getElementById('navProfile').style.display = 'none';
document.getElementById('navLogout').style.display = 'none';
document.getElementById('navFeed').style.display = 'none';
}
function showRegisterForm() {
hideAll();
document.getElementById('registerForm').style.display = 'block';
}
function showProfile() {
hideAll();
document.getElementById('profile').style.display = 'block';
document.getElementById('profileName').textContent = currentUser.name;
document.getElementById('profileUsername').textContent = currentUser.username;
document.getElementById('postForm').style.display = 'block';
document.getElementById('feedForm').style.display = 'block';
document.getElementById('aiBotForm').style.display = 'block';
loadProfileImage(); // プロフィール画像をロード
displayTimeline(); // タイムラインを表示
document.getElementById('navProfile').style.display = 'block';
document.getElementById('navLogout').style.display = 'block';
document.getElementById('navFeed').style.display = 'block'; // RSSナビゲーションを表示
}
function showFeedForm() {
hideAll();
document.getElementById('feedForm').style.display = 'block';
}
// ユーザー認証関連の関数
function validateLoginForm() {
let valid = true;
const username = document.getElementById('loginUsername').value;
const password = document.getElementById('loginPassword').value;
if (!username) {
document.getElementById('loginUsernameError').style.display = 'block';
valid = false;
} else {
document.getElementById('loginUsernameError').style.display = 'none';
}
if (!password) {
document.getElementById('loginPasswordError').style.display = 'block';
valid = false;
} else {
document.getElementById('loginPasswordError').style.display = 'none';
}
return valid;
}
function login() {
if (!validateLoginForm()) {
return;
}
const username = document.getElementById('loginUsername').value;
const password = document.getElementById('loginPassword').value;
const user = users.find(u => u.username === username && u.password === password);
if (user) {
currentUser = user;
saveCurrentUserToLocalStorage(); // currentUserを保存
showProfile();
} else {
alert('ユーザー名またはパスワードが間違っています。');
}
}
function logout() {
currentUser = null;
saveCurrentUserToLocalStorage(); // currentUserを削除
hideAll();
showLoginForm();
}
function validateRegisterForm() {
let valid = true;
const name = document.getElementById('registerName').value;
const username = document.getElementById('registerUsername').value;
const password = document.getElementById('registerPassword').value;
const confirmPassword = document.getElementById('registerConfirmPassword').value;
if (!name) {
document.getElementById('registerNameError').style.display = 'block';
valid = false;
} else {
document.getElementById('registerNameError').style.display = 'none';
}
if (!username) {
document.getElementById('registerUsernameError').style.display = 'block';
valid = false;
} else {
document.getElementById('registerUsernameError').style.display = 'none';
}
// ユーザー名の重複チェック
if (users.find(u => u.username === username)) {
document.getElementById('registerUsernameError').textContent = 'このユーザー名は既に使用されています';
document.getElementById('registerUsernameError').style.display = 'block';
valid = false;
} else {
document.getElementById('registerUsernameError').style.display = 'none';
}
if (!password) {
document.getElementById('registerPasswordError').style.display = 'block';
valid = false;
} else {
document.getElementById('registerPasswordError').style.display = 'none';
}
if (password !== confirmPassword) {
document.getElementById('registerConfirmPasswordError').style.display = 'block';
valid = false;
} else {
document.getElementById('registerConfirmPasswordError').style.display = 'none';
}
return valid;
}
function register() {
if (!validateRegisterForm()) {
return;
}
const name = document.getElementById('registerName').value;
const username = document.getElementById('registerUsername').value;
const password = document.getElementById('registerPassword').value;
users.push({ name, username, password, profileImage: null });
saveUsersToLocalStorage(); // ユーザー情報を保存
alert('登録が完了しました!ログインしてください。');
showLoginForm();
}
// プロフィール画像の処理
function loadProfileImage() {
const profileImg = document.getElementById('profileImg');
// プロフィール画像が設定されている場合はその画像を表示
if (currentUser.profileImage) {
profileImg.src = currentUser.profileImage;
} else {
// デフォルトのプロフィール画像を表示
profileImg.src = 'default_profile_img.jpg';
}
}
function uploadProfileImage() {
const input = document.getElementById('profileImageInput');
const file = input.files[0];
if (file) {
// FileReaderを使用して画像を読み込む
const reader = new FileReader();
reader.onload = function(e) {
// 読み込んだ画像をプロフィール画像として設定
currentUser.profileImage = e.target.result;
// プロフィール画像を更新して表示
loadProfileImage();
saveUsersToLocalStorage(); // プロフィール画像を保存
saveCurrentUserToLocalStorage(); // currentUserを更新
}
reader.readAsDataURL(file);
}
}
// AIBOT投稿を登録
function registerAiBotPost() {
const content = document.getElementById('aiBotContent').value;
if (content.trim() !== '') {
aiBotPosts.push(content);
saveAiBotPostsToLocalStorage();
alert("BOTの投稿が登録されました!");
document.getElementById('aiBotContent').value = ''; // 入力欄を空にする
}
}
// AIBOTが定期的に投稿
function postAiBotContent() {
if (aiBotPosts.length > 0) {
const content = aiBotPosts[Math.floor(Math.random() * aiBotPosts.length)];
const aiUser = {
name: 'BOT',
username: 'bot',
profileImage: 'default_ai_profile_img.jpg'
};
const post = {
id: Date.now(),
content: content,
author: aiUser.name,
authorUsername: aiUser.username,
authorProfileImage: aiUser.profileImage,
likes: 0,
comments: []
};
posts.unshift(post);
savePostsToLocalStorage();
displayTimeline();
}
}
setInterval(postAiBotContent, 500000); // 50,000ミリ秒 = 50秒
// マルコフ連鎖を使用した自動投稿BOT
function generateMarkovChainText(order = 2) {
const allTexts = posts.map(post => post.content).join(' ');
if (allTexts.length < 100) return null; // テキストが短すぎる場合は生成しない
const markov = new RiTa.Markov(order);
markov.addText(allTexts);
const sentences = markov.generate(1);
return sentences[0];
}
function postMarkovBotContent() {
const generatedText = generateMarkovChainText(3); // 階数を3に設定
if (generatedText) {
const botUser = {
name: 'MarkovBot',
username: 'markovbot',
profileImage: 'markov_bot_profile_img.jpg'
};
const post = {
id: Date.now(),
content: generatedText,
author: botUser.name,
authorUsername: botUser.username,
authorProfileImage: botUser.profileImage,
likes: 0,
comments: []
};
posts.unshift(post);
savePostsToLocalStorage();
displayTimeline();
}
}
setInterval(postMarkovBotContent, markovBotInterval); // マルコフ連鎖BOTの投稿間隔
// 投稿関連の関数
function createPost() {
const postContent = document.getElementById('postContent').value;
if (postContent.trim() !== '') {
const post = {
id: Date.now(),
content: postContent,
author: currentUser.name,
authorUsername: currentUser.username,
authorProfileImage: currentUser.profileImage,
likes: 0,
comments: [],
shares: 0
};
posts.unshift(post); // 最新の投稿を先頭に追加
savePostsToLocalStorage(); // 投稿を保存
displayTimeline();
document.getElementById('postContent').value = ''; // 投稿後、入力欄を空にする
}
}
function displayTimeline() {
const timeline = document.getElementById('timeline');
timeline.innerHTML = '';
posts.forEach(post => {
const postElement = document.createElement('div');
postElement.classList.add('card', 'mb-3');
postElement.innerHTML = `
<div class="card-body">
<div class="d-flex align-items-center mb-3">
<img src="${post.authorProfileImage || 'default_profile_img.jpg'}" class="profile-img mr-2" alt="プロフィール画像">
<div>
<strong>${post.author}</strong> (@${post.authorUsername})
${post.shared ? '<span class="badge badge-info ml-2">シェア</span>' : ''}
</div>
</div>
<p class="card-text">${post.content}</p>
${post.link ? `<a href="${post.link}" target="_blank" class="btn btn-link">続きを読む</a>` : ''}
<div class="d-flex justify-content-between">
<div>
<button onclick="likePost(${post.id})" class="btn btn-primary btn-sm"><i class="fas fa-thumbs-up"></i> いいね (${post.likes})</button>
<button onclick="toggleComments(${post.id})" class="btn btn-secondary btn-sm"><i class="fas fa-comments"></i> コメント (${post.comments.length})</button>
<button onclick="replyToPost(${post.id})" class="btn btn-info btn-sm"><i class="fas fa-reply"></i> 返信</button>
<button onclick="sharePost(${post.id})" class="btn btn-share btn-sm"><i class="fas fa-share"></i> シェア (${post.shares || 0})</button>
<button onclick="shareToTwitter(${post.id})" class="btn btn-share-twitter btn-sm"><i class="fab fa-twitter"></i> Xでシェア</button>
</div>
<small class="text-muted">${new Date(post.id).toLocaleString()}</small>
</div>
<div id="comments-${post.id}" class="comment-section mt-3" style="display: none;">
${post.comments.map(comment => `
<div class="card mb-2">
<div class="card-body">
<p><strong>${comment.author}</strong>: ${comment.content}</p>
</div>
</div>
`).join('')}
</div>
</div>
`;
timeline.appendChild(postElement);
});
}
// いいね機能
function likePost(postId) {
const post = posts.find(p => p.id === postId);
post.likes++;
savePostsToLocalStorage();
displayTimeline();
}
// コメント表示切替
function toggleComments(postId) {
const commentSection = document.getElementById(`comments-${postId}`);
commentSection.style.display = commentSection.style.display === 'none' ? 'block' : 'none';
}
// リプライ機能
function replyToPost(postId) {
const modal = document.getElementById('replyModal');
modal.dataset.postId = postId;
$('#replyModal').modal('show');
}
function postReply() {
const postId = parseInt(document.getElementById('replyModal').dataset.postId);
const post = posts.find(p => p.id === postId);
const replyContent = document.getElementById('replyContent').value;
if (replyContent.trim() !== '') {
post.comments.push({ author: currentUser.name, content: replyContent });
$('#replyModal').modal('hide');
savePostsToLocalStorage();
displayTimeline();
} else {
alert('返信を入力してください。');
}
}
// 投稿のシェア機能
function sharePost(postId) {
const post = posts.find(p => p.id === postId);
if (post) {
const sharedPost = {
...post,
id: Date.now(),
author: currentUser.name,
authorUsername: currentUser.username,
authorProfileImage: currentUser.profileImage,
shared: true,
likes: 0,
comments: [],
shares: post.shares ? post.shares + 1 : 1
};
posts.unshift(sharedPost);
savePostsToLocalStorage();
displayTimeline();
alert('投稿をシェアしました。');
}
}
// X(旧Twitter)にシェアする機能
function shareToTwitter(postId) {
const post = posts.find(p => p.id === postId);
if (post) {
let shareText = post.content;
if (post.link) {
shareText += ' ' + post.link;
}
const shareUrl = `https://twitter.com/intent/tweet?text=${encodeURIComponent(shareText)}&url=${encodeURIComponent(window.location.href)}`;
window.open(shareUrl, '_blank');
}
}
// FEEDの登録と自動投稿機能
function registerFeed() {
const feedUrl = document.getElementById('feedUrl').value;
if (feedUrl.trim() !== '') {
feeds.push(feedUrl);
saveFeedsToLocalStorage(); // フィード情報を保存
alert('RSSフィードが登録されました!');
document.getElementById('feedUrl').value = ''; // 登録後、入力欄を空にする
} else {
document.getElementById('feedUrlError').style.display = 'block';
}
}
function fetchFeeds() {
feeds.forEach(feedUrl => {
fetch(`https://api.rss2json.com/v1/api.json?rss_url=${encodeURIComponent(feedUrl)}`)
.then(response => response.json())
.then(data => {
data.items.forEach(item => {
// 同じ投稿が既に存在するかチェック
if (!posts.some(p => p.link === item.link)) {
const post = {
id: Date.now() + Math.random(), // 重複しないIDを生成
content: item.title,
link: item.link, // リンクを追加
author: 'FEEDBOT',
authorUsername: 'feedbot',
authorProfileImage: 'feedbot_profile_img.jpg', // FEEDBOTのプロフィール画像を設定
likes: 0,
comments: []
};
posts.unshift(post); // 最新の投稿を先頭に追加
savePostsToLocalStorage(); // 投稿を保存
}
});
displayTimeline(); // タイムラインを表示
})
.catch(error => console.error('RSSフィードの取得エラー:', error));
});
}
function setFeedInterval() {
const intervalInput = document.getElementById('feedInterval').value;
if (intervalInput && parseInt(intervalInput) > 0) {
feedFetchInterval = parseInt(intervalInput) * 1000; // ミリ秒に変換
clearInterval(feedFetchTimer);
feedFetchTimer = setInterval(fetchFeeds, feedFetchInterval);
alert(`自動投稿の間隔が${intervalInput}秒に設定されました。`);
} else {
alert('有効な間隔を入力してください(1以上の数字)。');
}
}
// ページロード時にフィードの自動取得を開始
function startFeedFetch() {
feedFetchTimer = setInterval(fetchFeeds, feedFetchInterval);
}
// 初期化
function init() {
loadUsersFromLocalStorage();
loadPostsFromLocalStorage();
loadFeedsFromLocalStorage();
loadAiBotPostsFromLocalStorage();
loadCurrentUserFromLocalStorage();
if (currentUser) {
showProfile();
} else {
hideAll();
document.getElementById('loginForm').style.display = 'block';
}
displayTimeline();
startFeedFetch(); // フィードの自動取得を開始
}
// ページロード時に初期化
window.onload = init;
</script>
</body>
</html>
chat.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ローカルチャットシステム</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
}
.chat-container {
width: 80%;
max-width: 600px;
margin: 50px auto;
background-color: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
border-radius: 8px;
overflow: hidden;
display: flex;
flex-direction: column;
height: 600px;
}
.chat-header {
background-color: #007bff;
color: white;
padding: 10px;
text-align: center;
font-size: 18px;
}
.chat-messages {
flex-grow: 1;
overflow-y: scroll;
padding: 10px;
background-color: #fafafa;
}
.chat-message {
margin-bottom: 10px;
display: flex;
align-items: center;
}
.chat-message .username {
font-weight: bold;
margin-right: 5px;
}
.message-content {
padding: 8px;
background-color: #e9ecef;
border-radius: 5px;
flex-grow: 1;
}
.message-time {
font-size: 12px;
text-align: right;
margin-left: 10px;
color: #888;
}
.chat-input {
display: flex;
border-top: 1px solid #ddd;
}
.chat-input input {
width: 100%;
padding: 10px;
border: none;
outline: none;
font-size: 16px;
}
.chat-input button {
padding: 10px;
background-color: #007bff;
color: white;
border: none;
cursor: pointer;
font-size: 16px;
}
</style>
</head>
<body>
<div class="chat-container">
<div class="chat-header">
ローカルチャットシステム
</div>
<div class="chat-messages" id="chat-messages">
<!-- メッセージがここに表示される -->
</div>
<div class="chat-input">
<input type="text" id="chat-input" placeholder="メッセージを入力...">
<button id="send-button">送信</button>
</div>
</div>
<script>
const messagesContainer = document.getElementById('chat-messages');
const inputField = document.getElementById('chat-input');
const sendButton = document.getElementById('send-button');
// ユーザー情報
const users = ['ユーザー1', 'ユーザー2'];
let currentUserIndex = 0;
// メッセージを追加する関数
function addMessage(content, username, time = new Date().toLocaleTimeString()) {
const messageDiv = document.createElement('div');
messageDiv.classList.add('chat-message');
const userSpan = document.createElement('span');
userSpan.classList.add('username');
userSpan.textContent = username;
messageDiv.appendChild(userSpan);
const messageContent = document.createElement('div');
messageContent.classList.add('message-content');
messageContent.textContent = content;
messageDiv.appendChild(messageContent);
const timeSpan = document.createElement('span');
timeSpan.classList.add('message-time');
timeSpan.textContent = time;
messageDiv.appendChild(timeSpan);
messagesContainer.appendChild(messageDiv);
// スクロールを最新メッセージに合わせる
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}
// 送信ボタンのクリックイベント
sendButton.addEventListener('click', function() {
const message = inputField.value;
if (message.trim() !== '') {
const username = users[currentUserIndex];
currentUserIndex = (currentUserIndex + 1) % users.length; // ユーザーを切り替え
addMessage(message, username); // メッセージを表示
inputField.value = ''; // 入力フィールドをクリア
}
});
// エンターキーで送信できるように
inputField.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
sendButton.click();
}
});
</script>
</body>
</html>
タスク管理.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AIベースのタスク管理アプリ</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f9;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
}
h1 {
color: #333;
}
.task-container {
width: 90%;
max-width: 1200px;
padding: 20px;
}
.task-form {
display: flex;
flex-direction: column;
margin-bottom: 20px;
}
.task-form input, .task-form textarea {
margin-bottom: 10px;
padding: 10px;
font-size: 16px;
border: 1px solid #ccc;
border-radius: 5px;
}
.task-form button {
padding: 10px;
background-color: #28a745;
color: #fff;
border: none;
border-radius: 5px;
cursor: pointer;
}
.task-form button:hover {
background-color: #218838;
}
.kanban-board {
display: flex;
justify-content: space-around;
}
.kanban-column {
background-color: #f8f9fa;
padding: 20px;
width: 30%;
border-radius: 10px;
min-height: 300px;
}
.kanban-column h2 {
text-align: center;
}
.task-list {
margin-top: 10px;
}
.task-item {
display: flex;
justify-content: space-between;
background-color: #e9ecef;
margin-bottom: 10px;
padding: 10px;
border-radius: 5px;
}
.task-item.high {
background-color: #ffcccc;
}
.task-item.medium {
background-color: #fff3cd;
}
.task-item.low {
background-color: #d4edda;
}
.task-item button {
background-color: #dc3545;
color: #fff;
border: none;
border-radius: 5px;
cursor: pointer;
}
.task-item button:hover {
background-color: #c82333;
}
</style>
</head>
<body>
<h1>タスク管理</h1>
<div class="task-container">
<form class="task-form" id="taskForm">
<input type="text" id="taskTitle" placeholder="タスクタイトル" required>
<textarea id="taskDescription" placeholder="タスク詳細" rows="4"></textarea>
<input type="date" id="taskDueDate" required>
<button type="submit">タスクを追加</button>
</form>
<div class="kanban-board">
<div class="kanban-column" id="notStarted">
<h2>未着手</h2>
<div class="task-list" id="notStartedList"></div>
</div>
<div class="kanban-column" id="inProgress">
<h2>進行中</h2>
<div class="task-list" id="inProgressList"></div>
</div>
<div class="kanban-column" id="completed">
<h2>完了</h2>
<div class="task-list" id="completedList"></div>
</div>
</div>
</div>
<script>
let tasks = JSON.parse(localStorage.getItem('tasks')) || [];
// 優先度予測(ルールベース)
function predictPriority(taskDueDate) {
const daysLeft = (new Date(taskDueDate) - new Date()) / (1000 * 60 * 60 * 24);
if (daysLeft < 2) {
return 'High'; // 緊急度が高い
} else if (daysLeft < 7) {
return 'Medium'; // 1週間以内
} else {
return 'Low'; // 余裕がある
}
}
// タスクをローカルストレージに保存
function saveTasks() {
localStorage.setItem('tasks', JSON.stringify(tasks));
}
// タスク表示
function loadTasks() {
const notStartedList = document.getElementById('notStartedList');
const inProgressList = document.getElementById('inProgressList');
const completedList = document.getElementById('completedList');
notStartedList.innerHTML = '';
inProgressList.innerHTML = '';
completedList.innerHTML = '';
tasks.forEach(task => {
const taskItem = document.createElement('div');
taskItem.classList.add('task-item', task.priority.toLowerCase());
taskItem.setAttribute('draggable', true);
taskItem.innerHTML = `
<div>
<strong>${task.title}</strong>
<p>${task.description}</p>
<small>期限: ${new Date(task.dueDate).toLocaleDateString()}</small>
<p>優先度: ${task.priority}</p>
</div>
<button onclick="deleteTask('${task.id}')">削除</button>
`;
taskItem.addEventListener('dragstart', (e) => {
e.dataTransfer.setData('text/plain', task.id);
});
if (task.status === 'notStarted') {
notStartedList.appendChild(taskItem);
} else if (task.status === 'inProgress') {
inProgressList.appendChild(taskItem);
} else if (task.status === 'completed') {
completedList.appendChild(taskItem);
}
});
}
// タスク追加
document.getElementById('taskForm').addEventListener('submit', (e) => {
e.preventDefault();
const title = document.getElementById('taskTitle').value;
const description = document.getElementById('taskDescription').value;
const dueDate = document.getElementById('taskDueDate').value;
const priority = predictPriority(dueDate);
const newTask = {
id: Date.now().toString(),
title,
description,
dueDate,
priority,
status: 'notStarted' // 初期状態は未着手
};
tasks.push(newTask);
saveTasks();
document.getElementById('taskForm').reset();
loadTasks();
});
// タスク削除
function deleteTask(taskId) {
tasks = tasks.filter(task => task.id !== taskId);
saveTasks();
loadTasks();
}
// ドラッグ&ドロップの設定
document.querySelectorAll('.kanban-column').forEach(column => {
column.addEventListener('dragover', (e) => {
e.preventDefault();
});
column.addEventListener('drop', (e) => {
const taskId = e.dataTransfer.getData('text/plain');
const newStatus = column.id;
const task = tasks.find(task => task.id === taskId);
task.status = newStatus;
saveTasks();
loadTasks();
});
});
// ページ読み込み時にタスクを表示
loadTasks();
</script>
</body>
</html>
ドメイン取得サイト.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Domain Acquisition</title> <style> body { font-family: Arial, sans-serif; background-color: #f4f4f4; margin: 0; padding: 0; display: flex; justify-content: center; align-items: center; height: 100vh; } .container { background-color: #fff; padding: 20px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); border-radius: 8px; text-align: center; width: 100%; max-width: 600px; } h1 { margin-bottom: 20px; } input[type="text"] { width: 80%; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-radius: 5px; font-size: 16px; } button { padding: 10px 20px; border: none; background-color: #007BFF; color: white; font-size: 16px; border-radius: 5px; cursor: pointer; } button:hover { background-color: #0056b3; } .result { margin-top: 20px; } .loading { display: none; margin-top: 20px; } .domain-list { margin-top: 20px; } .domain-list ul { list-style-type: none; padding: 0; } .domain-list li { background-color: #f9f9f9; margin: 10px 0; padding: 10px; border-radius: 5px; border: 1px solid #ddd; text-align: left; display: flex; justify-content: space-between; } .price { color: green; } .purchase-link { text-decoration: none; background-color: #28a745; color: white; padding: 5px 10px; border-radius: 5px; } .error { color: red; margin-top: 20px; } @media (max-width: 600px) { input[type="text"] { width: 100%; } } </style> </head> <body> <div class="container"> <h1>Check Domain Availability</h1> <form id="domain-form"> <input type="text" id="domain-name" placeholder="Enter domain name" required> <button type="submit">Search</button> </form> <div class="loading" id="loading"> <p>Searching...</p> <img src="https://i.gifer.com/ZZ5H.gif" alt="Loading" width="50"> </div> <div class="result" id="result"></div> <div class="error" id="error"></div> <div class="domain-list" id="domain-list"></div> </div> <script> const form = document.getElementById('domain-form'); const resultDiv = document.getElementById('result'); const loadingDiv = document.getElementById('loading'); const errorDiv = document.getElementById('error'); const domainListDiv = document.getElementById('domain-list'); form.addEventListener('submit', function (event) { event.preventDefault(); const domainName = document.getElementById('domain-name').value.trim(); // フィールドをリセット resultDiv.innerHTML = ''; errorDiv.innerHTML = ''; domainListDiv.innerHTML = ''; loadingDiv.style.display = 'block'; // ローディング表示 if (validateDomainName(domainName)) { // ダミーデータの使用例(実際にはAPIを呼び出します) setTimeout(() => { loadingDiv.style.display = 'none'; // ローディング終了 // 検索結果の仮表示 const available = Math.random() > 0.5; // ランダムに結果を生成 if (available) { resultDiv.innerHTML = `<strong>${domainName}</strong> is available!`; // 他のTLDを提案し、価格と購入リンクを表示 const suggestions = [ { tld: '.com', price: '$10.99', link: 'https://buydomain.com/com' }, { tld: '.net', price: '$9.99', link: 'https://buydomain.com/net' }, { tld: '.org', price: '$11.99', link: 'https://buydomain.com/org' }, { tld: '.info', price: '$8.99', link: 'https://buydomain.com/info' }, { tld: '.co', price: '$12.99', link: 'https://buydomain.com/co' } ]; let domainList = '<ul>'; suggestions.forEach(({ tld, price, link }) => { domainList += `<li>${domainName}${tld} <span class="price">${price}</span> <a href="${link}" target="_blank" class="purchase-link">Buy</a></li>`; }); domainList += '</ul>'; domainListDiv.innerHTML = domainList; } else { resultDiv.innerHTML = `<strong>${domainName}</strong> is already taken.`; } }, 2000); // 実際のAPIではこのタイミングで結果を取得 } else { errorDiv.innerHTML = 'Please enter a valid domain name. It should follow the format: example.com'; loadingDiv.style.display = 'none'; // エラー時はローディングを停止 } }); // ドメイン名のバリデーション関数 function validateDomainName(domain) { const domainPattern = /^[a-zA-Z0-9-]{1,63}\.[a-zA-Z]{2,}$/; return domainPattern.test(domain); } </script> </body> </html>
Bootstrapフッターを配置
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<title>My Site</title>
</head>
<body>
<header class="bg-primary text-center text-light p-5">
<h1 class="fs-3">My Admin</h1>
</header>
<div class="container mt-5">
<section class="row">
<section class="col-md-4 mb-5">
こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。
</section>
<section class="col-md-8">
こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。
</section>
</section>
</div>
<footer class="bg-secondary text-center text-light p-5 mt-5">
(c) chodomeyuhei
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW"
crossorigin="anonymous"></script>
</body>
</html>
myblog.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>私のブログ</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
.navbar {
background-color: #333;
color: #fff;
padding: 15px;
display: flex;
justify-content: space-between;
align-items: center;
}
.navbar a {
color: #fff;
text-decoration: none;
padding: 0 15px;
}
.navbar a:hover {
text-decoration: underline;
}
.navbar .menu-toggle {
display: none;
}
.navbar .menu {
display: flex;
}
.navbar .menu .dropdown {
position: relative;
display: inline-block;
}
.navbar .menu .dropdown-content {
display: none;
position: absolute;
background-color: #444;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
.navbar .menu .dropdown-content a {
color: #fff;
padding: 12px 16px;
text-decoration: none;
display: block;
}
.navbar .menu .dropdown-content a:hover {
background-color: #555;
}
.navbar .menu .dropdown:hover .dropdown-content {
display: block;
}
.custom-banner {
background-color: #f0f0f0;
text-align: center;
padding: 60px 20px;
}
.custom-banner h1 {
color: #333;
margin: 0;
font-size: 2.5em;
}
.content {
padding: 20px;
}
.post {
border-bottom: 1px solid #ddd;
padding: 20px 0;
transition: background-color 0.3s;
}
.post:hover {
background-color: #f9f9f9;
}
.post h2 {
margin: 0;
color: #333;
}
.post p {
margin: 10px 0 0;
color: #666;
}
.footer {
background-color: #333;
color: #fff;
text-align: center;
padding: 10px;
position: fixed;
width: 100%;
bottom: 0;
}
.contact-form {
max-width: 600px;
margin: 20px auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
background-color: #fff;
}
.contact-form label {
display: block;
margin-bottom: 5px;
color: #333;
}
.contact-form input, .contact-form textarea {
width: 100%;
padding: 10px;
margin-bottom: 10px;
border: 1px solid #ddd;
border-radius: 3px;
}
.contact-form button {
background-color: #333;
color: #fff;
padding: 10px 20px;
border: none;
border-radius: 3px;
cursor: pointer;
}
.contact-form button:hover {
background-color: #555;
}
@media (max-width: 600px) {
.navbar .menu-toggle {
display: block;
cursor: pointer;
}
.navbar .menu {
display: none;
flex-direction: column;
width: 100%;
}
.navbar .menu a {
padding: 10px;
border-top: 1px solid #444;
}
.navbar .menu.open {
display: flex;
}
}
</style>
</head>
<body>
<div class="navbar">
<div>私のブログ</div>
<div class="menu-toggle">メニュー</div>
<div class="menu">
<a href="#home">ホーム</a>
<a href="#about">紹介</a>
<a href="#posts">記事</a>
<a href="#contact">お問い合わせ</a>
<div class="dropdown">
<a href="#more">もっと</a>
<div class="dropdown-content">
<a href="#link1">リンク 1</a>
<a href="#link2">リンク 2</a>
<a href="#link3">リンク 3</a>
</div>
</div>
</div>
</div>
<div class="custom-banner">
<h1>私のブログへようこそ</h1>
</div>
<div class="content" id="home">
<h2>ホーム</h2>
<p>ここはホームセクションです。</p>
</div>
<div class="content" id="about">
<h2>紹介</h2>
<p>ここは紹介セクションです。</p>
</div>
<div class="content" id="posts">
<h2>記事</h2>
<div class="post">
<h2>記事タイトル 1</h2>
<p>この記事の概要や内容がここに表示されます。</p>
</div>
<div class="post">
<h2>記事タイトル 2</h2>
<p>この記事の概要や内容がここに表示されます。</p>
</div>
<!-- 追加の記事をここに追加 -->
</div>
<div class="content" id="contact">
<h2>お問い合わせ</h2>
<form class="contact-form">
<label for="name">名前:</label>
<input type="text" id="name" name="name" required>
<label for="email">メールアドレス:</label>
<input type="email" id="email" name="email" required>
<label for="message">メッセージ:</label>
<textarea id="message" name="message" rows="5" required></textarea>
<button type="submit">送信</button>
</form>
</div>
<div class="footer">
© 2024 私のブログ. All rights reserved.
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const menuToggle = document.querySelector('.menu-toggle');
const menu = document.querySelector('.menu');
const contactForm = document.querySelector('.contact-form');
menuToggle.addEventListener('click', function() {
menu.classList.toggle('open');
});
contactForm.addEventListener('submit', function(event) {
event.preventDefault();
alert('フォームが送信されました!');
// ここでフォームのデータを送信する処理を追加できます
});
alert('ブログへようこそ!');
});
</script>
</body>
</html>
ELDER
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ELDER</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet">
<style>
body {
padding-top: 20px;
background-color: #f8f9fa;
}
.card {
margin-bottom: 20px;
}
.profile-img {
width: 50px;
height: 50px;
object-fit: cover;
border-radius: 50%;
}
.comment-section {
margin-top: 20px;
}
.navbar {
margin-bottom: 20px;
}
.form-error {
color: red;
font-size: 0.9em;
}
</style>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">SNS</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="#" onclick="showLoginForm()">ログイン</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" onclick="showRegisterForm()">登録</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" onclick="showProfile()" style="display: none;" id="navProfile">プロフィール</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" onclick="logout()" style="display: none;" id="navLogout">ログアウト</a>
</li>
</ul>
</div>
</nav>
<div class="container">
<h1 class="text-center mb-4">ソーシャルネットワーキングサービス</h1>
<!-- ログインフォーム -->
<div id="loginForm" class="card w-50 mx-auto">
<div class="card-body">
<h2 class="card-title text-center mb-4">ログイン</h2>
<div class="form-group">
<input type="text" id="loginUsername" class="form-control" placeholder="ユーザー名">
<span id="loginUsernameError" class="form-error" style="display: none;">ユーザー名を入力してください</span>
</div>
<div class="form-group">
<input type="password" id="loginPassword" class="form-control" placeholder="パスワード">
<span id="loginPasswordError" class="form-error" style="display: none;">パスワードを入力してください</span>
</div>
<button onclick="login()" class="btn btn-primary btn-block">ログイン</button>
<button onclick="showRegisterForm()" class="btn btn-secondary btn-block">登録</button>
</div>
</div>
<!-- 登録フォーム -->
<div id="registerForm" class="card w-50 mx-auto" style="display: none;">
<div class="card-body">
<h2 class="card-title text-center mb-4">登録</h2>
<div class="form-group">
<input type="text" id="registerName" class="form-control" placeholder="氏名">
<span id="registerNameError" class="form-error" style="display: none;">氏名を入力してください</span>
</div>
<div class="form-group">
<input type="text" id="registerUsername" class="form-control" placeholder="ユーザー名">
<span id="registerUsernameError" class="form-error" style="display: none;">ユーザー名を入力してください</span>
</div>
<div class="form-group">
<input type="password" id="registerPassword" class="form-control" placeholder="パスワード">
<span id="registerPasswordError" class="form-error" style="display: none;">パスワードを入力してください</span>
</div>
<div class="form-group">
<input type="password" id="registerConfirmPassword" class="form-control" placeholder="パスワードを確認">
<span id="registerConfirmPasswordError" class="form-error" style="display: none;">パスワードが一致しません</span>
</div>
<button onclick="register()" class="btn btn-primary btn-block">登録</button>
<button onclick="showLoginForm()" class="btn btn-secondary btn-block">ログインに戻る</button>
</div>
</div>
<!-- プロフィール -->
<div id="profile" class="card w-50 mx-auto" style="display: none;">
<div class="card-body">
<h2 class="card-title text-center mb-4">プロフィール</h2>
<div class="text-center mb-3">
<img id="profileImg" class="profile-img" src="default_profile_img.jpg" alt="プロフィール画像">
</div>
<p class="text-center mb-2"><strong>氏名:</strong> <span id="profileName"></span></p>
<p class="text-center mb-4"><strong>ユーザー名:</strong> <span id="profileUsername"></span></p>
<div class="form-group">
<input type="file" id="profileImageInput" accept="image/*" class="form-control-file">
</div>
<button onclick="uploadProfileImage()" class="btn btn-primary btn-block"><i class="fas fa-upload"></i> プロフィール画像をアップロード</button>
<button id="followButton" onclick="toggleFollow()" class="btn btn-primary btn-block"></button>
<button id="messageButton" onclick="openDirectMessageModal()" class="btn btn-primary btn-block">ダイレクトメッセージを送信</button>
<button onclick="logout()" class="btn btn-danger btn-block"><i class="fas fa-sign-out-alt"></i> ログアウト</button>
</div>
</div>
<!-- 投稿フォーム -->
<div id="postForm" class="card w-75 mx-auto" style="display: none;">
<div class="card-body">
<h2 class="card-title text-center mb-4">投稿を作成</h2>
<div class="form-group">
<textarea id="postContent" class="form-control" rows="3" placeholder="今何を考えていますか?"></textarea>
</div>
<button onclick="createPost()" class="btn btn-primary btn-block">投稿</button>
</div>
</div>
<!-- FEED登録フォーム -->
<div id="feedForm" class="card w-75 mx-auto" style="display: none;">
<div class="card-body">
<h2 class="card-title text-center mb-4">FEEDを登録</h2>
<div class="form-group">
<input type="text" id="feedUrl" class="form-control" placeholder="RSSフィードのURL">
<span id="feedUrlError" class="form-error" style="display: none;">RSSフィードのURLを入力してください</span>
</div>
<button onclick="registerFeed()" class="btn btn-primary btn-block">登録</button>
</div>
</div>
<!-- タイムライン -->
<div id="timeline" class="w-75 mx-auto mt-4"></div>
</div>
<!-- リプライモーダル -->
<div class="modal fade" id="replyModal" tabindex="-1" role="dialog" aria-labelledby="replyModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="replyModalLabel">投稿に返信</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="閉じる">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<textarea id="replyContent" class="form-control" rows="3" placeholder="返信をここに書いてください..."></textarea>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">閉じる</button>
<button type="button" onclick="postReply()" class="btn btn-primary">返信</button>
</div>
</div>
</div>
</div>
<!-- ダイレクトメッセージモーダル -->
<div class="modal fade" id="directMessageModal" tabindex="-1" role="dialog" aria-labelledby="directMessageModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="directMessageModalLabel">ダイレクトメッセージを送信</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="閉じる">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<select id="recipient" class="form-control">
<option value="">送信先を選択</option>
<!-- ユーザーリストがここに追加される -->
</select>
<textarea id="directMessageContent" class="form-control mt-2" rows="3" placeholder="メッセージをここに書いてください..."></textarea>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">閉じる</button>
<button type="button" onclick="sendDirectMessage()" class="btn btn-primary">送信</button>
</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.4/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<script>
let currentUser = null; // 現在のログインユーザー
let users = []; // ユーザーの配列
let posts = []; // 投稿の配列
let feeds = []; // フィードの配列
// ローカルストレージにユーザー情報を保存
function saveUsersToLocalStorage() {
localStorage.setItem('users', JSON.stringify(users));
}
// ローカルストレージに投稿情報を保存
function savePostsToLocalStorage() {
localStorage.setItem('posts', JSON.stringify(posts));
}
// ローカルストレージにフィード情報を保存
function saveFeedsToLocalStorage() {
localStorage.setItem('feeds', JSON.stringify(feeds));
}
// ローカルストレージからユーザー情報を読み込み
function loadUsersFromLocalStorage() {
const storedUsers = localStorage.getItem('users');
if (storedUsers) {
users = JSON.parse(storedUsers);
}
}
// ローカルストレージから投稿情報を読み込み
function loadPostsFromLocalStorage() {
const storedPosts = localStorage.getItem('posts');
if (storedPosts) {
posts = JSON.parse(storedPosts);
}
}
// ローカルストレージからフィード情報を読み込み
function loadFeedsFromLocalStorage() {
const storedFeeds = localStorage.getItem('feeds');
if (storedFeeds) {
feeds = JSON.parse(storedFeeds);
}
}
function showLoginForm() {
hideAll();
document.getElementById('loginForm').style.display = 'block';
}
function showRegisterForm() {
hideAll();
document.getElementById('registerForm').style.display = 'block';
}
function validateLoginForm() {
let valid = true;
const username = document.getElementById('loginUsername').value;
const password = document.getElementById('loginPassword').value;
if (!username) {
document.getElementById('loginUsernameError').style.display = 'block';
valid = false;
} else {
document.getElementById('loginUsernameError').style.display = 'none';
}
if (!password) {
document.getElementById('loginPasswordError').style.display = 'block';
valid = false;
} else {
document.getElementById('loginPasswordError').style.display = 'none';
}
return valid;
}
function login() {
if (!validateLoginForm()) {
return;
}
const username = document.getElementById('loginUsername').value;
const password = document.getElementById('loginPassword').value;
const user = users.find(u => u.username === username && u.password === password);
if (user) {
currentUser = user;
showProfile();
} else {
alert('ユーザー名またはパスワードが間違っています。');
}
}
function logout() {
currentUser = null;
hideAll();
document.getElementById('loginForm').style.display = 'block';
document.getElementById('navProfile').style.display = 'none';
document.getElementById('navLogout').style.display = 'none';
}
function validateRegisterForm() {
let valid = true;
const name = document.getElementById('registerName').value;
const username = document.getElementById('registerUsername').value;
const password = document.getElementById('registerPassword').value;
const confirmPassword = document.getElementById('registerConfirmPassword').value;
if (!name) {
document.getElementById('registerNameError').style.display = 'block';
valid = false;
} else {
document.getElementById('registerNameError').style.display = 'none';
}
if (!username) {
document.getElementById('registerUsernameError').style.display = 'block';
valid = false;
} else {
document.getElementById('registerUsernameError').style.display = 'none';
}
if (!password) {
document.getElementById('registerPasswordError').style.display = 'block';
valid = false;
} else {
document.getElementById('registerPasswordError').style.display = 'none';
}
if (password !== confirmPassword) {
document.getElementById('registerConfirmPasswordError').style.display = 'block';
valid = false;
} else {
document.getElementById('registerConfirmPasswordError').style.display = 'none';
}
return valid;
}
function register() {
if (!validateRegisterForm()) {
return;
}
const name = document.getElementById('registerName').value;
const username = document.getElementById('registerUsername').value;
const password = document.getElementById('registerPassword').value;
users.push({ name, username, password, following: false });
saveUsersToLocalStorage(); // ユーザー情報を保存
alert('登録が完了しました!ログインしてください。');
showLoginForm();
}
function showProfile() {
hideAll();
document.getElementById('profile').style.display = 'block';
document.getElementById('profileName').textContent = currentUser.name;
document.getElementById('profileUsername').textContent = currentUser.username;
document.getElementById('postForm').style.display = 'block';
document.getElementById('feedForm').style.display = 'block';
loadProfileImage(); // プロフィール画像をロード
displayTimeline(); // タイムラインを表示
updateFollowButton(); // フォローボタンの表示を更新
loadDirectMessageRecipients(); // ダイレクトメッセージの送信先をロード
document.getElementById('navProfile').style.display = 'block';
document.getElementById('navLogout').style.display = 'block';
}
// プロフィール画像をロード
function loadProfileImage() {
const profileImg = document.getElementById('profileImg');
// プロフィール画像が設定されている場合はその画像を表示
if (currentUser.profileImage) {
profileImg.src = currentUser.profileImage;
} else {
// デフォルトのプロフィール画像を表示
profileImg.src = 'default_profile_img.jpg';
}
}
// プロフィール画像をアップロード
function uploadProfileImage() {
const input = document.getElementById('profileImageInput');
const file = input.files[0];
if (file) {
// FileReaderを使用して画像を読み込む
const reader = new FileReader();
reader.onload = function(e) {
// 読み込んだ画像をプロフィール画像として設定
currentUser.profileImage = e.target.result;
// プロフィール画像を更新して表示
loadProfileImage();
saveUsersToLocalStorage(); // プロフィール画像を保存
}
reader.readAsDataURL(file);
}
}
// フォローボタンの更新
function updateFollowButton() {
const followButton = document.getElementById('followButton');
if (currentUser.following) {
followButton.textContent = 'フォロー解除';
} else {
followButton.textContent = 'フォロー';
}
saveUsersToLocalStorage(); // フォロー状態を保存
}
// フォローの切り替え
function toggleFollow() {
currentUser.following = !currentUser.following;
updateFollowButton();
}
// ダイレクトメッセージの送信先をロード
function loadDirectMessageRecipients() {
const select = document.getElementById('recipient');
select.innerHTML = '<option value="">送信先を選択</option>';
users.forEach(user => {
if (user !== currentUser) {
const option = document.createElement('option');
option.value = user.username;
option.textContent = user.name;
select.appendChild(option);
}
});
}
// ダイレクトメッセージのモーダルを開く
function openDirectMessageModal() {
$('#directMessageModal').modal('show');
}
// ダイレクトメッセージを送信
function sendDirectMessage() {
const recipientUsername = document.getElementById('recipient').value;
const messageContent = document.getElementById('directMessageContent').value;
if (recipientUsername && messageContent.trim() !== '') {
const recipient = users.find(user => user.username === recipientUsername);
if (recipient) {
alert(`メッセージを${recipient.name}に送信しました: ${messageContent}`);
$('#directMessageModal').modal('hide');
} else {
alert('送信先が見つかりません。');
}
} else {
alert('送信先を選択し、メッセージを入力してください。');
}
}
function createPost() {
const postContent = document.getElementById('postContent').value;
if (postContent.trim() !== '') {
const post = {
id: Date.now(),
content: postContent,
author: currentUser.name,
authorUsername: currentUser.username,
authorProfileImage: currentUser.profileImage, // プロフィール画像を追加
likes: 0,
comments: []
};
posts.unshift(post); // 最新の投稿を先頭に追加
savePostsToLocalStorage(); // 投稿を保存
displayTimeline();
document.getElementById('postContent').value = ''; // 投稿後、入力欄を空にする
}
}
function registerFeed() {
const feedUrl = document.getElementById('feedUrl').value;
if (feedUrl.trim() !== '') {
feeds.push(feedUrl);
saveFeedsToLocalStorage(); // フィード情報を保存
alert('RSSフィードが登録されました!');
document.getElementById('feedUrl').value = ''; // 登録後、入力欄を空にする
} else {
document.getElementById('feedUrlError').style.display = 'block';
}
}
function displayTimeline() {
const timeline = document.getElementById('timeline');
timeline.innerHTML = '';
posts.forEach(post => {
const postElement = document.createElement('div');
postElement.classList.add('card', 'mb-3');
postElement.innerHTML = `
<div class="card-body">
<div class="d-flex align-items-center mb-3">
<img src="${post.authorProfileImage || 'default_profile_img.jpg'}" class="profile-img mr-2" alt="プロフィール画像">
<div>
<strong>${post.author}</strong> (@${post.authorUsername})
</div>
</div>
<p class="card-text">${post.content}</p>
${post.link ? `<a href="${post.link}" target="_blank" class="btn btn-link">続きを読む</a>` : ''}
<div class="d-flex justify-content-between">
<div>
<button onclick="likePost(${post.id})" class="btn btn-primary btn-sm"><i class="fas fa-thumbs-up"></i> いいね (${post.likes})</button>
<button onclick="toggleComments(${post.id})" class="btn btn-secondary btn-sm"><i class="fas fa-comments"></i> コメント (${post.comments.length})</button>
<button onclick="replyToPost(${post.id})" class="btn btn-info btn-sm"><i class="fas fa-reply"></i> 返信</button>
</div>
<small class="text-muted">${new Date(post.id).toLocaleString()}</small>
</div>
<div id="comments-${post.id}" class="comment-section mt-3" style="display: none;">
${post.comments.map(comment => `
<div class="card mb-2">
<div class="card-body">
<p><strong>${comment.author}</strong>: ${comment.content}</p>
</div>
</div>
`).join('')}
</div>
</div>
`;
timeline.appendChild(postElement);
});
}
function likePost(postId) {
const post = posts.find(p => p.id === postId);
post.likes++;
savePostsToLocalStorage(); // いいねを保存
displayTimeline();
}
function toggleComments(postId) {
const commentSection = document.getElementById(`comments-${postId}`);
commentSection.style.display = commentSection.style.display === 'none' ? 'block' : 'none';
}
function replyToPost(postId) {
const modal = document.getElementById('replyModal');
modal.dataset.postId = postId;
$('#replyModal').modal('show');
}
function postReply() {
const postId = parseInt(document.getElementById('replyModal').dataset.postId);
const post = posts.find(p => p.id === postId);
const replyContent = document.getElementById('replyContent').value;
if (replyContent.trim() !== '') {
post.comments.push({ author: currentUser.name, content: replyContent });
$('#replyModal').modal('hide');
savePostsToLocalStorage(); // コメントを保存
displayTimeline();
} else {
alert('返信を入力してください。');
}
}
function fetchFeeds() {
feeds.forEach(feedUrl => {
fetch(`https://api.rss2json.com/v1/api.json?rss_url=${encodeURIComponent(feedUrl)}`)
.then(response => response.json())
.then(data => {
data.items.forEach(item => {
const post = {
id: Date.now() + Math.random(), // 重複しないIDを生成
content: item.title,
link: item.link, // リンクを追加
author: 'RSSフィード',
authorUsername: 'rssfeed',
authorProfileImage: 'default_profile_img.jpg', // プロフィール画像を設定
likes: 0,
comments: []
};
posts.unshift(post); // 最新の投稿を先頭に追加
savePostsToLocalStorage(); // 投稿を保存
});
displayTimeline(); // タイムラインを表示
})
.catch(error => console.error('Error fetching RSS feed:', error));
});
}
function hideAll() {
document.getElementById('loginForm').style.display = 'none';
document.getElementById('registerForm').style.display = 'none';
document.getElementById('profile').style.display = 'none';
document.getElementById('postForm').style.display = 'none';
document.getElementById('feedForm').style.display = 'none';
}
// 初期データをローカルストレージから読み込む
loadUsersFromLocalStorage();
loadPostsFromLocalStorage();
loadFeedsFromLocalStorage();
// 初期ログイン画面表示
hideAll();
document.getElementById('loginForm').style.display = 'block';
// 1時間ごとにRSSフィードをフェッチして自動投稿
setInterval(fetchFeeds, 5); // 3600000ミリ秒 = 1時間
</script>
</body>
</html>
RSSの機能を使えるようにしました
Q&Aサイト
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Q&A Site</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f4f4f4;
}
h1, h2, h3 {
color: #333;
}
#question-list, #add-question, #question-detail {
margin-bottom: 20px;
}
#questions {
list-style-type: none;
padding: 0;
}
.question, .answer {
background-color: #fff;
padding: 10px;
margin-bottom: 10px;
border-radius: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
}
.answer {
margin-left: 20px;
}
form {
display: flex;
flex-direction: column;
}
form input, form textarea {
margin-bottom: 10px;
padding: 10px;
border-radius: 5px;
border: 1px solid #ccc;
}
form button {
padding: 10px;
border: none;
border-radius: 5px;
background-color: #333;
color: #fff;
cursor: pointer;
}
form button:hover {
background-color: #555;
}
.hidden {
display: none;
}
.action-buttons {
display: flex;
gap: 10px;
}
</style>
</head>
<body>
<h1>Q&A Site</h1>
<div id="question-list">
<h2>Questions</h2>
<ul id="questions"></ul>
</div>
<div id="add-question">
<h2>Add a Question</h2>
<form id="question-form">
<input type="text" id="question-title" placeholder="Title" required>
<textarea id="question-body" placeholder="Question" required></textarea>
<button type="submit">Add Question</button>
</form>
</div>
<div id="question-detail" class="hidden">
<h2 id="detail-title"></h2>
<p id="detail-body"></p>
<div class="action-buttons">
<button id="edit-question-button">Edit</button>
<button id="delete-question-button">Delete</button>
</div>
<div id="edit-question" class="hidden">
<h3>Edit Question</h3>
<form id="edit-question-form">
<input type="text" id="edit-question-title" required>
<textarea id="edit-question-body" required></textarea>
<button type="submit">Save Changes</button>
</form>
</div>
<h3>Answers</h3>
<ul id="answers"></ul>
<h3>Add an Answer</h3>
<form id="answer-form">
<input type="text" id="answer-name" placeholder="Your name" required>
<textarea id="answer-body" placeholder="Your answer" required></textarea>
<button type="submit">Add Answer</button>
</form>
<button id="back-button">Back to Questions</button>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
let questions = [];
let currentQuestionIndex = null;
const questionForm = document.getElementById('question-form');
const questionTitle = document.getElementById('question-title');
const questionBody = document.getElementById('question-body');
const questionsList = document.getElementById('questions');
const questionDetail = document.getElementById('question-detail');
const detailTitle = document.getElementById('detail-title');
const detailBody = document.getElementById('detail-body');
const answersList = document.getElementById('answers');
const answerForm = document.getElementById('answer-form');
const answerName = document.getElementById('answer-name');
const answerBody = document.getElementById('answer-body');
const backButton = document.getElementById('back-button');
const editQuestionButton = document.getElementById('edit-question-button');
const deleteQuestionButton = document.getElementById('delete-question-button');
const editQuestionForm = document.getElementById('edit-question-form');
const editQuestionTitle = document.getElementById('edit-question-title');
const editQuestionBody = document.getElementById('edit-question-body');
questionForm.addEventListener('submit', (e) => {
e.preventDefault();
const newQuestion = {
title: questionTitle.value,
body: questionBody.value,
answers: []
};
questions.push(newQuestion);
displayQuestions();
questionTitle.value = '';
questionBody.value = '';
});
answerForm.addEventListener('submit', (e) => {
e.preventDefault();
const newAnswer = {
name: answerName.value,
body: answerBody.value
};
questions[currentQuestionIndex].answers.push(newAnswer);
displayQuestionDetail(currentQuestionIndex);
answerName.value = '';
answerBody.value = '';
});
editQuestionButton.addEventListener('click', () => {
editQuestionForm.classList.remove('hidden');
editQuestionTitle.value = questions[currentQuestionIndex].title;
editQuestionBody.value = questions[currentQuestionIndex].body;
});
editQuestionForm.addEventListener('submit', (e) => {
e.preventDefault();
questions[currentQuestionIndex].title = editQuestionTitle.value;
questions[currentQuestionIndex].body = editQuestionBody.value;
displayQuestionDetail(currentQuestionIndex);
displayQuestions();
editQuestionForm.classList.add('hidden');
});
deleteQuestionButton.addEventListener('click', () => {
questions.splice(currentQuestionIndex, 1);
questionDetail.classList.add('hidden');
document.getElementById('question-list').classList.remove('hidden');
document.getElementById('add-question').classList.remove('hidden');
displayQuestions();
});
backButton.addEventListener('click', () => {
questionDetail.classList.add('hidden');
document.getElementById('question-list').classList.remove('hidden');
document.getElementById('add-question').classList.remove('hidden');
});
function displayQuestions() {
questionsList.innerHTML = '';
questions.forEach((question, index) => {
const li = document.createElement('li');
li.className = 'question';
li.innerHTML = `
<h3>${question.title}</h3>
<p>${question.body}</p>
<button onclick="viewQuestion(${index})">View Details</button>
`;
questionsList.appendChild(li);
});
}
window.viewQuestion = (index) => {
currentQuestionIndex = index;
displayQuestionDetail(index);
document.getElementById('question-list').classList.add('hidden');
document.getElementById('add-question').classList.add('hidden');
questionDetail.classList.remove('hidden');
};
function displayQuestionDetail(index) {
const question = questions[index];
detailTitle.textContent = question.title;
detailBody.textContent = question.body;
displayAnswers(index);
}
function displayAnswers(index) {
const question = questions[index];
answersList.innerHTML = '';
question.answers.forEach((answer, answerIndex) => {
const li = document.createElement('li');
li.className = 'answer';
li.innerHTML = `
<p><strong>${answer.name}:</strong> ${answer.body}</p>
<button onclick="editAnswer(${index}, ${answerIndex})">Edit</button>
<button onclick="deleteAnswer(${index}, ${answerIndex})">Delete</button>
`;
answersList.appendChild(li);
});
}
window.editAnswer = (questionIndex, answerIndex) => {
const answer = questions[questionIndex].answers[answerIndex];
const newBody = prompt("Edit your answer:", answer.body);
if (newBody) {
answer.body = newBody;
displayAnswers(questionIndex);
}
};
window.deleteAnswer = (questionIndex, answerIndex) => {
questions[questionIndex].answers.splice(answerIndex, 1);
displayAnswers(questionIndex);
};
displayQuestions();
});
</script>
</body>
</html>
ニコニコ動画風サイト
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ニコニコ動画風サイト</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f4f4f4;
}
header {
background-color: #333;
color: #fff;
padding: 10px 20px;
text-align: center;
}
nav {
background-color: #555;
color: #fff;
display: flex;
justify-content: space-around;
padding: 10px 0;
}
nav a {
color: #fff;
text-decoration: none;
padding: 10px 20px;
}
main {
display: flex;
margin: 20px;
}
aside {
width: 25%;
background-color: #fff;
padding: 20px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
section {
width: 75%;
padding: 20px;
}
.video-player {
background-color: #000;
height: 400px;
margin-bottom: 20px;
position: relative;
}
.video-player video {
width: 100%;
height: 100%;
}
footer {
background-color: #333;
color: #fff;
text-align: center;
padding: 10px 0;
}
.comments {
list-style: none;
padding: 0;
}
.comments li {
background-color: #fff;
margin-bottom: 10px;
padding: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.comment-form {
display: flex;
margin-top: 20px;
}
.comment-form input {
flex: 1;
padding: 10px;
margin-right: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
.comment-form button {
padding: 10px 20px;
border: none;
background-color: #333;
color: #fff;
border-radius: 5px;
cursor: pointer;
}
.thumbnail {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.thumbnail img {
width: 120px;
height: 90px;
margin-right: 10px;
}
.login-form, .register-form, .upload-form, .profile {
background-color: #fff;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.login-form h2, .register-form h2, .upload-form h2, .profile h2 {
margin-top: 0;
}
.login-form input, .register-form input, .upload-form input {
width: 100%;
padding: 10px;
margin-bottom: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
.login-form button, .register-form button, .upload-form button {
width: 100%;
padding: 10px;
border: none;
background-color: #333;
color: #fff;
border-radius: 5px;
cursor: pointer;
}
.search-form {
display: flex;
justify-content: center;
margin: 20px 0;
}
.search-form input {
width: 70%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
.search-form button {
padding: 10px 20px;
border: none;
background-color: #333;
color: #fff;
border-radius: 5px;
cursor: pointer;
}
.rating {
display: flex;
align-items: center;
margin-top: 10px;
}
.rating button {
border: none;
background: none;
cursor: pointer;
font-size: 1.2em;
margin-right: 10px;
}
.rating span {
margin-right: 20px;
}
</style>
</head>
<body>
<header>
<h1>ニコニコ動画風サイト</h1>
</header>
<nav>
<a href="index.html">ホーム</a>
<a href="ranking.html">ランキング</a>
<a href="categories.html">カテゴリー</a>
<a href="mypage.html">マイページ</a>
</nav>
<div class="search-form">
<input type="text" id="searchInput" placeholder="検索...">
<button onclick="search()">検索</button>
</div>
<main>
<aside>
<h2>おすすめ動画</h2>
<div class="thumbnail">
<a href="video.html"><img src="thumbnail1.jpg" alt="動画1"></a>
<a href="video.html">動画1のタイトル</a>
</div>
<div class="thumbnail">
<a href="video.html"><img src="thumbnail2.jpg" alt="動画2"></a>
<a href="video.html">動画2のタイトル</a>
</div>
<div class="thumbnail">
<a href="video.html"><img src="thumbnail3.jpg" alt="動画3"></a>
<a href="video.html">動画3のタイトル</a>
</div>
<div class="thumbnail">
<a href="video.html"><img src="thumbnail4.jpg" alt="動画4"></a>
<a href="video.html">動画4のタイトル</a>
</div>
</aside>
<section>
<div class="video-player">
<video controls>
<source src="sample.mp4" type="video/mp4">
あなたのブラウザは動画タグに対応していません。
</video>
</div>
<h2>動画タイトル</h2>
<p>動画の説明文がここに入ります。</p>
<div class="rating">
<button onclick="like()">👍</button><span id="likeCount">0</span>
<button onclick="dislike()">👎</button><span id="dislikeCount">0</span>
</div>
<h3>コメント</h3>
<ul class="comments" id="comments">
<li><span class="timestamp">12:34</span> コメント1</li>
<li><span class="timestamp">12:35</span> コメント2</li>
<li><span class="timestamp">12:36</span> コメント3</li>
<li><span class="timestamp">12:37</span> コメント4</li>
</ul>
<div class="comment-form">
<input type="text" id="commentInput" placeholder="コメントを入力してください">
<button onclick="addComment()">コメントを投稿</button>
</div>
</section>
</main>
<footer>
</footer>
<!-- Register Form -->
<div class="register-form">
<h2>ユーザー登録</h2>
<input type="text" id="registerUsername" placeholder="ユーザー名">
<input type="password" id="registerPassword" placeholder="パスワード">
<button onclick="register()">登録</button>
</div>
<!-- Login Form -->
<div class="login-form">
<h2>ログイン</h2>
<input type="text" id="loginUsername" placeholder="ユーザー名">
<input type="password" id="loginPassword" placeholder="パスワード">
<button onclick="login()">ログイン</button>
</div>
<!-- Upload Form -->
<div class="upload-form">
<h2>動画アップロード</h2>
<input type="file" id="uploadVideo">
<input type="text" id="uploadTitle" placeholder="タイトル">
<button onclick="upload()">アップロード</button>
</div>
<!-- Profile Page -->
<div class="profile">
<h2>プロフィール</h2>
<p>ユーザー名: <span id="profileUsername"></span></p>
<p>登録日: <span id="profileDate"></span></p>
</div>
<script>
let likeCount = 0;
let dislikeCount = 0;
function addComment() {
var commentInput = document.getElementById('commentInput');
var commentText = commentInput.value.trim();
if (commentText !== "") {
var commentsList = document.getElementById('comments');
var newComment = document.createElement('li');
var timestamp = new Date().toLocaleTimeString();
newComment.innerHTML = '<span class="timestamp">' + timestamp + '</span> ' + commentText;
commentsList.appendChild(newComment);
commentInput.value = "";
}
}
function like() {
likeCount++;
document.getElementById('likeCount').innerText = likeCount;
}
function dislike() {
dislikeCount++;
document.getElementById('dislikeCount').innerText = dislikeCount;
}
function search() {
var searchInput = document.getElementById('searchInput').value.trim();
if (searchInput !== "") {
alert('検索結果: ' + searchInput);
}
}
function register() {
var username = document.getElementById('registerUsername').value.trim();
var password = document.getElementById('registerPassword').value.trim();
if (username !== "" && password !== "") {
alert('ユーザー登録が完了しました: ' + username);
localStorage.setItem('username', username);
localStorage.setItem('password', password);
document.getElementById('registerUsername').value = "";
document.getElementById('registerPassword').value = "";
}
}
function login() {
var username = document.getElementById('loginUsername').value.trim();
var password = document.getElementById('loginPassword').value.trim();
var storedUsername = localStorage.getItem('username');
var storedPassword = localStorage.getItem('password');
if (username === storedUsername && password === storedPassword) {
alert('ログイン成功');
document.getElementById('profileUsername').innerText = username;
document.getElementById('profileDate').innerText = new Date().toLocaleDateString();
document.getElementById('loginUsername').value = "";
document.getElementById('loginPassword').value = "";
} else {
alert('ユーザー名またはパスワードが間違っています');
}
}
function upload() {
var video = document.getElementById('uploadVideo').files[0];
var title = document.getElementById('uploadTitle').value.trim();
if (video && title !== "") {
alert('動画アップロードが完了しました: ' + title);
document.getElementById('uploadVideo').value = "";
document.getElementById('uploadTitle').value = "";
}
}
</script>
</body>
</html>