this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Allow multiple media types in sandbox

+200 -21
src/assets/sandbox/big-buck-bunny-muted.webm

This is a binary file and will not be displayed.

src/assets/sandbox/big-buck-bunny-preview.png

This is a binary file and will not be displayed.

src/assets/sandbox/big-buck-bunny.mp3

This is a binary file and will not be displayed.

src/assets/sandbox/big-buck-bunny.webm

This is a binary file and will not be displayed.

+35
src/pages/sandbox.css
··· 176 176 input[type='checkbox' i] { 177 177 margin: 0; 178 178 } 179 + 180 + /* Media types styling */ 181 + .media-types { 182 + padding-inline-start: 12px; 183 + li { 184 + list-style: decimal; 185 + display: flex; 186 + counter-increment: index; 187 + align-items: center; 188 + 189 + &:before { 190 + content: counter(index); 191 + color: var(--text-insignificant-color); 192 + font-variant: tabular-nums; 193 + } 194 + } 195 + } 179 196 } 180 197 } 198 + 199 + ::view-transition-old(status), 200 + ::view-transition-new(status) { 201 + width: 100%; 202 + height: 100%; 203 + } 204 + 205 + ::view-transition-old(status-media), 206 + ::view-transition-new(status-media) { 207 + width: 100%; 208 + height: 100%; 209 + } 210 + 211 + ::view-transition-old(status-poll), 212 + ::view-transition-new(status-poll) { 213 + width: 100%; 214 + height: 100%; 215 + }
+165 -21
src/pages/sandbox.jsx
··· 2 2 3 3 import { useEffect, useState } from 'preact/hooks'; 4 4 5 + import testGIFURL from '../assets/sandbox/big-buck-bunny-muted.webm'; 6 + import testPreviewURL from '../assets/sandbox/big-buck-bunny-preview.png'; 7 + import testAudioURL from '../assets/sandbox/big-buck-bunny.mp3'; 8 + import testVideoURL from '../assets/sandbox/big-buck-bunny.webm'; 9 + 5 10 import Status from '../components/status'; 6 11 import { getPreferences } from '../utils/api'; 7 12 import FilterContext from '../utils/filter-context'; 13 + import states from '../utils/states'; 8 14 import store from '../utils/store'; 9 15 10 16 function hashID(obj) { ··· 85 91 if (mediaCount > 0) { 86 92 base.mediaAttachments = Array(parseInt(mediaCount, 10)) 87 93 .fill(0) 88 - .map((_, i) => ({ 89 - id: `media-${i}`, 90 - type: 'image', 91 - url: `https://picsum.photos/seed/media-${i}/600/400`, 92 - previewUrl: `https://picsum.photos/seed/media-${i}/300/200`, 93 - description: 94 - i % 2 === 0 ? `Sample image description for media ${i + 1}` : '', 95 - meta: { 96 - original: { 97 - width: 600, 98 - height: 400, 99 - }, 100 - small: { 101 - width: 600, 102 - height: 400, 103 - }, 104 - }, 105 - })); 94 + .map((_, i) => { 95 + const mediaType = toggles.mediaTypes?.[i] || 'image'; 96 + 97 + // Configure media based on type 98 + let mediaConfig = { 99 + id: `media-${i}`, 100 + type: mediaType, 101 + description: 102 + i % 2 === 0 103 + ? `Sample ${mediaType} description for media ${i + 1}` 104 + : '', 105 + }; 106 + 107 + // Set URLs based on media type 108 + switch (mediaType) { 109 + case 'image': 110 + mediaConfig.url = `https://picsum.photos/seed/media-${i}/600/400`; 111 + mediaConfig.previewUrl = `https://picsum.photos/seed/media-${i}/300/200`; 112 + mediaConfig.meta = { 113 + original: { 114 + width: 600, 115 + height: 400, 116 + }, 117 + small: { 118 + width: 300, 119 + height: 200, 120 + }, 121 + }; 122 + break; 123 + case 'gifv': 124 + mediaConfig.type = 'gifv'; 125 + mediaConfig.url = testGIFURL; 126 + mediaConfig.previewUrl = testPreviewURL; 127 + mediaConfig.meta = { 128 + original: { 129 + width: 426, 130 + height: 240, 131 + duration: 14, 132 + }, 133 + }; 134 + break; 135 + case 'video': 136 + mediaConfig.type = 'video'; 137 + mediaConfig.url = testVideoURL; 138 + mediaConfig.previewUrl = testPreviewURL; 139 + break; 140 + case 'audio': 141 + mediaConfig.type = 'audio'; 142 + mediaConfig.url = testAudioURL; 143 + mediaConfig.previewUrl = i % 2 === 0 ? '' : testPreviewURL; 144 + break; 145 + } 146 + 147 + return mediaConfig; 148 + }); 106 149 } 107 150 108 151 // Add poll if selected ··· 222 265 hasSpoiler: false, 223 266 spoilerType: 'all', 224 267 mediaCount: '0', 268 + mediaTypes: [], 225 269 pollCount: '0', 226 270 pollMultiple: false, 227 271 pollExpired: false, ··· 233 277 234 278 // Update function with view transitions 235 279 const updateToggles = (updates) => { 280 + if (typeof updates === 'function') { 281 + updates = updates(toggleState); 282 + } 283 + 236 284 // Check for browser support 237 285 if (!document.startViewTransition) { 238 286 setToggleState((prev) => ({ ...prev, ...updates })); ··· 290 338 spoiler: toggleState.hasSpoiler, 291 339 spoilerType: toggleState.spoilerType, 292 340 mediaCount: toggleState.mediaCount, 341 + mediaTypes: toggleState.mediaTypes, 293 342 pollCount: toggleState.pollCount, 294 343 pollMultiple: toggleState.pollMultiple, 295 344 pollExpired: toggleState.pollExpired, ··· 335 384 allowFilters={true} 336 385 // Add a key that changes when preferences change to force re-render 337 386 key={`status-${toggleState.mediaPreference}-${toggleState.expandWarnings}-${mockStatus.id}`} 387 + // Prevent opening as URL 388 + onMediaClick={(e, i, media, status) => { 389 + e.preventDefault(); 390 + states.showMediaModal = { 391 + mediaAttachments: status.mediaAttachments, 392 + mediaIndex: i, 393 + }; 394 + }} 338 395 /> 339 396 )} 340 397 </FilterContext.Provider> ··· 512 569 const newHasMedia = e.target.checked; 513 570 const updates = { 514 571 mediaCount: newHasMedia ? '1' : '0', 572 + mediaTypes: newHasMedia ? ['image'] : [], 515 573 }; 516 574 517 575 // If removing media and no text content, enable text content ··· 526 584 <input 527 585 type="number" 528 586 min="1" 587 + // max="4" 529 588 value={ 530 589 toggleState.mediaCount === '0' 531 590 ? '1' 532 591 : toggleState.mediaCount 533 592 } 534 593 step="1" 535 - onChange={(e) => 536 - updateToggles({ mediaCount: e.target.value }) 537 - } 594 + onChange={(e) => { 595 + const value = parseInt(e.target.value) || 1; 596 + updateToggles(({ mediaTypes = [] }) => { 597 + mediaTypes[value - 1] = 'image'; 598 + return { 599 + mediaCount: String(value), 600 + mediaTypes, 601 + }; 602 + }); 603 + }} 538 604 disabled={parseInt(toggleState.mediaCount) === 0} 539 605 /> 540 606 </label> 607 + 608 + {parseInt(toggleState.mediaCount) > 0 && ( 609 + <ul class="media-types"> 610 + {Array.from( 611 + { length: parseInt(toggleState.mediaCount) }, 612 + (_, index) => ( 613 + <li key={`media-type-${index}`}> 614 + <label> 615 + <input 616 + type="radio" 617 + name={`mediaType${index}`} 618 + checked={ 619 + toggleState.mediaTypes[index] === 'image' 620 + } 621 + onChange={() => { 622 + const newMediaTypes = [ 623 + ...toggleState.mediaTypes, 624 + ]; 625 + newMediaTypes[index] = 'image'; 626 + updateToggles({ mediaTypes: newMediaTypes }); 627 + }} 628 + /> 629 + <span>Image</span> 630 + </label> 631 + <label> 632 + <input 633 + type="radio" 634 + name={`mediaType${index}`} 635 + checked={toggleState.mediaTypes[index] === 'gifv'} 636 + onChange={() => { 637 + const newMediaTypes = [ 638 + ...toggleState.mediaTypes, 639 + ]; 640 + newMediaTypes[index] = 'gifv'; 641 + updateToggles({ mediaTypes: newMediaTypes }); 642 + }} 643 + /> 644 + <span>GIFV</span> 645 + </label> 646 + <label> 647 + <input 648 + type="radio" 649 + name={`mediaType${index}`} 650 + checked={ 651 + toggleState.mediaTypes[index] === 'video' 652 + } 653 + onChange={() => { 654 + const newMediaTypes = [ 655 + ...toggleState.mediaTypes, 656 + ]; 657 + newMediaTypes[index] = 'video'; 658 + updateToggles({ mediaTypes: newMediaTypes }); 659 + }} 660 + /> 661 + <span>Video</span> 662 + </label> 663 + <label> 664 + <input 665 + type="radio" 666 + name={`mediaType${index}`} 667 + checked={ 668 + toggleState.mediaTypes[index] === 'audio' 669 + } 670 + onChange={() => { 671 + const newMediaTypes = [ 672 + ...toggleState.mediaTypes, 673 + ]; 674 + newMediaTypes[index] = 'audio'; 675 + updateToggles({ mediaTypes: newMediaTypes }); 676 + }} 677 + /> 678 + <span>Audio</span> 679 + </label> 680 + </li> 681 + ), 682 + )} 683 + </ul> 684 + )} 541 685 </li> 542 686 <li> 543 687 <label>