first commit! 🎉
This commit is contained in:
		
						commit
						8dc8190cdf
					
				
					 12 changed files with 1327 additions and 0 deletions
				
			
		
							
								
								
									
										
											BIN
										
									
								
								public/avatar/ari.jpg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/avatar/ari.jpg
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 88 KiB | 
							
								
								
									
										240
									
								
								public/css/style.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										240
									
								
								public/css/style.css
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,240 @@ | |||
| :root { | ||||
|     --fg0: #eee; | ||||
|     --bg0: #080808; | ||||
|     --bg1: #101010; | ||||
|     --bg2: #121212; | ||||
|     --accent: #b7fd49; | ||||
| } | ||||
| 
 | ||||
| body { | ||||
|     margin: 0; | ||||
|     padding: 0; | ||||
|      | ||||
|     background-color: var(--bg0); | ||||
|     color: var(--fg0); | ||||
| 
 | ||||
|     font-family: "Inter", sans-serif; | ||||
| } | ||||
| 
 | ||||
| #feed { | ||||
|     width: 720px; | ||||
|     margin: 0 auto; | ||||
|     background-color: var(--bg1); | ||||
| } | ||||
| 
 | ||||
| .post-container { | ||||
|     padding: 20px 32px; | ||||
|     border-bottom: 1px solid #8884; | ||||
|     transition: background-color .1s; | ||||
| } | ||||
| 
 | ||||
| .post-container:hover { | ||||
|     background-color: var(--bg2); | ||||
| } | ||||
| 
 | ||||
| .post-context { | ||||
|     margin-bottom: 8px; | ||||
|     padding-left: 58px; | ||||
|     display: flex; | ||||
|     flex-direction: row; | ||||
|     align-items: center; | ||||
|     color: var(--accent); | ||||
|     opacity: .8; | ||||
|     transition: opacity .1s; | ||||
| } | ||||
| 
 | ||||
| .post-container:hover .post-context { | ||||
|     opacity: 1; | ||||
| } | ||||
| 
 | ||||
| .post-context-icon { | ||||
|     margin-right: 4px; | ||||
| } | ||||
| 
 | ||||
| .post-context a, | ||||
| .post-context a:visited, | ||||
| .post-header-container a, | ||||
| .post-header-container a:visited { | ||||
|     color: inherit; | ||||
|     text-decoration: none; | ||||
| } | ||||
| .post-context a:hover, | ||||
| .post-header-container a:hover { | ||||
|     text-decoration: underline; | ||||
| } | ||||
| 
 | ||||
| .post-context-time { | ||||
|     margin-left: auto; | ||||
| } | ||||
| 
 | ||||
| article.post { /* ... */ } | ||||
| 
 | ||||
| .post-header-container { | ||||
|     display: flex; | ||||
|     flex-direction: row; | ||||
| } | ||||
| 
 | ||||
| .post-avatar-container { | ||||
|     margin-right: 12px; | ||||
| } | ||||
| 
 | ||||
| .post-avatar { | ||||
|     border-radius: 8px; | ||||
|     box-shadow: 2px 2px #0004; | ||||
|     /* transition: transform .2s ease-out; */ | ||||
| } | ||||
| 
 | ||||
| /* .post-avatar:hover { */ | ||||
| /*     transform: scale(1.1); */ | ||||
| /* } */ | ||||
| 
 | ||||
| .post-header { | ||||
|     display: flex; | ||||
|     flex-grow: 1; | ||||
|     flex-direction: row; | ||||
| } | ||||
| 
 | ||||
| .post-info { | ||||
|     margin-left: auto; | ||||
| } | ||||
| 
 | ||||
| .post-user-info a { | ||||
|     display: block; | ||||
| } | ||||
| 
 | ||||
| .post-body { | ||||
|     margin-top: 8px; | ||||
| } | ||||
| 
 | ||||
| .post-media-container { | ||||
|     margin-top: 8px; | ||||
|     display: grid; | ||||
|     grid-gap: 8px; | ||||
| } | ||||
| 
 | ||||
