commit
15c3979815
|
@ -11,8 +11,8 @@ Phanpy
|
||||||
|
|
||||||
This is an alternative web client for [Mastodon](https://joinmastodon.org/).
|
This is an alternative web client for [Mastodon](https://joinmastodon.org/).
|
||||||
|
|
||||||
🔗 **Production**: https://phanpy.social <br>
|
🔗 **Production**: https://phanpy.social (`production` branch)<br>
|
||||||
🔗 **Development**: https://dev.phanpy.social
|
🔗 **Development**: https://dev.phanpy.social (`main` branch, may break more often)
|
||||||
|
|
||||||
Everything is designed and engineered for my own use case, following my taste and vision. This is a personal side project for me to learn about Mastodon and experiment with new UI/UX ideas.
|
Everything is designed and engineered for my own use case, following my taste and vision. This is a personal side project for me to learn about Mastodon and experiment with new UI/UX ideas.
|
||||||
|
|
||||||
|
|
|
@ -143,6 +143,7 @@ export function App() {
|
||||||
window.masto = await login({
|
window.masto = await login({
|
||||||
url: `https://${instanceURL}`,
|
url: `https://${instanceURL}`,
|
||||||
accessToken,
|
accessToken,
|
||||||
|
disableVersionCheck: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const mastoAccount = await masto.accounts.verifyCredentials();
|
const mastoAccount = await masto.accounts.verifyCredentials();
|
||||||
|
@ -183,6 +184,7 @@ export function App() {
|
||||||
window.masto = await login({
|
window.masto = await login({
|
||||||
url: `https://${instanceURL}`,
|
url: `https://${instanceURL}`,
|
||||||
accessToken,
|
accessToken,
|
||||||
|
disableVersionCheck: true,
|
||||||
});
|
});
|
||||||
setIsLoggedIn(true);
|
setIsLoggedIn(true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -662,39 +662,40 @@ function Status({
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</span>{' '}
|
</span>{' '}
|
||||||
{size !== 'l' && uri ? (
|
{size !== 'l' &&
|
||||||
<a href={uri} target="_blank" class="time">
|
(uri ? (
|
||||||
<Icon
|
<a href={uri} target="_blank" class="time">
|
||||||
icon={visibilityIconsMap[visibility]}
|
<Icon
|
||||||
alt={visibility}
|
icon={visibilityIconsMap[visibility]}
|
||||||
size="s"
|
alt={visibility}
|
||||||
/>{' '}
|
size="s"
|
||||||
<relative-time
|
/>{' '}
|
||||||
datetime={createdAtDate.toISOString()}
|
<relative-time
|
||||||
format="micro"
|
datetime={createdAtDate.toISOString()}
|
||||||
threshold="P1D"
|
format="micro"
|
||||||
prefix=""
|
threshold="P1D"
|
||||||
>
|
prefix=""
|
||||||
{createdAtDate.toLocaleString()}
|
>
|
||||||
</relative-time>
|
{createdAtDate.toLocaleString()}
|
||||||
</a>
|
</relative-time>
|
||||||
) : (
|
</a>
|
||||||
<span class="time">
|
) : (
|
||||||
<Icon
|
<span class="time">
|
||||||
icon={visibilityIconsMap[visibility]}
|
<Icon
|
||||||
alt={visibility}
|
icon={visibilityIconsMap[visibility]}
|
||||||
size="s"
|
alt={visibility}
|
||||||
/>{' '}
|
size="s"
|
||||||
<relative-time
|
/>{' '}
|
||||||
datetime={createdAtDate.toISOString()}
|
<relative-time
|
||||||
format="micro"
|
datetime={createdAtDate.toISOString()}
|
||||||
threshold="P1D"
|
format="micro"
|
||||||
prefix=""
|
threshold="P1D"
|
||||||
>
|
prefix=""
|
||||||
{createdAtDate.toLocaleString()}
|
>
|
||||||
</relative-time>
|
{createdAtDate.toLocaleString()}
|
||||||
</span>
|
</relative-time>
|
||||||
)}
|
</span>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class={`content-container ${
|
class={`content-container ${
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { useEffect, useState } from 'preact/hooks';
|
||||||
|
|
||||||
import Compose from './components/compose';
|
import Compose from './components/compose';
|
||||||
import store from './utils/store';
|
import store from './utils/store';
|
||||||
|
import useTitle from './utils/useTitle';
|
||||||
|
|
||||||
if (window.opener) {
|
if (window.opener) {
|
||||||
console = window.opener.console;
|
console = window.opener.console;
|
||||||
|
@ -27,6 +28,7 @@ if (window.opener) {
|
||||||
window.masto = await login({
|
window.masto = await login({
|
||||||
url: `https://${instanceURL}`,
|
url: `https://${instanceURL}`,
|
||||||
accessToken,
|
accessToken,
|
||||||
|
disableVersionCheck: true,
|
||||||
});
|
});
|
||||||
console.info('Logged in successfully.');
|
console.info('Logged in successfully.');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -40,11 +42,15 @@ function App() {
|
||||||
|
|
||||||
const { editStatus, replyToStatus, draftStatus } = window.__COMPOSE__ || {};
|
const { editStatus, replyToStatus, draftStatus } = window.__COMPOSE__ || {};
|
||||||
|
|
||||||
useEffect(() => {
|
useTitle(
|
||||||
if (uiState === 'closed') {
|
editStatus
|
||||||
window.close();
|
? 'Editing source status'
|
||||||
}
|
: replyToStatus
|
||||||
}, [uiState]);
|
? `Replying to @${
|
||||||
|
replyToStatus.account?.acct || replyToStatus.account?.username
|
||||||
|
}`
|
||||||
|
: 'Compose',
|
||||||
|
);
|
||||||
|
|
||||||
if (uiState === 'closed') {
|
if (uiState === 'closed') {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -338,6 +338,7 @@ export default () => {
|
||||||
class="plain block"
|
class="plain block"
|
||||||
disabled={uiState === 'loading'}
|
disabled={uiState === 'loading'}
|
||||||
onClick={() => loadNotifications()}
|
onClick={() => loadNotifications()}
|
||||||
|
style={{ marginBlockEnd: '6em' }}
|
||||||
>
|
>
|
||||||
{uiState === 'loading' ? <Loader /> : <>Show more…</>}
|
{uiState === 'loading' ? <Loader /> : <>Show more…</>}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -111,18 +111,25 @@ export default ({ id }) => {
|
||||||
}, [heroStatus]);
|
}, [heroStatus]);
|
||||||
const heroContentText = useMemo(() => {
|
const heroContentText = useMemo(() => {
|
||||||
if (!heroStatus) return '';
|
if (!heroStatus) return '';
|
||||||
const { content } = heroStatus;
|
const { spoilerText, content } = heroStatus;
|
||||||
const div = document.createElement('div');
|
let text;
|
||||||
div.innerHTML = content;
|
if (spoilerText) {
|
||||||
let text = div.innerText.trim();
|
text = spoilerText;
|
||||||
|
} else {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.innerHTML = content;
|
||||||
|
text = div.innerText.trim();
|
||||||
|
}
|
||||||
if (text.length > 64) {
|
if (text.length > 64) {
|
||||||
|
// "The title should ideally be less than 64 characters in length"
|
||||||
|
// https://www.w3.org/Provider/Style/TITLE.html
|
||||||
text = text.slice(0, 64) + '…';
|
text = text.slice(0, 64) + '…';
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
}, [heroStatus]);
|
}, [heroStatus]);
|
||||||
useTitle(
|
useTitle(
|
||||||
heroDisplayName && heroContentText
|
heroDisplayName && heroContentText
|
||||||
? `${heroDisplayName}: ${heroContentText}`
|
? `${heroDisplayName}: "${heroContentText}"`
|
||||||
: 'Status',
|
: 'Status',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,6 @@ const { VITE_CLIENT_NAME: CLIENT_NAME } = import.meta.env;
|
||||||
|
|
||||||
export default (title) => {
|
export default (title) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = title ? `${title} - ${CLIENT_NAME}` : CLIENT_NAME;
|
document.title = title ? `${title} / ${CLIENT_NAME}` : CLIENT_NAME;
|
||||||
}, [title]);
|
}, [title]);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue