this repo has no description
0
fork

Configure Feed

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

Merge pull request #268 from cheeaun/main

Update from main

authored by

Chee Aun and committed by
GitHub
0cf7d683 cb80057f

+194 -95
+5 -3
.github/workflows/prodtag.yml
··· 14 14 - uses: actions/checkout@v4 15 15 with: 16 16 ref: production 17 - - run: git tag "`date +%Y.%m.%d`.`git rev-parse --short HEAD`" $(git rev-parse HEAD) 18 - - run: git push --tags 17 + # - run: git tag "`date +%Y.%m.%d`.`git rev-parse --short HEAD`" $(git rev-parse HEAD) 18 + # - run: git push --tags 19 19 - uses: actions/setup-node@v3 20 20 with: 21 21 node-version: 18 22 22 - run: npm ci && npm run build 23 23 - run: cd dist && zip -r ../phanpy-dist.zip . && cd .. 24 + - id: tag_name 25 + run: echo ::set-output name=tag_name::$(date +%Y.%m.%d).$(git rev-parse --short HEAD) 24 26 - uses: softprops/action-gh-release@v1 25 27 with: 26 - tag_name: ${{ github.ref_name }} 28 + tag_name: ${{ steps.tag_name.outputs.tag_name }} 27 29 generate_release_notes: true 28 30 files: phanpy-dist.zip
+1 -1
public/sw.js
··· 179 179 console.log('NOTIFICATION CLICK navigate', url); 180 180 if (bestClient) { 181 181 console.log('NOTIFICATION CLICK postMessage', bestClient); 182 + bestClient.focus(); 182 183 bestClient.postMessage?.({ 183 184 type: 'notification', 184 185 id: tag, 185 186 accessToken: access_token, 186 187 }); 187 - bestClient.focus(); 188 188 } else { 189 189 console.log('NOTIFICATION CLICK openWindow', url); 190 190 await self.clients.openWindow(url);
+18 -2
src/app.css
··· 676 676 position: relative; 677 677 border-radius: 0; 678 678 padding-block: 16px !important; 679 + 680 + .avatars-bunch > .avatar:not(:first-child) { 681 + margin-left: -4px; 682 + } 679 683 } 680 684 .timeline .show-more:hover { 681 685 filter: none !important; ··· 2116 2120 transparent 2117 2121 ); 2118 2122 align-items: center; 2123 + transition: opacity 0.3s ease-out; 2124 + 2125 + &.loading, 2126 + .loading > & { 2127 + pointer-events: none; 2128 + opacity: 0.5; 2129 + } 2119 2130 } 2120 2131 .filter-bar.centered { 2121 2132 justify-content: center; ··· 2133 2144 text-decoration: none; 2134 2145 white-space: nowrap; 2135 2146 border: 2px solid transparent; 2136 - transition: all 0.3s ease-out; 2147 + transition: border-color 0.3s ease-out; 2137 2148 display: inline-flex; 2138 2149 align-items: center; 2139 2150 gap: 8px; 2140 2151 } 2141 - .filter-bar > a:is(:hover, :focus) { 2152 + .filter-bar > a:focus-visible { 2142 2153 border-color: var(--link-light-color); 2154 + } 2155 + @media (hover: hover) { 2156 + .filter-bar > a:hover { 2157 + border-color: var(--link-light-color); 2158 + } 2143 2159 } 2144 2160 .filter-bar > a > * { 2145 2161 vertical-align: middle;
+25 -21
src/components/account-info.jsx
··· 550 550 tabIndex={0} 551 551 to={accountLink} 552 552 onClick={() => { 553 - states.showAccount = false; 554 - states.showGenericAccounts = { 555 - heading: 'Followers', 556 - fetchAccounts: fetchFollowers, 557 - }; 553 + // states.showAccount = false; 554 + setTimeout(() => { 555 + states.showGenericAccounts = { 556 + heading: 'Followers', 557 + fetchAccounts: fetchFollowers, 558 + }; 559 + }, 0); 558 560 }} 559 561 > 560 562 {!!familiarFollowers.length && ( ··· 581 583 tabIndex={0} 582 584 to={accountLink} 583 585 onClick={() => { 584 - states.showAccount = false; 585 - states.showGenericAccounts = { 586 - heading: 'Following', 587 - fetchAccounts: fetchFollowing, 588 - }; 586 + // states.showAccount = false; 587 + setTimeout(() => { 588 + states.showGenericAccounts = { 589 + heading: 'Following', 590 + fetchAccounts: fetchFollowing, 591 + }; 592 + }, 0); 589 593 }} 590 594 > 591 595 <span title={followingCount}> ··· 597 601 <LinkOrDiv 598 602 class="insignificant" 599 603 to={accountLink} 600 - onClick={ 601 - standalone 602 - ? undefined 603 - : () => { 604 - hideAllModals(); 605 - } 606 - } 604 + // onClick={ 605 + // standalone 606 + // ? undefined 607 + // : () => { 608 + // hideAllModals(); 609 + // } 610 + // } 607 611 > 608 612 <span title={statusesCount}> 609 613 {shortenNumber(statusesCount)} ··· 626 630 <LinkOrDiv 627 631 to={accountLink} 628 632 class="account-metadata-box" 629 - onClick={() => { 630 - states.showAccount = false; 631 - }} 633 + // onClick={() => { 634 + // states.showAccount = false; 635 + // }} 632 636 > 633 637 <div class="shazam-container"> 634 638 <div class="shazam-container-inner"> ··· 1511 1515 </button> 1512 1516 )} 1513 1517 <header> 1514 - <b>Private note for @{account?.acct}</b> 1518 + <b>Private note about @{account?.username || account?.acct}</b> 1515 1519 </header> 1516 1520 <main> 1517 1521 <form
+11 -8
src/components/account-sheet.jsx
··· 2 2 3 3 import { api } from '../utils/api'; 4 4 import states from '../utils/states'; 5 + import useLocationChange from '../utils/useLocationChange'; 5 6 6 7 import AccountInfo from './account-info'; 7 8 import Icon from './icon'; ··· 16 17 } 17 18 }, [account]); 18 19 20 + useLocationChange(onClose); 21 + 19 22 return ( 20 23 <div 21 24 class="sheet" 22 - onClick={(e) => { 23 - const accountBlock = e.target.closest('.account-block'); 24 - if (accountBlock) { 25 - onClose({ 26 - destination: 'account-statuses', 27 - }); 28 - } 29 - }} 25 + // onClick={(e) => { 26 + // const accountBlock = e.target.closest('.account-block'); 27 + // if (accountBlock) { 28 + // onClose({ 29 + // destination: 'account-statuses', 30 + // }); 31 + // } 32 + // }} 30 33 > 31 34 {!!onClose && ( 32 35 <button type="button" class="sheet-close outer" onClick={onClose}>
+3
src/components/generic-accounts.jsx
··· 5 5 import { useSnapshot } from 'valtio'; 6 6 7 7 import states from '../utils/states'; 8 + import useLocationChange from '../utils/useLocationChange'; 8 9 9 10 import AccountBlock from './account-block'; 10 11 import Icon from './icon'; ··· 15 16 const [uiState, setUIState] = useState('default'); 16 17 const [accounts, setAccounts] = useState([]); 17 18 const [showMore, setShowMore] = useState(false); 19 + 20 + useLocationChange(onClose); 18 21 19 22 if (!snapStates.showGenericAccounts) { 20 23 return null;
+3 -3
src/components/loader.jsx
··· 2 2 3 3 function Loader({ abrupt, hidden, ...props }) { 4 4 return ( 5 - <div 5 + <span 6 6 {...props} 7 7 class={`loader-container ${abrupt ? 'abrupt' : ''} ${ 8 8 hidden ? 'hidden' : '' 9 9 }`} 10 10 > 11 - <div class="loader" /> 12 - </div> 11 + <span class="loader" /> 12 + </span> 13 13 ); 14 14 } 15 15
+1
src/components/media.jsx
··· 130 130 enabled: pinchZoomEnabled, 131 131 draggableUnZoomed: false, 132 132 inertiaFriction: 0.9, 133 + doubleTapZoomOutOnMaxScale: true, 133 134 containerProps: { 134 135 className: 'media-zoom', 135 136 style: {
+4 -3
src/components/modals.jsx
··· 117 117 instance={snapStates.showAccount?.instance} 118 118 onClose={({ destination } = {}) => { 119 119 states.showAccount = false; 120 - if (destination) { 121 - states.showAccounts = false; 122 - } 120 + // states.showGenericAccounts = false; 121 + // if (destination) { 122 + // states.showAccounts = false; 123 + // } 123 124 }} 124 125 /> 125 126 </Modal>
+16 -1
src/components/nav-menu.css
··· 1 + .nav-menu section:last-child { 2 + background-color: var(--bg-faded-color); 3 + margin-bottom: -8px; 4 + padding-bottom: 8px; 5 + } 6 + 1 7 @media (min-width: 23em) { 2 8 .nav-menu { 3 9 display: grid; ··· 8 14 'left right'; 9 15 padding: 0; 10 16 width: 22em; 17 + max-width: calc(100vw - 16px); 11 18 } 12 19 .nav-menu .top-menu { 13 20 grid-area: top; ··· 27 34 } 28 35 } 29 36 .nav-menu section:last-child { 30 - background-color: var(--bg-faded-color); 31 37 background-image: linear-gradient( 32 38 to right, 33 39 var(--divider-color) 1px, ··· 45 51 animation: phanpying 0.2s ease-in-out both; 46 52 border-top-right-radius: inherit; 47 53 border-bottom-right-radius: inherit; 54 + margin-bottom: 0; 55 + display: flex; 56 + flex-direction: column; 57 + 58 + .divider-grow { 59 + flex-grow: 1; 60 + height: auto; 61 + background-color: transparent; 62 + } 48 63 } 49 64 .nav-menu section:last-child > .szh-menu__divider:first-child { 50 65 display: none;
+2 -1
src/components/nav-menu.jsx
··· 249 249 <Icon icon="block" size="l" /> 250 250 Blocked users&hellip; 251 251 </MenuItem> 252 + <MenuDivider className="divider-grow" /> 252 253 <MenuItem 253 254 onClick={() => { 254 255 states.showKeyboardShortcutsHelp = true; ··· 263 264 }} 264 265 > 265 266 <Icon icon="shortcut" size="l" />{' '} 266 - <span>Shortcuts Settings&hellip;</span> 267 + <span>Shortcuts / Columns&hellip;</span> 267 268 </MenuItem> 268 269 <MenuItem 269 270 onClick={() => {
+39 -41
src/components/shortcuts-settings.jsx
··· 249 249 </h2> 250 250 </header> 251 251 <main> 252 - <p> 253 - Specify a list of shortcuts that'll appear&nbsp;as: 254 - <div class="shortcuts-view-mode"> 255 - {[ 256 - { 257 - value: 'float-button', 258 - label: 'Floating button', 259 - imgURL: floatingButtonUrl, 260 - }, 261 - { 262 - value: 'tab-menu-bar', 263 - label: 'Tab/Menu bar', 264 - imgURL: tabMenuBarUrl, 265 - }, 266 - { 267 - value: 'multi-column', 268 - label: 'Multi-column', 269 - imgURL: multiColumnUrl, 270 - }, 271 - ].map(({ value, label, imgURL }) => ( 272 - <label> 273 - <input 274 - type="radio" 275 - name="shortcuts-view-mode" 276 - value={value} 277 - checked={ 278 - snapStates.settings.shortcutsViewMode === value || 279 - (value === 'float-button' && 280 - !snapStates.settings.shortcutsViewMode) 281 - } 282 - onChange={(e) => { 283 - states.settings.shortcutsViewMode = e.target.value; 284 - }} 285 - />{' '} 286 - <img src={imgURL} alt="" width="80" height="58" />{' '} 287 - <span>{label}</span> 288 - </label> 289 - ))} 290 - </div> 291 - {/* <select 252 + <p>Specify a list of shortcuts that'll appear&nbsp;as:</p> 253 + <div class="shortcuts-view-mode"> 254 + {[ 255 + { 256 + value: 'float-button', 257 + label: 'Floating button', 258 + imgURL: floatingButtonUrl, 259 + }, 260 + { 261 + value: 'tab-menu-bar', 262 + label: 'Tab/Menu bar', 263 + imgURL: tabMenuBarUrl, 264 + }, 265 + { 266 + value: 'multi-column', 267 + label: 'Multi-column', 268 + imgURL: multiColumnUrl, 269 + }, 270 + ].map(({ value, label, imgURL }) => ( 271 + <label> 272 + <input 273 + type="radio" 274 + name="shortcuts-view-mode" 275 + value={value} 276 + checked={ 277 + snapStates.settings.shortcutsViewMode === value || 278 + (value === 'float-button' && 279 + !snapStates.settings.shortcutsViewMode) 280 + } 281 + onChange={(e) => { 282 + states.settings.shortcutsViewMode = e.target.value; 283 + }} 284 + />{' '} 285 + <img src={imgURL} alt="" width="80" height="58" />{' '} 286 + <span>{label}</span> 287 + </label> 288 + ))} 289 + </div> 290 + {/* <select 292 291 value={snapStates.settings.shortcutsViewMode || 'float-button'} 293 292 onChange={(e) => { 294 293 states.settings.shortcutsViewMode = e.target.value; ··· 298 297 <option value="multi-column">Multi-column</option> 299 298 <option value="tab-menu-bar">Tab/Menu bar </option> 300 299 </select> */} 301 - </p> 302 300 {/* <p> 303 301 <details> 304 302 <summary class="insignificant">
+30 -6
src/components/status.jsx
··· 579 579 try { 580 580 const done = await confirmBoostStatus(); 581 581 if (!isSizeLarge && done) { 582 - showToast(reblogged ? 'Unboosted' : 'Boosted'); 582 + showToast( 583 + reblogged 584 + ? `Unboosted @${username || acct}'s post` 585 + : `Boosted @${username || acct}'s post`, 586 + ); 583 587 } 584 588 } catch (e) {} 585 589 }} ··· 597 601 try { 598 602 favouriteStatus(); 599 603 if (!isSizeLarge) { 600 - showToast(favourited ? 'Unfavourited' : 'Favourited'); 604 + showToast( 605 + favourited 606 + ? `Unfavourited @${username || acct}'s post` 607 + : `Favourited @${username || acct}'s post`, 608 + ); 601 609 } 602 610 } catch (e) {} 603 611 }} ··· 621 629 try { 622 630 bookmarkStatus(); 623 631 if (!isSizeLarge) { 624 - showToast(bookmarked ? 'Unbookmarked' : 'Bookmarked'); 632 + showToast( 633 + bookmarked 634 + ? `Unbookmarked @${username || acct}'s post` 635 + : `Bookmarked @${username || acct}'s post`, 636 + ); 625 637 } 626 638 } catch (e) {} 627 639 }} ··· 829 841 try { 830 842 favouriteStatus(); 831 843 if (!isSizeLarge) { 832 - showToast(favourited ? 'Unfavourited' : 'Favourited'); 844 + showToast( 845 + favourited 846 + ? `Unfavourited @${username || acct}'s post` 847 + : `Favourited @${username || acct}'s post`, 848 + ); 833 849 } 834 850 } catch (e) {} 835 851 }, ··· 843 859 try { 844 860 bookmarkStatus(); 845 861 if (!isSizeLarge) { 846 - showToast(bookmarked ? 'Unbookmarked' : 'Bookmarked'); 862 + showToast( 863 + bookmarked 864 + ? `Unbookmarked @${username || acct}'s post` 865 + : `Bookmarked @${username || acct}'s post`, 866 + ); 847 867 } 848 868 } catch (e) {} 849 869 }, ··· 858 878 try { 859 879 const done = await confirmBoostStatus(); 860 880 if (!isSizeLarge && done) { 861 - showToast(reblogged ? 'Unboosted' : 'Boosted'); 881 + showToast( 882 + reblogged 883 + ? `Unboosted @${username || acct}'s post` 884 + : `Boosted @${username || acct}'s post`, 885 + ); 862 886 } 863 887 } catch (e) {} 864 888 })();
+7 -1
src/components/timeline.jsx
··· 334 334 </button> 335 335 )} 336 336 </header> 337 - {!!timelineStart && <div class="timeline-start">{timelineStart}</div>} 337 + {!!timelineStart && ( 338 + <div 339 + class={`timeline-start ${uiState === 'loading' ? 'loading' : ''}`} 340 + > 341 + {timelineStart} 342 + </div> 343 + )} 338 344 {!!items.length ? ( 339 345 <> 340 346 <ul class="timeline">
+1 -1
src/pages/account-statuses.jsx
··· 258 258 useItemID 259 259 boostsCarousel={snapStates.settings.boostsCarousel} 260 260 timelineStart={TimelineStart} 261 - refresh={excludeReplies + excludeBoosts + tagged + media} 261 + refresh={[excludeReplies, excludeBoosts, tagged, media].toString()} 262 262 headerEnd={ 263 263 <Menu2 264 264 portal
+1 -1
src/pages/search.jsx
··· 152 152 </header> 153 153 <main> 154 154 {!!q && ( 155 - <div class="filter-bar"> 155 + <div class={`filter-bar ${uiState === 'loading' ? 'loading' : ''}`}> 156 156 {!!type && ( 157 157 <Link to={`/search${q ? `?q=${encodeURIComponent(q)}` : ''}`}> 158 158 ‹ All
+1 -1
src/pages/status.jsx
··· 1062 1062 onClick={() => setLimit((l) => l + LIMIT)} 1063 1063 style={{ marginBlockEnd: '6em' }} 1064 1064 > 1065 - <div class="ib"> 1065 + <div class="ib avatars-bunch"> 1066 1066 {/* show avatars for first 5 statuses */} 1067 1067 {statuses.slice(limit, limit + 5).map((status) => ( 1068 1068 <Avatar
+3 -1
src/utils/getHTMLText.jsx
··· 1 + import mem from './mem'; 2 + 1 3 const div = document.createElement('div'); 2 4 function getHTMLText(html) { 3 5 if (!html) return ''; ··· 10 12 return div.innerText.replace(/[\r\n]{3,}/g, '\n\n').trim(); 11 13 } 12 14 13 - export default getHTMLText; 15 + export default mem(getHTMLText);
+23
src/utils/useLocationChange.js
··· 1 + import { useEffect, useRef } from 'preact/hooks'; 2 + import { useLocation } from 'react-router-dom'; 3 + 4 + // Hook that runs a callback when the location changes 5 + // Won't run on the first render 6 + 7 + export default function useLocationChange(fn) { 8 + if (!fn) return; 9 + const location = useLocation(); 10 + const currentLocationRef = useRef(location.pathname); 11 + useEffect(() => { 12 + // console.log('location', { 13 + // current: currentLocationRef.current, 14 + // next: location.pathname, 15 + // }); 16 + if ( 17 + currentLocationRef.current && 18 + location.pathname !== currentLocationRef.current 19 + ) { 20 + fn?.(); 21 + } 22 + }, [location.pathname, fn]); 23 + }