| .post-media-container[data-count="1"] { | ||||
|     grid-template-rows: 1fr; | ||||
| } | ||||
| 
 | ||||
| .post-media-container[data-count="2"] { | ||||
|     grid-template-columns: 1fr 1fr; | ||||
|     grid-template-rows: 1fr; | ||||
| } | ||||
| 
 | ||||
| .post-media-container[data-count="3"] { | ||||
|     grid-template-columns: 1fr .5fr; | ||||
|     grid-template-rows: 1fr 1fr; | ||||
| } | ||||
| 
 | ||||
| .post-media-container[data-count="4"] { | ||||
|     grid-template-columns: 1fr 1fr; | ||||
|     grid-template-rows: 1fr 1fr; | ||||
| } | ||||
| 
 | ||||
| .post-media { | ||||
|     border-radius: 12px; | ||||
|     background-color: #000; | ||||
|     overflow: hidden; | ||||
| } | ||||
| 
 | ||||
| .post-media a { | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     display: block; | ||||
|     cursor: zoom-in; | ||||
| } | ||||
| 
 | ||||
| .post-media a img { | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     display: block; | ||||
|     object-fit: contain; | ||||
| } | ||||
| 
 | ||||
| .post-media-container > :nth-child(1) { | ||||
|     grid-column: 1/2; | ||||
|     grid-row: 1/2; | ||||
| } | ||||
| 
 | ||||
| .post-media-container[data-count="3"] > :nth-child(1) { | ||||
|     grid-row: 1/3; | ||||
| } | ||||
| 
 | ||||
| .post-media-container > :nth-child(2) { | ||||
|     grid-column: 2/2; | ||||
|     grid-row: 1/2; | ||||
| } | ||||
| 
 | ||||
| .post-media-container > :nth-child(3) { | ||||
|     grid-column: 1/2; | ||||
|     grid-row: 2/2; | ||||
| } | ||||
| 
 | ||||
| .post-media-container[data-count="3"] > :nth-child(3) { | ||||
|     grid-column: 2/2; | ||||
|     grid-row: 2/2; | ||||
| } | ||||
| 
 | ||||
| .post-media-container > :nth-child(4) { | ||||
|     grid-column: 2/2; | ||||
|     grid-row: 2/2; | ||||
| } | ||||
| 
 | ||||
| .post-container footer { | ||||
|     opacity: .8; | ||||
|     transition: opacity .1s; | ||||
| } | ||||
| 
 | ||||
| .post-container:hover footer { | ||||
|     opacity: 1; | ||||
| } | ||||
| 
 | ||||
| .post-reactions { | ||||
|     margin-top: 8px; | ||||
| } | ||||
| 
 | ||||
| button.reaction { | ||||
|     padding: 6px 8px; | ||||
|     font-size: 1em; | ||||
|     background: none; | ||||
|     color: inherit; | ||||
|     border: none; | ||||
|     border-radius: 8px; | ||||
|     /* transition: transform .1s ease-out; */ | ||||
| } | ||||
| 
 | ||||
| button.reaction:hover, | ||||
| .post-actions button:hover { | ||||
|     /* transform: scale(1.1); */ | ||||
|     background: #8881; | ||||
| } | ||||
| 
 | ||||
| button.reaction:active, | ||||
| .post-actions button:active { | ||||
|     /* transform: scale(.95); */ | ||||
|     background: #0001; | ||||
| } | ||||
| 
 | ||||
| button.reaction.active, | ||||
| .post-actions button.active { | ||||
|     background: var(--accent); | ||||
|     color: var(--bg0); | ||||
| } | ||||
| 
 | ||||
| .post-actions { | ||||
|     margin-top: 8px; | ||||
| } | ||||
| 
 | ||||
| .post-actions button { | ||||
|     padding: 6px 8px; | ||||
|     font-size: 1em; | ||||
|     background: none; | ||||
|     color: inherit; | ||||
|     border: none; | ||||
|     border-radius: 8px; | ||||
|     transition: transform .1s ease-out; | ||||
| } | ||||
| 
 | ||||
