{"id":25948,"date":"2025-03-31T11:07:12","date_gmt":"2025-03-31T02:07:12","guid":{"rendered":"http:\/\/www.tyosuke20xx.com\/blog\/?p=25948"},"modified":"2025-03-31T11:07:14","modified_gmt":"2025-03-31T02:07:14","slug":"twitter%e9%a2%a8%e3%82%b5%e3%82%a4%e3%83%88","status":"publish","type":"post","link":"http:\/\/www.tyosuke20xx.com\/blog\/?p=25948","title":{"rendered":"Twitter\u98a8\u30b5\u30a4\u30c8"},"content":{"rendered":"\n<pre class=\"wp-block-code\"><code>&lt;!DOCTYPE html>\n&lt;html lang=\"ja\">\n&lt;head>\n  &lt;meta charset=\"UTF-8\">\n  &lt;title>Twitter\u98a8\u30b5\u30a4\u30c8\uff08\u9ad8\u5ea6\u62e1\u5f35\u7248\uff09&lt;\/title>\n  &lt;style>\n    \/* \u5168\u4f53\u8a2d\u5b9a *\/\n    body {\n      margin: 0;\n      padding: 0;\n      font-family: sans-serif;\n      background-color: #f5f8fa;\n    }\n\n    header {\n      position: fixed;\n      top: 0;\n      left: 0;\n      width: 100%;\n      height: 50px;\n      background-color: #1da1f2;\n      display: flex;\n      align-items: center;\n      padding: 0 20px;\n      color: #fff;\n      font-size: 20px;\n      font-weight: bold;\n      box-sizing: border-box;\n      z-index: 10;\n    }\n\n    \/* \u30ec\u30a4\u30a2\u30a6\u30c8\u7528\u30b3\u30f3\u30c6\u30ca *\/\n    .container {\n      display: flex;\n      width: 100%;\n      max-width: 1200px;\n      margin: 60px auto 0; \/* \u30d8\u30c3\u30c0\u30fc\u5206\u3060\u3051\u4e0b\u306b\u4f59\u767d\u3092\u3068\u308b *\/\n      box-sizing: border-box;\n    }\n\n    \/* \u5de6\u30b5\u30a4\u30c9\u30d0\u30fc\uff08\u30ca\u30d3\u30b2\u30fc\u30b7\u30e7\u30f3\uff09 *\/\n    .sidebar {\n      width: 20%;\n      max-width: 200px;\n      padding: 10px;\n      box-sizing: border-box;\n    }\n\n    .nav-item {\n      margin: 10px 0;\n      font-size: 18px;\n    }\n\n    .nav-item a {\n      text-decoration: none;\n      color: #1da1f2;\n      cursor: pointer;\n    }\n\n    .profile-settings {\n      margin-top: 20px;\n      padding: 10px;\n      background-color: #fff;\n      border: 1px solid #e6ecf0;\n      border-radius: 5px;\n    }\n\n    .profile-settings input {\n      width: 100%;\n      margin-bottom: 5px;\n      font-size: 14px;\n      padding: 5px;\n      box-sizing: border-box;\n    }\n\n    .profile-settings button {\n      border: none;\n      background-color: #1da1f2;\n      color: #fff;\n      font-size: 14px;\n      padding: 5px 10px;\n      border-radius: 4px;\n      cursor: pointer;\n    }\n\n    \/* \u30e1\u30a4\u30f3\u30bf\u30a4\u30e0\u30e9\u30a4\u30f3\u90e8\u5206 *\/\n    .feed {\n      width: 60%;\n      padding: 10px;\n      box-sizing: border-box;\n    }\n\n    .tweet-box {\n      background-color: #fff;\n      border: 1px solid #e6ecf0;\n      border-radius: 5px;\n      padding: 10px;\n      margin-bottom: 20px;\n    }\n\n    .tweet-box textarea {\n      width: 100%;\n      border: none;\n      resize: none;\n      font-size: 16px;\n      outline: none;\n      box-sizing: border-box;\n    }\n\n    .tweet-stats {\n      display: flex;\n      justify-content: space-between;\n      margin-top: 5px;\n      font-size: 14px;\n    }\n\n    .tweet-stats .char-count {\n      color: #657786;\n    }\n\n    .tweet-stats .error {\n      color: red;\n    }\n\n    .tweet-box .attach-label {\n      display: inline-block;\n      margin-top: 5px;\n      font-size: 14px;\n      color: #657786;\n    }\n\n    .tweet-box button {\n      margin-top: 10px;\n      padding: 8px 16px;\n      border: none;\n      background-color: #1da1f2;\n      color: #fff;\n      font-size: 16px;\n      border-radius: 5px;\n      cursor: pointer;\n    }\n\n    .tweet {\n      background-color: #fff;\n      border: 1px solid #e6ecf0;\n      border-radius: 5px;\n      padding: 10px;\n      margin-bottom: 10px;\n    }\n\n    .tweet-header {\n      display: flex;\n      align-items: center;\n      margin-bottom: 5px;\n      flex-wrap: wrap;\n    }\n\n    .tweet-header img.user-icon {\n      width: 40px;\n      height: 40px;\n      border-radius: 50%;\n      margin-right: 10px;\n    }\n\n    .tweet-header .name {\n      font-weight: bold;\n      margin-right: 5px;\n    }\n\n    .tweet-header .username {\n      color: #657786;\n      font-size: 14px;\n      margin-right: 5px;\n    }\n\n    .tweet-time {\n      font-size: 12px;\n      color: #657786;\n    }\n\n    .tweet-content {\n      font-size: 16px;\n      margin: 10px 0;\n      white-space: pre-wrap; \/* \u6539\u884c\u3092\u4fdd\u6301 *\/\n    }\n\n    .tweet-content img.attached-image {\n      max-width: 100%;\n      display: block;\n      margin-top: 5px;\n      border: 1px solid #ccc;\n    }\n\n    .tweet-footer {\n      display: flex;\n      justify-content: flex-start;\n      gap: 15px;\n      margin-top: 10px;\n      flex-wrap: wrap;\n    }\n\n    .tweet-footer button {\n      background: none;\n      border: none;\n      cursor: pointer;\n      font-size: 14px;\n      color: #657786;\n      display: flex;\n      align-items: center;\n      gap: 5px;\n    }\n\n    .tweet .replies-container {\n      margin-top: 10px;\n      border-left: 2px solid #e6ecf0;\n      padding-left: 10px;\n    }\n\n    \/* \u30ea\u30d7\u30e9\u30a4\u306e\u66f4\u306a\u308b\u968e\u5c64\u306f\u5c11\u3057\u305a\u3064\u5de6\u306b\u305a\u3089\u3059 *\/\n    .nested-reply {\n      margin-left: 20px;\n    }\n\n    \/* \u53f3\u30b5\u30a4\u30c9\u30d0\u30fc\uff08\u30a6\u30a3\u30b8\u30a7\u30c3\u30c8\uff09 *\/\n    .widgets {\n      width: 20%;\n      max-width: 250px;\n      padding: 10px;\n      box-sizing: border-box;\n    }\n\n    .search-box {\n      background-color: #fff;\n      border-radius: 20px;\n      padding: 8px 15px;\n      margin-bottom: 20px;\n      border: 1px solid #e6ecf0;\n      display: flex;\n      align-items: center;\n    }\n\n    .search-box input {\n      border: none;\n      outline: none;\n      width: 100%;\n      font-size: 16px;\n    }\n\n    .trends {\n      background-color: #fff;\n      border: 1px solid #e6ecf0;\n      border-radius: 5px;\n      padding: 10px;\n    }\n\n    .trends h3 {\n      margin-top: 0;\n    }\n\n    .trend-item {\n      margin-bottom: 10px;\n      font-size: 14px;\n    }\n\n    \/* \u30ea\u30f3\u30af\u98a8\u306e\u30c6\u30ad\u30b9\u30c8\u30c7\u30b6\u30a4\u30f3 *\/\n    .hashtag,\n    .mention {\n      color: #1da1f2;\n      text-decoration: none;\n      cursor: pointer;\n    }\n\n    .hashtag:hover,\n    .mention:hover {\n      text-decoration: underline;\n    }\n\n    \/* \u6298\u308a\u305f\u305f\u307f\u8868\u793a\u306e\u30dc\u30bf\u30f3 *\/\n    .toggle-replies-btn {\n      background: none;\n      color: #1da1f2;\n      border: none;\n      cursor: pointer;\n      font-size: 14px;\n      margin-top: 5px;\n      padding: 0;\n    }\n  &lt;\/style>\n&lt;\/head>\n&lt;body>\n  &lt;!-- \u30d8\u30c3\u30c0\u30fc -->\n  &lt;header>\n    Twitter\u98a8\u30b5\u30a4\u30c8\uff08\u9ad8\u5ea6\u62e1\u5f35\u7248\uff09\n  &lt;\/header>\n\n  &lt;!-- \u30e1\u30a4\u30f3\u30b3\u30f3\u30c6\u30f3\u30c4\u3092\u5de6\u53f3\u306b\u5206\u3051\u308b\u30b3\u30f3\u30c6\u30ca -->\n  &lt;div class=\"container\">\n\n    &lt;!-- \u5de6\u30b5\u30a4\u30c9\u30d0\u30fc -->\n    &lt;aside class=\"sidebar\">\n      &lt;div class=\"nav-item\">&lt;a href=\"#\">\u30db\u30fc\u30e0&lt;\/a>&lt;\/div>\n      &lt;div class=\"nav-item\">&lt;a href=\"#\">\u901a\u77e5&lt;\/a>&lt;\/div>\n      &lt;div class=\"nav-item\">&lt;a href=\"#\">\u8a2d\u5b9a&lt;\/a>&lt;\/div>\n\n      &lt;!-- \u7c21\u6613\u30d7\u30ed\u30d5\u30a3\u30fc\u30eb\u8a2d\u5b9a -->\n      &lt;div class=\"profile-settings\">\n        &lt;label for=\"displayName\">\u540d\u524d&lt;\/label>\n        &lt;input type=\"text\" id=\"displayName\" placeholder=\"\u3042\u306a\u305f\u306e\u8868\u793a\u540d\">\n        &lt;label for=\"userName\">\u30e6\u30fc\u30b6\u30fc\u540d(@\u306a\u3057\u3067)&lt;\/label>\n        &lt;input type=\"text\" id=\"userName\" placeholder=\"myAccount\">\n        &lt;button id=\"saveProfileBtn\">\u4fdd\u5b58&lt;\/button>\n      &lt;\/div>\n    &lt;\/aside>\n\n    &lt;!-- \u30bf\u30a4\u30e0\u30e9\u30a4\u30f3\u90e8\u5206 -->\n    &lt;main class=\"feed\">\n      &lt;!-- \u65b0\u898f\u30c4\u30a4\u30fc\u30c8\u5165\u529b\u30d5\u30a9\u30fc\u30e0 -->\n      &lt;div class=\"tweet-box\">\n        &lt;textarea rows=\"3\" placeholder=\"\u3044\u307e\u3069\u3046\u3057\u3066\u308b\uff1f (140\u6587\u5b57\u307e\u3067)\">&lt;\/textarea>\n        &lt;div class=\"tweet-stats\">\n          &lt;span class=\"char-count\">0 \/ 140&lt;\/span>\n          &lt;span class=\"error\">&lt;\/span>\n        &lt;\/div>\n        &lt;label class=\"attach-label\">\n          \u753b\u50cf\u3092\u6dfb\u4ed8:\n          &lt;input type=\"file\" class=\"attach-input\" accept=\"image\/*\">\n        &lt;\/label>\n        &lt;button class=\"tweet-submit-btn\">\u30c4\u30a4\u30fc\u30c8&lt;\/button>\n      &lt;\/div>\n    &lt;\/main>\n\n    &lt;!-- \u53f3\u30b5\u30a4\u30c9\u30d0\u30fc -->\n    &lt;aside class=\"widgets\">\n      &lt;!-- \u691c\u7d22\u30dc\u30c3\u30af\u30b9 -->\n      &lt;div class=\"search-box\">\n        &lt;input type=\"text\" placeholder=\"\u30ad\u30fc\u30ef\u30fc\u30c9\u691c\u7d22\">\n      &lt;\/div>\n\n      &lt;!-- \u30c8\u30ec\u30f3\u30c9\u8868\u793a -->\n      &lt;div class=\"trends\">\n        &lt;h3>\u4eca\u3069\u3046\u3057\u3066\u308b\uff1f&lt;\/h3>\n        &lt;div class=\"trend-item\">#\u6625\u306e\u8a2a\u308c&lt;\/div>\n        &lt;div class=\"trend-item\">#\u304a\u82b1\u898b&lt;\/div>\n        &lt;div class=\"trend-item\">#\u65b0\u5e74\u5ea6&lt;\/div>\n      &lt;\/div>\n    &lt;\/aside>\n  &lt;\/div>\n\n  &lt;script>\n    \/\/ =======================\n    \/\/      \u5b9a\u6570\u30fb\u5909\u6570\u8a2d\u5b9a\n    \/\/ =======================\n    const TWEET_MAX_LENGTH = 140;\n    const feedContainer = document.querySelector('.feed');\n    const tweetTextarea = document.querySelector('.tweet-box textarea');\n    const tweetButton = document.querySelector('.tweet-submit-btn');\n    const charCountEl = document.querySelector('.char-count');\n    const errorEl = document.querySelector('.error');\n    const attachInput = document.querySelector('.attach-input');\n\n    const displayNameInput = document.getElementById('displayName');\n    const userNameInput = document.getElementById('userName');\n    const saveProfileBtn = document.getElementById('saveProfileBtn');\n\n    \/\/ LocalStorage\u304b\u3089\u30c4\u30a4\u30fc\u30c8\u4e00\u89a7\u3092\u8aad\u307f\u8fbc\u307f\uff08\u306a\u3051\u308c\u3070\u7a7a\u914d\u5217\uff09\n    let tweets = JSON.parse(localStorage.getItem('tweets-advanced') || '&#91;]');\n\n    \/\/ \u30e6\u30fc\u30b6\u30fc\u30d7\u30ed\u30d5\u30a3\u30fc\u30eb\u60c5\u5831\u3092LocalStorage\u304b\u3089\u8aad\u307f\u8fbc\u307f\n    let userProfile = JSON.parse(localStorage.getItem('userProfile-advanced') || '{}');\n    let currentName = userProfile.displayName || '\u3042\u306a\u305f';\n    let currentUserName = userProfile.userName || 'myAccount';\n\n    \/\/ \u30d5\u30a9\u30fc\u30e0\u306b\u53cd\u6620\n    displayNameInput.value = currentName;\n    userNameInput.value = currentUserName;\n\n    \/\/ =======================\n    \/\/   \u753b\u50cf\u30d5\u30a1\u30a4\u30eb\u53d6\u5f97\u7528\n    \/\/ =======================\n    let attachedImageBase64 = null;\n    attachInput.addEventListener('change', (e) => {\n      const file = e.target.files&#91;0];\n      if(!file) {\n        attachedImageBase64 = null;\n        return;\n      }\n      const reader = new FileReader();\n      reader.onload = () => {\n        attachedImageBase64 = reader.result;  \/\/ base64\u30c7\u30fc\u30bf\n      };\n      reader.readAsDataURL(file);\n    });\n\n    \/\/ =======================\n    \/\/   \u30b9\u30ec\u30c3\u30c9\u5b9f\u88c5\u306e\u305f\u3081\u306e\u30c4\u30a4\u30fc\u30c8\u69cb\u9020\n    \/\/ =======================\n    \/\/ tweet = {\n    \/\/   id: string (\u4e00\u610f\u306eID),\n    \/\/   name: string,\n    \/\/   userName: string,\n    \/\/   content: string,\n    \/\/   time: number (Date.now()),\n    \/\/   likes: number,\n    \/\/   retweets: number,\n    \/\/   image: string (base64) | null,\n    \/\/   replies: array of same structure\n    \/\/ }\n\n    \/\/ =======================\n    \/\/       \u30e6\u30fc\u30c6\u30a3\u30ea\u30c6\u30a3\n    \/\/ =======================\n    function escapeHtml(str) {\n      return str\n        .replace(\/&amp;\/g, \"&amp;amp;\")\n        .replace(\/&lt;\/g, \"&amp;lt;\")\n        .replace(\/>\/g, \"&amp;gt;\")\n        .replace(\/\"\/g, \"&amp;quot;\")\n        .replace(\/'\/g, \"&amp;#39;\");\n    }\n\n    \/\/ \u30cf\u30c3\u30b7\u30e5\u30bf\u30b0\/\u30e1\u30f3\u30b7\u30e7\u30f3\u306e\u30ea\u30f3\u30af\u5316\n    function linkify(text) {\n      let escaped = escapeHtml(text);\n      escaped = escaped.replace(\/#(\\w+)\/g, `&lt;a href=\"#\" class=\"hashtag\">#$1&lt;\/a>`);\n      escaped = escaped.replace(\/@(\\w+)\/g, `&lt;a href=\"#\" class=\"mention\">@$1&lt;\/a>`);\n      return escaped;\n    }\n\n    \/\/ \u30c4\u30a4\u30fc\u30c8\u3092LocalStorage\u306b\u4fdd\u5b58\n    function updateLocalStorage() {\n      localStorage.setItem('tweets-advanced', JSON.stringify(tweets));\n    }\n\n    \/\/ \u89aa\u30c4\u30a4\u30fc\u30c8\u307e\u305f\u306f\u30ea\u30d7\u30e9\u30a4\u5148\u3092\u691c\u7d22\u3059\u308b\u305f\u3081\u306e\u518d\u5e30\u95a2\u6570\n    function findTweetById(tweetArray, tweetId) {\n      for (const tw of tweetArray) {\n        if (tw.id === tweetId) {\n          return tw;\n        }\n        const childFound = findTweetById(tw.replies, tweetId);\n        if (childFound) {\n          return childFound;\n        }\n      }\n      return null;\n    }\n\n    \/\/ \u65b0\u3057\u3044\u30c4\u30a4\u30fc\u30c8\u3092\u4f5c\u6210 &amp; tweets\u914d\u5217\u306b\u767b\u9332\n    \/\/ parentId\u304c\u6307\u5b9a\u3055\u308c\u305f\u3089\u3001\u305d\u306e\u30c4\u30a4\u30fc\u30c8\u306ereplies\u306b\u8ffd\u52a0\u3059\u308b\n    function createNewTweet(content, parentId = null, imageBase64 = null) {\n      const newTweet = {\n        id: 'tw-' + Date.now() + '-' + Math.floor(Math.random() * 10000),\n        name: currentName,\n        userName: currentUserName,\n        content: content,\n        time: Date.now(),\n        likes: 0,\n        retweets: 0,\n        image: imageBase64,\n        replies: &#91;]\n      };\n      if (parentId) {\n        const parentTweet = findTweetById(tweets, parentId);\n        if (parentTweet) {\n          parentTweet.replies.unshift(newTweet);\n        }\n      } else {\n        tweets.unshift(newTweet);\n      }\n      updateLocalStorage();\n      renderTweets();\n    }\n\n    \/\/ =======================\n    \/\/      \u30c4\u30a4\u30fc\u30c8\u63cf\u753b\n    \/\/ =======================\n\n    \/\/ \u30c4\u30a4\u30fc\u30c81\u4ef6\u3092\u751f\u6210\u3059\u308bDOM\u8981\u7d20\u3092\u8fd4\u3059\uff08\u8fd4\u4fe1\u5206\u3082\u542b\u3081\u518d\u5e30\u7684\u306b\u751f\u6210\uff09\n    \/\/ depth: \u30b9\u30ec\u30c3\u30c9\u306e\u6df1\u3055\u306b\u5fdc\u3058\u3066\u5de6\u30de\u30fc\u30b8\u30f3\u306a\u3069\u3092\u8abf\u6574\u3057\u305f\u3044\u3068\u304d\u306b\u5229\u7528\n    function createTweetElement(tweet, depth = 0) {\n      const tweetDiv = document.createElement('div');\n      tweetDiv.classList.add('tweet');\n      if (depth >= 1) {\n        \/\/ 2\u6bb5\u76ee\u4ee5\u964d\u306e\u30ea\u30d7\u30e9\u30a4\u306a\u3089class\u3067\u5de6\u306b\u305a\u3089\u3059\n        tweetDiv.classList.add('nested-reply');\n      }\n\n      \/\/ \u65e5\u4ed8\u6587\u5b57\u5217\n      const timeString = new Date(tweet.time).toLocaleString('ja-JP', {\n        month: '2-digit',\n        day: '2-digit',\n        hour: '2-digit',\n        minute: '2-digit'\n      });\n\n      \/\/ \u672c\u6587\u306e\u30ea\u30f3\u30af\u5316\n      const contentHtml = linkify(tweet.content);\n\n      \/\/ \u753b\u50cf\u304c\u3042\u308b\u5834\u5408\n      const imageHtml = tweet.image\n        ? `&lt;img src=\"${tweet.image}\" alt=\"Attached Image\" class=\"attached-image\" \/>`\n        : '';\n\n      \/\/ \u81ea\u5206\u306e\u30c4\u30a4\u30fc\u30c8\u306a\u3089\u524a\u9664\u30dc\u30bf\u30f3\u3092\u8868\u793a\n      const isMyTweet = (tweet.name === currentName &amp;&amp; tweet.userName === currentUserName);\n      const deleteBtnHtml = isMyTweet\n        ? `&lt;button class=\"delete-btn\">\u524a\u9664&lt;\/button>`\n        : '';\n\n      tweetDiv.innerHTML = `\n        &lt;div class=\"tweet-header\">\n          &lt;img src=\"https:\/\/via.placeholder.com\/40\" alt=\"User Icon\" class=\"user-icon\" \/>\n          &lt;span class=\"name\">${escapeHtml(tweet.name)}&lt;\/span>\n          &lt;span class=\"username\">@${escapeHtml(tweet.userName)}&lt;\/span>\n          &lt;span class=\"tweet-time\">- ${timeString}&lt;\/span>\n        &lt;\/div>\n        &lt;div class=\"tweet-content\">\n          ${contentHtml}\n          ${imageHtml}\n        &lt;\/div>\n        &lt;div class=\"tweet-footer\">\n          &lt;button class=\"like-btn\">\n            &lt;span>\u3044\u3044\u306d&lt;\/span>\n            &lt;span class=\"like-count\">${tweet.likes}&lt;\/span>\n          &lt;\/button>\n          &lt;button class=\"retweet-btn\">\n            &lt;span>\u30ea\u30c4\u30a4\u30fc\u30c8&lt;\/span>\n            &lt;span class=\"retweet-count\">${tweet.retweets}&lt;\/span>\n          &lt;\/button>\n          &lt;button class=\"reply-btn\">\u8fd4\u4fe1&lt;\/button>\n          ${deleteBtnHtml}\n        &lt;\/div>\n      `;\n\n      \/\/ ---------- \u8fd4\u4fe1\u30d5\u30a9\u30fc\u30e0 &amp; \u30b9\u30ec\u30c3\u30c9\u8868\u793a ----------\n      \/\/ \u8fd4\u4fe1\u30b3\u30f3\u30c6\u30ca(\u6298\u308a\u305f\u305f\u307f\u5bfe\u8c61)\n      const repliesContainer = document.createElement('div');\n      repliesContainer.classList.add('replies-container');\n\n      \/\/ \u8fd4\u4fe1\u304c\u3042\u308b\u5834\u5408\u3001\u8868\u793a\/\u975e\u8868\u793a\u3092\u5207\u308a\u66ff\u3048\u308b\u30dc\u30bf\u30f3\u3092\u8a2d\u7f6e\n      if (tweet.replies &amp;&amp; tweet.replies.length > 0) {\n        const toggleRepliesBtn = document.createElement('button');\n        toggleRepliesBtn.classList.add('toggle-replies-btn');\n        toggleRepliesBtn.textContent = `\u8fd4\u4fe1\u3092\u8868\u793a (${tweet.replies.length})`;\n        tweetDiv.appendChild(toggleRepliesBtn);\n\n        \/\/ \u6298\u308a\u305f\u305f\u307f\u72b6\u614b\u7ba1\u7406\n        let isRepliesOpen = false;\n        toggleRepliesBtn.addEventListener('click', () => {\n          isRepliesOpen = !isRepliesOpen;\n          toggleRepliesBtn.textContent = isRepliesOpen\n            ? `\u8fd4\u4fe1\u3092\u975e\u8868\u793a`\n            : `\u8fd4\u4fe1\u3092\u8868\u793a (${tweet.replies.length})`;\n          repliesContainer.style.display = isRepliesOpen ? 'block' : 'none';\n        });\n      }\n\n      \/\/ \u8fd4\u4fe1\u30d5\u30a9\u30fc\u30e0\n      const replyForm = document.createElement('div');\n      replyForm.style.marginTop = '5px';\n      replyForm.innerHTML = `\n        &lt;textarea rows=\"2\" placeholder=\"\u8fd4\u4fe1\u3092\u5165\u529b...\" style=\"width: 100%; font-size:14px;\">&lt;\/textarea>\n        &lt;button class=\"reply-submit-btn\" style=\"margin-top:5px;\">\u8fd4\u4fe1\u3092\u6295\u7a3f&lt;\/button>\n      `;\n      replyForm.style.display = 'none'; \/\/ \u30c7\u30d5\u30a9\u30eb\u30c8\u306f\u975e\u8868\u793a\n      tweetDiv.appendChild(replyForm);\n\n      \/\/ \u30b9\u30ec\u30c3\u30c9\uff08\u8fd4\u4fe1\uff09\u306e\u518d\u5e30\u63cf\u753b\n      tweet.replies.forEach(replyTweet => {\n        const replyEl = createTweetElement(replyTweet, depth + 1);\n        repliesContainer.appendChild(replyEl);\n      });\n      repliesContainer.style.display = 'none'; \/\/ \u6700\u521d\u306f\u6298\u308a\u305f\u305f\u307f\n      tweetDiv.appendChild(repliesContainer);\n\n      \/\/ ========== \u5404\u7a2e\u30dc\u30bf\u30f3\u30a4\u30d9\u30f3\u30c8 ==========\n      \/\/ \u3044\u3044\u306d\n      const likeBtn = tweetDiv.querySelector('.like-btn');\n      const likeCountEl = tweetDiv.querySelector('.like-count');\n      likeBtn.addEventListener('click', () => {\n        tweet.likes++;\n        updateLocalStorage();\n        likeCountEl.textContent = tweet.likes;\n      });\n\n      \/\/ \u30ea\u30c4\u30a4\u30fc\u30c8\n      const retweetBtn = tweetDiv.querySelector('.retweet-btn');\n      const retweetCountEl = tweetDiv.querySelector('.retweet-count');\n      retweetBtn.addEventListener('click', () => {\n        tweet.retweets++;\n        updateLocalStorage();\n        retweetCountEl.textContent = tweet.retweets;\n      });\n\n      \/\/ \u8fd4\u4fe1\u30dc\u30bf\u30f3 -> \u30d5\u30a9\u30fc\u30e0\u8868\u793a\/\u975e\u8868\u793a\n      const replyBtn = tweetDiv.querySelector('.reply-btn');\n      replyBtn.addEventListener('click', () => {\n        replyForm.style.display = (replyForm.style.display === 'none') ? 'block' : 'none';\n      });\n\n      \/\/ \u8fd4\u4fe1\u6295\u7a3f\n      const replySubmitBtn = replyForm.querySelector('.reply-submit-btn');\n      const replyTextarea = replyForm.querySelector('textarea');\n      replySubmitBtn.addEventListener('click', () => {\n        const replyText = replyTextarea.value.trim();\n        if (replyText === '' || replyText.length > TWEET_MAX_LENGTH) {\n          return;\n        }\n        \/\/ \u65b0\u898f\u30ea\u30d7\u30e9\u30a4\u4f5c\u6210\n        createNewTweet(replyText, tweet.id);\n        replyTextarea.value = '';\n      });\n\n      \/\/ \u524a\u9664\n      if (isMyTweet) {\n        const deleteBtn = tweetDiv.querySelector('.delete-btn');\n        deleteBtn.addEventListener('click', () => {\n          \/\/ \u518d\u5e30\u7684\u306b\u63a2\u3057\u3066\u524a\u9664\n          removeTweetById(tweets, tweet.id);\n          updateLocalStorage();\n          renderTweets();\n        });\n      }\n\n      return tweetDiv;\n    }\n\n    \/\/ \u30c4\u30a4\u30fc\u30c8\u524a\u9664\uff08\u518d\u5e30\uff09\n    function removeTweetById(tweetArray, tweetId) {\n      for (let i = 0; i &lt; tweetArray.length; i++) {\n        if (tweetArray&#91;i].id === tweetId) {\n          tweetArray.splice(i, 1);\n          return true;\n        }\n        if (removeTweetById(tweetArray&#91;i].replies, tweetId)) {\n          return true;\n        }\n      }\n      return false;\n    }\n\n    \/\/ \u753b\u9762\u4e0a\u306e\u30c4\u30a4\u30fc\u30c8\u4e00\u89a7\u3092\u518d\u63cf\u753b\n    function renderTweets() {\n      \/\/ \u307e\u305a\u65e2\u5b58\u30c4\u30a4\u30fc\u30c8\u3092\u5168\u524a\u9664\n      const oldTweets = feedContainer.querySelectorAll('.tweet');\n      oldTweets.forEach(t => t.remove());\n\n      \/\/ \u4e0a\u304b\u3089\u9806\u306b\u30c4\u30a4\u30fc\u30c8\u3092\u8ffd\u52a0\n      tweets.forEach(tweet => {\n        const tweetEl = createTweetElement(tweet);\n        feedContainer.appendChild(tweetEl);\n      });\n    }\n\n    \/\/ ======================\n    \/\/   \u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u30fc\n    \/\/ ======================\n    window.addEventListener('DOMContentLoaded', () => {\n      renderTweets();\n      updateCharCount();\n    });\n\n    \/\/ \u30c4\u30a4\u30fc\u30c8\u6587\u5b57\u6570\u30ab\u30a6\u30f3\u30c8\n    tweetTextarea.addEventListener('input', updateCharCount);\n\n    function updateCharCount() {\n      const length = tweetTextarea.value.length;\n      charCountEl.textContent = `${length} \/ ${TWEET_MAX_LENGTH}`;\n\n      if (length > TWEET_MAX_LENGTH) {\n        errorEl.textContent = '\u6587\u5b57\u6570\u30aa\u30fc\u30d0\u30fc\u3067\u3059\uff01';\n        tweetButton.disabled = true;\n      } else {\n        errorEl.textContent = '';\n        tweetButton.disabled = false;\n      }\n    }\n\n    \/\/ \u30c4\u30a4\u30fc\u30c8\u6295\u7a3f\n    tweetButton.addEventListener('click', () => {\n      const text = tweetTextarea.value.trim();\n      if (text === '' || text.length > TWEET_MAX_LENGTH) {\n        return;\n      }\n      createNewTweet(text, null, attachedImageBase64);\n      tweetTextarea.value = '';\n      attachedImageBase64 = null;\n      attachInput.value = ''; \/\/ \u30d5\u30a1\u30a4\u30eb\u9078\u629e\u3092\u30af\u30ea\u30a2\n      updateCharCount();\n    });\n\n    \/\/ \u30d7\u30ed\u30d5\u30a3\u30fc\u30eb\u60c5\u5831\u306e\u4fdd\u5b58\n    saveProfileBtn.addEventListener('click', () => {\n      currentName = displayNameInput.value.trim() || '\u3042\u306a\u305f';\n      currentUserName = userNameInput.value.trim() || 'myAccount';\n\n      userProfile = {\n        displayName: currentName,\n        userName: currentUserName\n      };\n      localStorage.setItem('userProfile-advanced', JSON.stringify(userProfile));\n\n      alert('\u30d7\u30ed\u30d5\u30a3\u30fc\u30eb\u3092\u4fdd\u5b58\u3057\u307e\u3057\u305f\uff01\\n' +\n            `\u540d\u524d\uff1a${currentName}\\n\u30e6\u30fc\u30b6\u30fc\u540d\uff1a@${currentUserName}`);\n      renderTweets(); \/\/ \u8868\u793a\u540d\u3092\u5909\u3048\u3066\u518d\u63cf\u753b\n    });\n  &lt;\/script>\n&lt;\/body>\n&lt;\/html>\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[87],"tags":[],"class_list":["post-25948","post","type-post","status-publish","format-standard","hentry","category-web"],"aioseo_notices":[],"jetpack_featured_media_url":"","_links":{"self":[{"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/25948","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=25948"}],"version-history":[{"count":1,"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/25948\/revisions"}],"predecessor-version":[{"id":25949,"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/25948\/revisions\/25949"}],"wp:attachment":[{"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=25948"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=25948"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=25948"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}