Merge pull request #268 from cheeaun/main

Update from main
This commit is contained in:
Chee Aun 2023-10-20 00:44:53 +08:00 committed by GitHub
commit 0cf7d683ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 194 additions and 95 deletions

View file

@ -14,15 +14,17 @@ jobs:
- uses: actions/checkout@v4
with:
ref: production
- run: git tag "`date +%Y.%m.%d`.`git rev-parse --short HEAD`" $(git rev-parse HEAD)
- run: git push --tags
# - run: git tag "`date +%Y.%m.%d`.`git rev-parse --short HEAD`" $(git rev-parse HEAD)
# - run: git push --tags
- uses: actions/setup-node@v3
with:
node-version: 18
- run: npm ci && npm run build
- run: cd dist && zip -r ../phanpy-dist.zip . && cd ..
- id: tag_name
run: echo ::set-output name=tag_name::$(date +%Y.%m.%d).$(git rev-parse --short HEAD)
- uses: softprops/action-gh-release@v1
with:
tag_name: ${{ github.ref_name }}
tag_name: ${{ steps.tag_name.outputs.tag_name }}
generate_release_notes: true
files: phanpy-dist.zip

View file

@ -179,12 +179,12 @@ self.addEventListener('notificationclick', (event) => {
console.log('NOTIFICATION CLICK navigate', url);
if (bestClient) {
console.log('NOTIFICATION CLICK postMessage', bestClient);
bestClient.focus();
bestClient.postMessage?.({
type: 'notification',
id: tag,
accessToken: access_token,
});
bestClient.focus();
} else {
console.log('NOTIFICATION CLICK openWindow', url);
await self.clients.openWindow(url);

View file

@ -676,6 +676,10 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
position: relative;
border-radius: 0;
padding-block: 16px !important;
.avatars-bunch > .avatar:not(:first-child) {
margin-left: -4px;
}
}
.timeline .show-more:hover {
filter: none !important;
@ -2116,6 +2120,13 @@ ul.link-list li a .icon {
transparent
);
align-items: center;
transition: opacity 0.3s ease-out;
&.loading,
.loading > & {
pointer-events: none;
opacity: 0.5;
}
}
.filter-bar.centered {
justify-content: center;
@ -2133,14 +2144,19 @@ ul.link-list li a .icon {
text-decoration: none;
white-space: nowrap;
border: 2px solid transparent;
transition: all 0.3s ease-out;
transition: border-color 0.3s ease-out;
display: inline-flex;
align-items: center;
gap: 8px;
}
.filter-bar > a:is(:hover, :focus) {
.filter-bar > a:focus-visible {
border-color: var(--link-light-color);
}
@media (hover: hover) {
.filter-bar > a:hover {
border-color: var(--link-light-color);
}
}
.filter-bar > a > * {
vertical-align: middle;
}

View file

@ -550,11 +550,13 @@ function AccountInfo({
tabIndex={0}
to={accountLink}
onClick={() => {
states.showAccount = false;
states.showGenericAccounts = {
heading: 'Followers',
fetchAccounts: fetchFollowers,
};
// states.showAccount = false;
setTimeout(() => {
states.showGenericAccounts = {
heading: 'Followers',
fetchAccounts: fetchFollowers,
};
}, 0);
}}
>
{!!familiarFollowers.length && (
@ -581,11 +583,13 @@ function AccountInfo({
tabIndex={0}
to={accountLink}
onClick={() => {
states.showAccount = false;
states.showGenericAccounts = {
heading: 'Following',
fetchAccounts: fetchFollowing,
};
// states.showAccount = false;
setTimeout(() => {
states.showGenericAccounts = {
heading: 'Following',
fetchAccounts: fetchFollowing,
};
}, 0);
}}
>
<span title={followingCount}>
@ -597,13 +601,13 @@ function AccountInfo({
<LinkOrDiv
class="insignificant"
to={accountLink}
onClick={
standalone
? undefined
: () => {
hideAllModals();
}
}
// onClick={
// standalone
// ? undefined
// : () => {
// hideAllModals();
// }
// }
>
<span title={statusesCount}>
{shortenNumber(statusesCount)}
@ -626,9 +630,9 @@ function AccountInfo({
<LinkOrDiv
to={accountLink}
class="account-metadata-box"
onClick={() => {
states.showAccount = false;
}}
// onClick={() => {
// states.showAccount = false;
// }}
>
<div class="shazam-container">
<div class="shazam-container-inner">
@ -1511,7 +1515,7 @@ function PrivateNoteSheet({
</button>
)}
<header>
<b>Private note for @{account?.acct}</b>
<b>Private note about @{account?.username || account?.acct}</b>
</header>
<main>
<form

View file

@ -2,6 +2,7 @@ import { useEffect } from 'preact/hooks';
import { api } from '../utils/api';
import states from '../utils/states';
import useLocationChange from '../utils/useLocationChange';
import AccountInfo from './account-info';
import Icon from './icon';
@ -16,17 +17,19 @@ function AccountSheet({ account, instance: propInstance, onClose }) {
}
}, [account]);
useLocationChange(onClose);
return (
<div
class="sheet"
onClick={(e) => {
const accountBlock = e.target.closest('.account-block');
if (accountBlock) {
onClose({
destination: 'account-statuses',
});
}
}}
// onClick={(e) => {
// const accountBlock = e.target.closest('.account-block');
// if (accountBlock) {
// onClose({
// destination: 'account-statuses',
// });
// }
// }}
>
{!!onClose && (
<button type="button" class="sheet-close outer" onClick={onClose}>

View file

@ -5,6 +5,7 @@ import { InView } from 'react-intersection-observer';
import { useSnapshot } from 'valtio';
import states from '../utils/states';
import useLocationChange from '../utils/useLocationChange';
import AccountBlock from './account-block';
import Icon from './icon';
@ -16,6 +17,8 @@ export default function GenericAccounts({ onClose = () => {} }) {
const [accounts, setAccounts] = useState([]);
const [showMore, setShowMore] = useState(false);
useLocationChange(onClose);
if (!snapStates.showGenericAccounts) {
return null;
}

View file

@ -2,14 +2,14 @@ import './loader.css';
function Loader({ abrupt, hidden, ...props }) {
return (
<div
<span
{...props}
class={`loader-container ${abrupt ? 'abrupt' : ''} ${
hidden ? 'hidden' : ''
}`}
>
<div class="loader" />
</div>
<span class="loader" />
</span>
);
}

View file

@ -130,6 +130,7 @@ function Media({
enabled: pinchZoomEnabled,
draggableUnZoomed: false,
inertiaFriction: 0.9,
doubleTapZoomOutOnMaxScale: true,
containerProps: {
className: 'media-zoom',
style: {

View file

@ -117,9 +117,10 @@ export default function Modals() {
instance={snapStates.showAccount?.instance}
onClose={({ destination } = {}) => {
states.showAccount = false;
if (destination) {
states.showAccounts = false;
}
// states.showGenericAccounts = false;
// if (destination) {
// states.showAccounts = false;
// }
}}
/>
</Modal>

View file

@ -1,3 +1,9 @@
.nav-menu section:last-child {
background-color: var(--bg-faded-color);
margin-bottom: -8px;
padding-bottom: 8px;
}
@media (min-width: 23em) {
.nav-menu {
display: grid;
@ -8,6 +14,7 @@
'left right';
padding: 0;
width: 22em;
max-width: calc(100vw - 16px);
}
.nav-menu .top-menu {
grid-area: top;
@ -27,7 +34,6 @@
}
}
.nav-menu section:last-child {
background-color: var(--bg-faded-color);
background-image: linear-gradient(
to right,
var(--divider-color) 1px,
@ -45,6 +51,15 @@
animation: phanpying 0.2s ease-in-out both;
border-top-right-radius: inherit;
border-bottom-right-radius: inherit;
margin-bottom: 0;
display: flex;
flex-direction: column;
.divider-grow {
flex-grow: 1;
height: auto;
background-color: transparent;
}
}
.nav-menu section:last-child > .szh-menu__divider:first-child {
display: none;

View file

@ -249,6 +249,7 @@ function NavMenu(props) {
<Icon icon="block" size="l" />
Blocked users&hellip;
</MenuItem>
<MenuDivider className="divider-grow" />
<MenuItem
onClick={() => {
states.showKeyboardShortcutsHelp = true;
@ -263,7 +264,7 @@ function NavMenu(props) {
}}
>
<Icon icon="shortcut" size="l" />{' '}
<span>Shortcuts Settings&hellip;</span>
<span>Shortcuts / Columns&hellip;</span>
</MenuItem>
<MenuItem
onClick={() => {

View file

@ -249,46 +249,45 @@ function ShortcutsSettings({ onClose }) {
</h2>
</header>
<main>
<p>
Specify a list of shortcuts that'll appear&nbsp;as:
<div class="shortcuts-view-mode">
{[
{
value: 'float-button',
label: 'Floating button',
imgURL: floatingButtonUrl,
},
{
value: 'tab-menu-bar',
label: 'Tab/Menu bar',
imgURL: tabMenuBarUrl,
},
{
value: 'multi-column',
label: 'Multi-column',
imgURL: multiColumnUrl,
},
].map(({ value, label, imgURL }) => (
<label>
<input
type="radio"
name="shortcuts-view-mode"
value={value}
checked={
snapStates.settings.shortcutsViewMode === value ||
(value === 'float-button' &&
!snapStates.settings.shortcutsViewMode)
}
onChange={(e) => {
states.settings.shortcutsViewMode = e.target.value;
}}
/>{' '}
<img src={imgURL} alt="" width="80" height="58" />{' '}
<span>{label}</span>
</label>
))}
</div>
{/* <select
<p>Specify a list of shortcuts that'll appear&nbsp;as:</p>
<div class="shortcuts-view-mode">
{[
{
value: 'float-button',
label: 'Floating button',
imgURL: floatingButtonUrl,
},
{
value: 'tab-menu-bar',
label: 'Tab/Menu bar',
imgURL: tabMenuBarUrl,
},
{
value: 'multi-column',
label: 'Multi-column',
imgURL: multiColumnUrl,
},
].map(({ value, label, imgURL }) => (
<label>
<input
type="radio"
name="shortcuts-view-mode"
value={value}
checked={
snapStates.settings.shortcutsViewMode === value ||
(value === 'float-button' &&
!snapStates.settings.shortcutsViewMode)
}
onChange={(e) => {
states.settings.shortcutsViewMode = e.target.value;
}}
/>{' '}
<img src={imgURL} alt="" width="80" height="58" />{' '}
<span>{label}</span>
</label>
))}
</div>
{/* <select
value={snapStates.settings.shortcutsViewMode || 'float-button'}
onChange={(e) => {
states.settings.shortcutsViewMode = e.target.value;
@ -298,7 +297,6 @@ function ShortcutsSettings({ onClose }) {
<option value="multi-column">Multi-column</option>
<option value="tab-menu-bar">Tab/Menu bar </option>
</select> */}
</p>
{/* <p>
<details>
<summary class="insignificant">

View file

@ -579,7 +579,11 @@ function Status({
try {
const done = await confirmBoostStatus();
if (!isSizeLarge && done) {
showToast(reblogged ? 'Unboosted' : 'Boosted');
showToast(
reblogged
? `Unboosted @${username || acct}'s post`
: `Boosted @${username || acct}'s post`,
);
}
} catch (e) {}
}}
@ -597,7 +601,11 @@ function Status({
try {
favouriteStatus();
if (!isSizeLarge) {
showToast(favourited ? 'Unfavourited' : 'Favourited');
showToast(
favourited
? `Unfavourited @${username || acct}'s post`
: `Favourited @${username || acct}'s post`,
);
}
} catch (e) {}
}}
@ -621,7 +629,11 @@ function Status({
try {
bookmarkStatus();
if (!isSizeLarge) {
showToast(bookmarked ? 'Unbookmarked' : 'Bookmarked');
showToast(
bookmarked
? `Unbookmarked @${username || acct}'s post`
: `Bookmarked @${username || acct}'s post`,
);
}
} catch (e) {}
}}
@ -829,7 +841,11 @@ function Status({
try {
favouriteStatus();
if (!isSizeLarge) {
showToast(favourited ? 'Unfavourited' : 'Favourited');
showToast(
favourited
? `Unfavourited @${username || acct}'s post`
: `Favourited @${username || acct}'s post`,
);
}
} catch (e) {}
},
@ -843,7 +859,11 @@ function Status({
try {
bookmarkStatus();
if (!isSizeLarge) {
showToast(bookmarked ? 'Unbookmarked' : 'Bookmarked');
showToast(
bookmarked
? `Unbookmarked @${username || acct}'s post`
: `Bookmarked @${username || acct}'s post`,
);
}
} catch (e) {}
},
@ -858,7 +878,11 @@ function Status({
try {
const done = await confirmBoostStatus();
if (!isSizeLarge && done) {
showToast(reblogged ? 'Unboosted' : 'Boosted');
showToast(
reblogged
? `Unboosted @${username || acct}'s post`
: `Boosted @${username || acct}'s post`,
);
}
} catch (e) {}
})();

View file

@ -334,7 +334,13 @@ function Timeline({
</button>
)}
</header>
{!!timelineStart && <div class="timeline-start">{timelineStart}</div>}
{!!timelineStart && (
<div
class={`timeline-start ${uiState === 'loading' ? 'loading' : ''}`}
>
{timelineStart}
</div>
)}
{!!items.length ? (
<>
<ul class="timeline">

View file

@ -258,7 +258,7 @@ function AccountStatuses() {
useItemID
boostsCarousel={snapStates.settings.boostsCarousel}
timelineStart={TimelineStart}
refresh={excludeReplies + excludeBoosts + tagged + media}
refresh={[excludeReplies, excludeBoosts, tagged, media].toString()}
headerEnd={
<Menu2
portal

View file

@ -152,7 +152,7 @@ function Search(props) {
</header>
<main>
{!!q && (
<div class="filter-bar">
<div class={`filter-bar ${uiState === 'loading' ? 'loading' : ''}`}>
{!!type && (
<Link to={`/search${q ? `?q=${encodeURIComponent(q)}` : ''}`}>
All

View file

@ -1062,7 +1062,7 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
onClick={() => setLimit((l) => l + LIMIT)}
style={{ marginBlockEnd: '6em' }}
>
<div class="ib">
<div class="ib avatars-bunch">
{/* show avatars for first 5 statuses */}
{statuses.slice(limit, limit + 5).map((status) => (
<Avatar

View file

@ -1,3 +1,5 @@
import mem from './mem';
const div = document.createElement('div');
function getHTMLText(html) {
if (!html) return '';
@ -10,4 +12,4 @@ function getHTMLText(html) {
return div.innerText.replace(/[\r\n]{3,}/g, '\n\n').trim();
}
export default getHTMLText;
export default mem(getHTMLText);

View file

@ -0,0 +1,23 @@
import { useEffect, useRef } from 'preact/hooks';
import { useLocation } from 'react-router-dom';
// Hook that runs a callback when the location changes
// Won't run on the first render
export default function useLocationChange(fn) {
if (!fn) return;
const location = useLocation();
const currentLocationRef = useRef(location.pathname);
useEffect(() => {
// console.log('location', {
// current: currentLocationRef.current,
// next: location.pathname,
// });
if (
currentLocationRef.current &&
location.pathname !== currentLocationRef.current
) {
fn?.();
}
}, [location.pathname, fn]);
}