| .post-actions button .count { | ||||
|     opacity: .5; | ||||
| } | ||||
							
								
								
									
										107
									
								
								public/index.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								public/index.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,107 @@ | |||
| <!DOCTYPE html> | ||||
| <!-- | ||||
|     experimenting with post layouts here! | ||||
|     don't expect anything too flashy ;3 | ||||
| 
 | ||||
|     ari melody, 2024 | ||||
| --> | ||||
| <html lang="en"> | ||||
|     <head> | ||||
|         <meta charset="UTF-8"> | ||||
|         <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||
|         <title></title> | ||||
|         <link href="css/style.css" rel="stylesheet"> | ||||
|         <script type="application/javascript" src="script/main.mjs" defer></script> | ||||
|     </head> | ||||
|     <body> | ||||
|         <audio id="sound-success" src="sound/success.wav"></audio> | ||||
|         <header> | ||||
|              | ||||
|         </header> | ||||
|         <main> | ||||
|             <div id="feed"> | ||||
|                 <!-- | ||||
|                 <div class="post-container" aria-label="ari; hello world!~; 02:12:06"> | ||||
|                     <div class="post-context"> | ||||
|                         <span class="post-context-icon">🔁</span> | ||||
|                         <span class="post-context-action"> | ||||
|                             <a href="/@ari">ari 💫</a> boosted this post. | ||||
|                         </span> | ||||
|                         <span class="post-context-time"> | ||||
|                             <time title="6/3/2024, 2:12:06 AM">2m ago</time> | ||||
|                         </span> | ||||
|                     </div> | ||||
|                     <article class="post"> | ||||
|                         <div class="post-header-container"> | ||||
|                             <a href="/@ari" class="post-avatar-container"> | ||||
|                                 <img src="avatar/ari.jpg" alt="" width="48" height="48" class="post-avatar" loading="lazy" decoding="async"> | ||||
|                             </a> | ||||
|                             <header class="post-header"> | ||||
|                                 <div class="post-user-info"> | ||||
|                                     <a href="/@ari" class="name">ari 💫</a> | ||||
|                                     <span class="username">@ari</span> | ||||
|                                 </div> | ||||
|                                 <div class="post-info"> | ||||
|                                     <a href="/post/21c892b23701" class="created-at"> | ||||
|                                         <time title="6/3/2024, 2:11:58 AM">10m ago</time> | ||||
|                                     </a> | ||||
|                                 </div> | ||||
|                             </header> | ||||
|                         </div> | ||||
|                         <div class="post-body"> | ||||
|                             <span class="post-content">hello world!~</span> | ||||
|                             <div class="post-media-container" data-count="3"> | ||||
|                                 <div class="post-media image"> | ||||
|                                     <a href="media/ariyeah-button.png"> | ||||
|                                         <img src="media/ariyeah-button.png" alt="custom miiverse "yeah!" button" loading="lazy" decoding="async"> | ||||
|                                     </a> | ||||
|                                 </div> | ||||
|                                 <div class="post-media image"> | ||||
|                                     <a href="media/beer.jpg"> | ||||
|                                         <img src="media/beer.jpg" alt="barney calhoun with beer" loading="lazy" decoding="async"> | ||||
|                                     </a> | ||||
|                                 </div> | ||||
|                                 <div class="post-media image"> | ||||
|                                     <a href="media/duck.jpg"> | ||||
|                                         <img src="media/duck.jpg" alt="big rubber duck" loading="lazy" decoding="async"> | ||||
|                                     </a> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                         <footer class="post-footer"> | ||||
|                             <div class="post-reactions"> | ||||
|                                 <button type="button" class="reaction"> | ||||
|                                     <span>⭐</span> | ||||
|                                     <span class="count">52</span> | ||||
|                                 </button> | ||||
|                             </div> | ||||
|                             <div class="post-actions"> | ||||
|                                 <button type="button" class="reply" aria-label="Reply" title="Reply"> | ||||
|                                     <span>🗨️</span> | ||||
|                                     <span class="count">7</span> | ||||
|                                 </button> | ||||
|                                 <button type="button" class="boost" aria-label="Boost" title="Boost"> | ||||
|                                     <span>🔁</span> | ||||
|                                     <span class="count">13</span> | ||||
|                                 </button> | ||||
|                                 <button type="button" class="favourite" aria-label="Favourite" title="Favourite"> | ||||
|                                     <span>⭐</span> | ||||
|                                 </button> | ||||
|                                 <button type="button" class="react" aria-label="React" title="React"> | ||||
|                                     <span>😃</span> | ||||
|                                 </button> | ||||
|                                 <button type="button" class="quote" aria-label="Quote" title="Quote"> | ||||
|                                     <span>🗣️</span> | ||||
|                                 </button> | ||||
|                                 <button type="button" class="more" aria-label="More" title="More"> | ||||
|                                     <span>🛠️</span> | ||||
|                                 </button> | ||||
|                             </div> | ||||
|                         </footer> | ||||
|                     </article> | ||||
|                 </div> | ||||
|                 --> | ||||
|             </div> | ||||
|         </main> | ||||
|     </body> | ||||
| </html> | ||||
							
								
								
									
										
											BIN
										
									
								
								public/media/ariyeah-button.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/media/ariyeah-button.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 90 KiB | 
							
								
								
									
										
											BIN
										
									
								
								public/media/beer.jpg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/media/beer.jpg
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 14 KiB | 
							
								
								
									
										
											BIN
										
									
								
								public/media/duck.jpg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/media/duck.jpg
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 22 KiB | 
							
								
								
									
										302
									
								
								public/script/main.mjs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										302
									
								
								public/script/main.mjs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,302 @@ | |||
