Verse.html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Verse - 次世代ソーシャルネットワーク</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/rita/1.3.63/rita-full.min.js"></script>
    <style>
        body { font-family: Arial, sans-serif; margin: 0; padding: 0; background: #f0f0f0; }
        header, .footer { background: linear-gradient(45deg, #6a11cb, #2575fc); color: white; text-align: center; padding: 20px; }
        .nav-container { background: #2575fc; display: flex; justify-content: center; padding: 10px; position: sticky; top: 0; }
        .nav-menu a { color: white; text-decoration: none; margin: 0 10px; }
        .content { max-width: 900px; margin: 20px auto; background: white; padding: 20px; border-radius: 8px; }
        .cta-button { background: #2575fc; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer; }
        .profile-icon { width: 80px; height: 80px; border-radius: 50%; object-fit: cover; }
        .dark-mode { background: #1e1e1e; color: #ddd; }
        .timeline { margin-top: 20px; }
        .timeline-post { border: 1px solid #ddd; border-radius: 8px; padding: 10px; margin-bottom: 10px; background: #fff; }
        .post-controls { display: flex; gap: 10px; }
        .search-box { width: 100%; margin-bottom: 10px; }
    </style>
    <script>
        let posts = JSON.parse(localStorage.getItem('posts') || '[]');
        let feedUrls = JSON.parse(localStorage.getItem('feedUrls') || '[]');
        let botInterval = null;
        let feedInterval = null;

        function saveData() {
            localStorage.setItem('posts', JSON.stringify(posts));
            localStorage.setItem('feedUrls', JSON.stringify(feedUrls));
        }

        function createPost(content) {
            posts.unshift({ content: content, likes: 0 });
            saveData();
            renderTimeline();
        }

        function createUserPost() {
            const content = document.getElementById('postContent').value.trim();
            if(content) {
                createPost(content);
                document.getElementById('postContent').value = '';
            }
        }

        function likePost(index) {
            posts[index].likes++;
            saveData();
            renderTimeline();
        }

        function deletePost(index) {
            posts.splice(index, 1);
            saveData();
            renderTimeline();
        }

        function searchPosts() {
            const query = document.getElementById('searchInput').value.trim().toLowerCase();
            renderTimeline(query);
        }

        function renderTimeline(filter = '') {
            const container = document.getElementById('timeline');
            container.innerHTML = '';
            posts.filter(post => post.content.toLowerCase().includes(filter)).forEach((post, index) => {
                const postDiv = document.createElement('div');
                postDiv.className = 'timeline-post';
                postDiv.innerHTML = `
                    <p>${post.content}</p>
                    <div class='post-controls'>
                        <button class='btn btn-sm btn-primary' onclick='likePost(${index})'>❤️ いいね (${post.likes})</button>
                        <button class='btn btn-sm btn-danger' onclick='deletePost(${index})'>🗑️ 削除</button>
                    </div>
                `;
                container.appendChild(postDiv);
            });
        }

        function toggleDarkMode() {
            document.body.classList.toggle('dark-mode');
        }

        function uploadProfileIcon(event) {
            const file = event.target.files[0];
            if(file) {
                const reader = new FileReader();
                reader.onload = function(e) {
                    document.getElementById('profile-icon').src = e.target.result;
                    showTimeline();
                };
                reader.readAsDataURL(file);
            }
        }

        function showTimeline() {
            document.getElementById('profile-section').style.display = 'none';
            document.getElementById('post-section').style.display = 'block';
            document.getElementById('timeline').style.display = 'block';
        }

        function showProfile() {
            document.getElementById('profile-section').style.display = 'block';
            document.getElementById('post-section').style.display = 'none';
            document.getElementById('timeline').style.display = 'none';
        }

        function postBotMessage() {
            const content = document.getElementById('botContent').value.trim();
            if(content) {
                createPost(`🤖 BOT: ${content}`);
                document.getElementById('botContent').value = '';
            }
        }

        function generateMarkovText() {
            const combinedText = posts.map(p => p.content).join(' ');
            if(combinedText.length < 20) return "BOTの投稿データが不足しています。";

            const markov = new RiTa.Markov(3);
            markov.addText(combinedText);
            const sentences = markov.generate(1);
            return sentences[0] ? sentences[0] : "自然な文章の生成に失敗しました。";
        }

        function postMarkovBot() {
            const text = generateMarkovText();
            createPost(`🤖 MarkovBOT: ${text}`);
        }

        function startBotAutoPost(intervalSec) {
            if(botInterval) clearInterval(botInterval);
            botInterval = setInterval(postMarkovBot, intervalSec * 1000);
            alert(`マルコフ連鎖BOTの自動投稿間隔を${intervalSec}秒に設定しました。`);
        }

        function registerFeedUrl() {
            const url = document.getElementById('feedUrl').value.trim();
            if(url) {
                feedUrls.push(url);
                saveData();
                alert('RSSフィードURLを登録しました。');
                document.getElementById('feedUrl').value = '';
            }
        }

        async function fetchAllFeeds() {
            for(const url of feedUrls) {
                try {
                    const response = await fetch(`https://api.rss2json.com/v1/api.json?rss_url=${encodeURIComponent(url)}`);
                    const data = await response.json();
                    data.items.forEach(item => {
                        createPost(`📡 FEED: ${item.title} - ${item.link}`);
                    });
                } catch (error) {
                    console.error('RSSフィード取得エラー:', error);
                }
            }
        }

        function startFeedAutoPost(intervalSec) {
            if(feedInterval) clearInterval(feedInterval);
            feedInterval = setInterval(fetchAllFeeds, intervalSec * 1000);
            alert(`RSSフィードの自動投稿間隔を${intervalSec}秒に設定しました。`);
        }

        window.onload = function() {
            renderTimeline();
        };
    </script>
</head>
<body>
    <header>
        <h1>Verse</h1>
        <button class="cta-button" onclick="toggleDarkMode()">🌙 ダークモード切替</button>
    </header>

    <div class="nav-container">
        <div class="nav-menu">
            <a href="#" onclick="showTimeline()">ホーム</a>
            <a href="#" onclick="showProfile()">プロフィール</a>
        </div>
    </div>

    <div class="content">
        <section id="profile-section" style="display:none;">
            <h2>プロフィール</h2>
            <img id="profile-icon" src="https://via.placeholder.com/80" alt="プロフィールアイコン" class="profile-icon"><br><br>
            <input type="file" accept="image/*" onchange="uploadProfileIcon(event)">
        </section>

        <section id="post-section">
            <h2>新規投稿</h2>
            <textarea id="postContent" class="form-control" placeholder="いま何してる?"></textarea><br>
            <button class="cta-button" onclick="createUserPost()">投稿</button>

            <h2>BOT投稿登録</h2>
            <textarea id="botContent" class="form-control" placeholder="BOTに投稿させたい内容"></textarea><br>
            <button class="cta-button" onclick="postBotMessage()">BOT投稿登録</button><br><br>

            <input type="number" id="botIntervalSec" placeholder="BOTの自動投稿間隔(秒)">
            <button class="cta-button" onclick="startBotAutoPost(parseInt(document.getElementById('botIntervalSec').value))">マルコフ連鎖 自動投稿開始</button><br><br>

            <h2>RSSフィード登録</h2>
            <input type="text" id="feedUrl" class="form-control" placeholder="RSSフィードのURL"><br>
            <button class="cta-button" onclick="registerFeedUrl()">フィード登録</button><br><br>

            <input type="number" id="feedIntervalSec" placeholder="RSS自動投稿間隔(秒)">
            <button class="cta-button" onclick="startFeedAutoPost(parseInt(document.getElementById('feedIntervalSec').value))">RSS 自動投稿開始</button>
        </section>

        <input type="text" id="searchInput" class="form-control search-box" placeholder="投稿を検索..." onkeyup="searchPosts()">

        <section id="timeline" class="timeline"></section>
    </div>

    <div class="footer">&copy; 2025 Verse - 新しいつながりを創造する</div>
</body>
</html>

投稿者: chosuke

趣味はゲームやアニメや漫画などです

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です