| const aria_safe_regex = /([\u2700-\u27BF]|[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83E[\uDD10-\uDDFF]|[\r])/g; | ||||
| const INSTANCE_URL = "soc.arimelody.me"; | ||||
| 
 | ||||
| const sounds = { | ||||
|     "default": new Audio("sound/log.ogg"), | ||||
|     "post": new Audio("sound/success.ogg"), | ||||
|     "boost": new Audio("sound/hello.ogg"), | ||||
| }; | ||||
| 
 | ||||
| const actors = { | ||||
|     "@ari": { | ||||
|         "url": "https://soc.arimelody.me/@ari", | ||||
|         "name": "ari 💫", | ||||
|         "avatar": "avatar/ari.jpg", | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| const test_post = { | ||||
|     "context": { | ||||
|         "type": "boost", | ||||
|         "by": "@ari", | ||||
|         "at": 1718513838624, | ||||
|     }, | ||||
|     "author": "@ari", | ||||
|     "url": "/post/21c892b23701", | ||||
|     "at": 1718513988384, | ||||
|     "content": "hello world!~", | ||||
|     "media": [ | ||||
|         { "url": "media/ariyeah-button.png", "alt": "custom miiverse \"yeah!\" button" }, | ||||
|         { "url": "media/beer.jpg", "alt": "barney calhoun with beer" }, | ||||
|         { "url": "media/duck.jpg", "alt": "big rubber duck" }, | ||||
|     ], | ||||
|     "replies": 7, | ||||
|     "boosts": 13, | ||||
|     "reactions": [ | ||||
|         { "react": "⭐", "count": "52" }, | ||||
|         { "react": "❤️", "count": "9" }, | ||||
|     ], | ||||
| }; | ||||
| 
 | ||||
| const feed = document.getElementById("feed"); | ||||
| 
 | ||||
| function render_post(data) { | ||||
|     // TODO: please god just use or make a library to build this
 | ||||
| 
 | ||||
|     const actor = actors[data.author]; | ||||
|     if (!actor) return; | ||||
|     const date = new Date(data.at); | ||||
| 
 | ||||
|     const post = document.createElement("article"); | ||||
|     post.classList.add("post-container"); | ||||
|     post.ariaLabel = actor.name.replace(aria_safe_regex, "").trim() + "; " + data.content + "; " + date.toLocaleTimeString(); | ||||
| 
 | ||||
|     if (data.context && data.context.by && actors[data.context.by]) { | ||||
|         // post context
 | ||||
|         const post_context = document.createElement("div"); | ||||
|         post_context.classList.add("post-context"); | ||||
| 
 | ||||
|         if (data.context.type == "boost") { | ||||
|             const post_context_icon = document.createElement("span"); | ||||
|             post_context_icon.classList.add("post-context-icon"); | ||||
|             post_context_icon.innerText = "🔁"; | ||||
|             post_context.appendChild(post_context_icon); | ||||
| 
 | ||||
|             const post_context_action = document.createElement("span"); | ||||
|             post_context_action.classList.add("post-context-action"); | ||||
|             const actor = actors[data.context.by]; | ||||
|             post_context_action.innerHTML = `boosted by <a href="${actor.url}">${actor.name}</a>`; | ||||
|             post_context.appendChild(post_context_action); | ||||
| 
 | ||||
|             const post_context_time = document.createElement("span"); | ||||
|             post_context_time.classList.add("post-context-time"); | ||||
|             post_context_time.innerHTML = `<time>${new Date(data.context.at).toLocaleString()}</time>`; | ||||
|             post_context.appendChild(post_context_time); | ||||
|         } | ||||
| 
 | ||||
|         post.appendChild(post_context); | ||||
|     } | ||||
| 
 | ||||
|     // the actual post
 | ||||
|     // article.post
 | ||||
|     const post_article = document.createElement("article"); | ||||
| 
 | ||||
|     const post_header_container = document.createElement("div"); | ||||
|     post_header_container.classList.add("post-header-container"); | ||||
|     const post_avatar_container = document.createElement("a"); | ||||
|     post_avatar_container.classList.add("post-avatar-container"); | ||||
|     post_avatar_container.href = actor.url; | ||||
|     const post_avatar = document.createElement("img"); | ||||
|     post_avatar.classList.add("post-avatar"); | ||||
|     post_avatar.src = actor.avatar; | ||||
|     post_avatar.alt = ""; | ||||
|     post_avatar.width = 48; | ||||
|     post_avatar.height = 48; | ||||
|     post_avatar.loading = "lazy"; | ||||
|     post_avatar.decoding = "async"; | ||||
|     post_avatar_container.appendChild(post_avatar); | ||||
|     post_header_container.appendChild(post_avatar_container); | ||||
| 
 | ||||
|     const post_header = document.createElement("header"); | ||||
|     post_header.classList.add("post-header"); | ||||
|     const post_user_info = document.createElement("div"); | ||||
|     post_user_info.classList.add("post-user-info"); | ||||
|     const post_user_info_name = document.createElement("a"); | ||||
|     post_user_info_name.classList.add("name"); | ||||
|     post_user_info_name.href = actor.url; | ||||
|     post_user_info_name.innerText = actor.name | ||||
|     post_user_info.appendChild(post_user_info_name); | ||||
|     const post_user_info_username = document.createElement("span"); | ||||
|     post_user_info_username.classList.add("username"); | ||||
|     post_user_info_username.href = actor.url; | ||||
|     post_user_info_username.innerText = data.author | ||||
|     post_user_info.appendChild(post_user_info_username); | ||||
|     post_header.appendChild(post_user_info); | ||||
|     const post_info = document.createElement("div"); | ||||
|     post_info.classList.add("post-info"); | ||||
|     const post_info_time = document.createElement("a"); | ||||
|     post_info_time.classList.add("created-at"); | ||||
|     const post_date = new Date(data.at); | ||||
|     post_info_time.innerHTML = `<time title=${post_date.toLocaleString()}>${post_date.toLocaleString()}</time>`; | ||||
|     post_info_time.href = post.url; | ||||
|     post_info.appendChild(post_info_time); | ||||
|     post_header.appendChild(post_info); | ||||
|     post_header_container.appendChild(post_header); | ||||
| 
 | ||||
|     post_article.appendChild(post_header_container); | ||||
| 
 | ||||
| 
 | ||||
|     const post_body = document.createElement("div"); | ||||
|     post_body.classList.add("post-body"); | ||||
| 
 | ||||
|     const post_content = document.createElement("span"); | ||||
|     post_content.classList.add("post-content"); | ||||
|     post_content.innerText = data.content; | ||||
|     post_body.appendChild(post_content); | ||||
| 
 | ||||
|     const media_container = document.createElement("div"); | ||||
|     media_container.classList.add("post-media-container"); | ||||
|     media_container.dataset.count = data.media.length; | ||||
|     data.media.forEach(media => { | ||||
|         const media_item = document.createElement("div"); | ||||
|         media_item.classList.add("post-media"); | ||||
|         const link = document.createElement("a"); | ||||
|         link.href = media.url; | ||||
|         const source = document.createElement("img"); | ||||
|         source.src = media.url; | ||||
|         source.alt = media.alt; | ||||
|         source.loading = "lazy"; | ||||
|         source.decoding = "async"; | ||||
|         link.appendChild(source); | ||||
|         media_item.appendChild(link); | ||||
|         media_container.appendChild(media_item); | ||||
|     }); | ||||
|     post_body.appendChild(media_container); | ||||
| 
 | ||||
|     post_article.appendChild(post_body); | ||||
| 
 | ||||
| 
 | ||||
|     const post_footer = document.createElement("footer"); | ||||
|     post_footer.classList.add("post-footer"); | ||||
| 
 | ||||
|     const post_reactions = document.createElement("div"); | ||||
|     post_reactions.classList.add("post-reactions"); | ||||
|     data.reactions.forEach(reaction => { | ||||
|         const btn = document.createElement("button"); | ||||
|         btn.classList.add("reaction"); | ||||
|         btn.type = "button"; | ||||
|         const emote = document.createElement("span"); | ||||
|         emote.innerText = reaction.react; | ||||
|         btn.appendChild(emote); | ||||
|         const count = document.createElement("span"); | ||||
|         count.classList.add("count"); | ||||
|         count.innerText = reaction.count; | ||||
|         btn.appendChild(count); | ||||
|         post_reactions.appendChild(btn); | ||||
|     }); | ||||
|     post_footer.appendChild(post_reactions); | ||||
| 
 | ||||
|     const post_actions = document.createElement("div"); | ||||
|     post_actions.classList.add("post-actions"); | ||||
| 
 | ||||
|     const reply_button = document.createElement("button"); | ||||
|     reply_button.type = "button"; | ||||
|     reply_button.ariaLabel = "Reply"; | ||||
|     reply_button.title = "Reply"; | ||||
|     reply_button.innerHTML = `<span>🗨️</span><span class="count">${data.replies}</count>`; | ||||
|     post_actions.appendChild(reply_button); | ||||
| 
 | ||||
|     const boost_button = document.createElement("button"); | ||||
|     boost_button.type = "button"; | ||||
|     boost_button.ariaLabel = "Boost"; | ||||
|     boost_button.title = "Boost"; | ||||
|     boost_button.innerHTML = `<span>🔁</span><span class="count">${data.boosts}</count>`; | ||||
|     post_actions.appendChild(boost_button); | ||||
| 
 | ||||
|     const fav_button = document.createElement("button"); | ||||
|     fav_button.type = "button"; | ||||
|     fav_button.ariaLabel = "Favourite"; | ||||
|     fav_button.title = "Favourite"; | ||||
|     fav_button.innerText = "⭐"; | ||||
|     post_actions.appendChild(fav_button); | ||||
| 
 | ||||
|     const react_button = document.createElement("button"); | ||||
|     react_button.type = "button"; | ||||
|     react_button.ariaLabel = "React"; | ||||
|     react_button.title = "React"; | ||||
|     react_button.innerText = "😃"; | ||||
|     post_actions.appendChild(react_button); | ||||
| 
 | ||||
|     const quote_button = document.createElement("button"); | ||||
|     quote_button.type = "button"; | ||||
|     quote_button.ariaLabel = "Quote"; | ||||
|     quote_button.title = "Quote"; | ||||
|     quote_button.innerText = "🗣️"; | ||||
|     post_actions.appendChild(quote_button); | ||||
| 
 | ||||
|     const more_button = document.createElement("button"); | ||||
|     more_button.type = "button"; | ||||
|     more_button.ariaLabel = "More"; | ||||
|     more_button.title = "More"; | ||||
|     more_button.innerText = "⚒️"; | ||||
|     post_actions.appendChild(more_button); | ||||
| 
 | ||||
|     post_footer.appendChild(post_actions); | ||||
| 
 | ||||
|     post_article.appendChild(post_footer); | ||||
| 
 | ||||
| 
 | ||||
|     post.appendChild(post_article); | ||||
| 
 | ||||
|     return post; | ||||
| }; | ||||
| 
 | ||||
| function hook_post_listeners(post) { | ||||
|     post.querySelectorAll("button").forEach(button => { | ||||
|         button.addEventListener("click", () => { | ||||
|             if (button.classList.contains("reaction")) { | ||||
|                 toggle_reaction(button); | ||||
|             } | ||||
| 
 | ||||
|             switch (button.ariaLabel) { | ||||
|                 case "Reply": | ||||
|                     play_sound("post"); | ||||
|                     break; | ||||
| 
 | ||||
|                 case "Boost": | ||||
|                     play_sound("boost"); | ||||
|                     break; | ||||
| 
 | ||||
|                 case "Favourite": | ||||
|                     post.querySelectorAll("button.reaction").forEach(reaction => { | ||||
|                         if (!reaction.innerText.startsWith("⭐")) return; | ||||
|                         toggle_reaction(reaction); | ||||
|                     }); | ||||
|                     play_sound(); | ||||
|                     break; | ||||
| 
 | ||||
|                 default: | ||||
|                     play_sound(); | ||||
|                     break; | ||||
|             } | ||||
|         });        | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| function toggle_reaction(reaction) { | ||||
|     const was_active = reaction.classList.contains("active"); | ||||
|     reaction.classList.toggle("active"); | ||||
|     const count = reaction.querySelector(".count"); | ||||
|     count.innerText = Number(count.innerText) + (was_active ? -1 : 1); | ||||
| } | ||||
| 
 | ||||
| function load_content() { | ||||
|     for (let i = 0; i < 10; i++) { | ||||
|         const post = render_post(test_post); | ||||
|         feed.appendChild(post); | ||||
|         hook_post_listeners(post); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function play_sound(name) { | ||||
|     if (!name) name = "default"; | ||||
|     const sound = sounds[name]; | ||||
|     if (!sound) { | ||||
|         console.warn(`Attempted to play sound "${name}", which does not exist!`); | ||||
|         return; | ||||
|     } | ||||
|     sound.pause(); | ||||
|     sound.currentTime = 0; | ||||
|     sound.play(); | ||||
| } | ||||
| 
 | ||||
| feed.querySelectorAll(".post-container").forEach(post => { | ||||
|     hook_post_listeners(post); | ||||
| }); | ||||
| load_content(); | ||||
| 
 | ||||
| document.addEventListener("scroll", event => { | ||||
|     while (window.innerHeight + window.scrollY >= document.body.offsetHeight - 1000) { | ||||
|         load_content(); | ||||
|     } | ||||
| }); | ||||
							
								
								
									
										
											BIN
										
									
								
								public/sound/hello.ogg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/sound/hello.ogg
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								public/sound/log.ogg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/sound/log.ogg
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								public/sound/success.ogg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/sound/success.ogg
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue