Porównaj commity

...

19 Commity

Autor SHA1 Wiadomość Data
Alyx ba5e172440
Merge fa196a2c94 into 015ed5e7eb 2024-04-05 12:11:17 +02:00
Lim Chee Aun 015ed5e7eb Further expand usage of SubMenu2 2024-04-04 17:03:30 +08:00
Lim Chee Aun 2ad9706304 Further utilize lazy shazam 2024-04-04 14:34:28 +08:00
Lim Chee Aun 30382d088b Possible fix for menus again 2024-04-04 14:34:04 +08:00
Lim Chee Aun 80196f83ca Revert "Test if this fixes submenu not opening"
This reverts commit 49fa48bd28.
2024-04-04 14:29:46 +08:00
Lim Chee Aun 419ad34250 Revert "Test another fix for submenus not opening"
This reverts commit a7cc0785f9.
2024-04-04 14:29:35 +08:00
Lim Chee Aun ed0d714cf2 Just a little spacing fix 2024-04-03 22:51:29 +08:00
Lim Chee Aun 708976a9e9 Anything Intl always need to extract out
and memoized
2024-04-03 19:48:18 +08:00
Lim Chee Aun d77ba19308 Handle another kind of emojiReaction response
Can't everyone just standardize the responses?
2024-04-03 17:58:37 +08:00
Lim Chee Aun b10e22a9a2 Better fallbacks 2024-04-03 17:57:15 +08:00
Lim Chee Aun 36d8b62e1e Height adjustments when switching between poll form and results 2024-04-03 16:14:59 +08:00
Lim Chee Aun 989e788d8e Slight delay is needed 2024-04-03 16:06:37 +08:00
Lim Chee Aun ebd9f05f69 Preload IntlSegmenter polyfill if needed 2024-04-03 14:33:53 +08:00
Lim Chee Aun 5246af4ae9 Undo lazy component experiment
Doesn't make much difference
2024-04-03 14:33:19 +08:00
Lim Chee Aun e6ba72f4c8 'Remove follower' menu item 2024-04-03 11:54:46 +08:00
Lim Chee Aun 960dff8b9e Make lazy shazam ignore top sticky header 2024-04-03 11:53:03 +08:00
Lim Chee Aun e3c25d25ee Add menus to view profile image and header 2024-04-03 09:29:23 +08:00
Lim Chee Aun 090320150a Select text too when pressing / 2024-04-03 09:28:59 +08:00
Alyx fa196a2c94
Add Dockerfile 2024-03-18 09:52:29 +01:00
16 zmienionych plików z 192 dodań i 86 usunięć

23
Dockerfile 100644
Wyświetl plik

@ -0,0 +1,23 @@
FROM busybox:1 AS build
ARG PHANPY_RELEASE_VERSION
WORKDIR /root/phanpy_release
RUN wget "https://github.com/cheeaun/phanpy/releases/download/${PHANPY_RELEASE_VERSION}/phanpy-dist.tar.gz" && \
tar -xvf "phanpy-dist.tar.gz" -C /root/phanpy_release && \
rm "phanpy-dist.tar.gz"
# ---
FROM busybox:1
# Create a non-root user to own the files and run our server
RUN adduser -D static
USER static
WORKDIR /home/static
# Copy the static website
# Use the .dockerignore file to control what ends up inside the image!
COPY --chown=static:static --from=build /root/phanpy_release /home/static
# Run BusyBox httpd
CMD ["httpd", "-f", "-v", "-p", "8080"]

Wyświetl plik

@ -1,7 +1,6 @@
import './app.css';
import debounce from 'just-debounce-it';
import { lazy, Suspense } from 'preact/compat';
import {
useEffect,
useLayoutEffect,
@ -18,14 +17,14 @@ import ComposeButton from './components/compose-button';
import { ICONS } from './components/ICONS';
import KeyboardShortcutsHelp from './components/keyboard-shortcuts-help';
import Loader from './components/loader';
// import Modals from './components/modals';
import Modals from './components/modals';
import NotificationService from './components/notification-service';
import SearchCommand from './components/search-command';
import Shortcuts from './components/shortcuts';
import NotFound from './pages/404';
import AccountStatuses from './pages/account-statuses';
import Bookmarks from './pages/bookmarks';
// import Catchup from './pages/catchup';
import Catchup from './pages/catchup';
import Favourites from './pages/favourites';
import Filters from './pages/filters';
import FollowedHashtags from './pages/followed-hashtags';
@ -57,9 +56,6 @@ import store from './utils/store';
import { getCurrentAccount } from './utils/store-utils';
import './utils/toast-alert';
const Catchup = lazy(() => import('./pages/catchup'));
const Modals = lazy(() => import('./components/modals'));
window.__STATES__ = states;
window.__STATES_STATS__ = () => {
const keys = [
@ -387,9 +383,7 @@ function App() {
)}
{isLoggedIn && <ComposeButton />}
{isLoggedIn && <Shortcuts />}
<Suspense>
<Modals />
</Suspense>
<Modals />
{isLoggedIn && <NotificationService />}
<BackgroundService isLoggedIn={isLoggedIn} />
{uiState !== 'loading' && <SearchCommand onClose={focusDeck} />}
@ -466,14 +460,7 @@ function SecondaryRoutes({ isLoggedIn }) {
</Route>
<Route path="/fh" element={<FollowedHashtags />} />
<Route path="/ft" element={<Filters />} />
<Route
path="/catchup"
element={
<Suspense>
<Catchup />
</Suspense>
}
/>
<Route path="/catchup" element={<Catchup />} />
</>
)}
<Route path="/:instance?/t/:hashtag" element={<Hashtag />} />

Wyświetl plik

@ -107,4 +107,5 @@ export const ICONS = {
quote: () => import('@iconify-icons/mingcute/quote-left-line'),
settings: () => import('@iconify-icons/mingcute/settings-6-line'),
'heart-break': () => import('@iconify-icons/mingcute/heart-crack-line'),
'user-x': () => import('@iconify-icons/mingcute/user-x-line'),
};

Wyświetl plik

@ -1,6 +1,6 @@
import './account-info.css';
import { Menu, MenuDivider, MenuItem, SubMenu } from '@szhsin/react-menu';
import { MenuDivider, MenuItem } from '@szhsin/react-menu';
import {
useCallback,
useEffect,
@ -33,7 +33,9 @@ import ListAddEdit from './list-add-edit';
import Loader from './loader';
import Menu2 from './menu2';
import MenuConfirm from './menu-confirm';
import MenuLink from './menu-link';
import Modal from './modal';
import SubMenu2 from './submenu2';
import TranslationBlock from './translation-block';
const MUTE_DURATIONS = [
@ -582,6 +584,15 @@ function AccountInfo({
<Icon icon="external" />
<span>Go to original profile page</span>
</MenuItem>
<MenuDivider />
<MenuLink href={info.avatar} target="_blank">
<Icon icon="user" />
<span>View profile image</span>
</MenuLink>
<MenuLink href={info.header} target="_blank">
<Icon icon="media" />
<span>View profile header</span>
</MenuLink>
</Menu2>
) : (
<AccountBlock
@ -660,6 +671,7 @@ function AccountInfo({
// states.showAccount = false;
setTimeout(() => {
states.showGenericAccounts = {
id: 'followers',
heading: 'Followers',
fetchAccounts: fetchFollowers,
instance,
@ -1273,7 +1285,7 @@ function RelatedActions({
<span>Unmute @{username}</span>
</MenuItem>
) : (
<SubMenu
<SubMenu2
menuClassName="menu-blur"
openTrigger="clickOnly"
direction="bottom"
@ -1327,7 +1339,44 @@ function RelatedActions({
</MenuItem>
))}
</div>
</SubMenu>
</SubMenu2>
)}
{followedBy && (
<MenuConfirm
subMenu
menuItemClassName="danger"
confirmLabel={
<>
<Icon icon="user-x" />
<span>Remove @{username} from followers?</span>
</>
}
onClick={() => {
setRelationshipUIState('loading');
(async () => {
try {
const newRelationship = await currentMasto.v1.accounts
.$select(currentInfo?.id || id)
.removeFromFollowers();
console.log(
'removing from followers',
newRelationship,
);
setRelationship(newRelationship);
setRelationshipUIState('default');
showToast(`@${username} removed from followers`);
states.reloadGenericAccounts.id = 'followers';
states.reloadGenericAccounts.counter++;
} catch (e) {
console.error(e);
setRelationshipUIState('error');
}
})();
}}
>
<Icon icon="user-x" />
<span>Remove follower</span>
</MenuConfirm>
)}
<MenuConfirm
subMenu

Wyświetl plik

@ -1,9 +1,11 @@
export default function CustomEmoji({ staticUrl, alt, url }) {
return (
<picture>
<source srcset={staticUrl} media="(prefers-reduced-motion: reduce)" />
{staticUrl && (
<source srcset={staticUrl} media="(prefers-reduced-motion: reduce)" />
)}
<img
key={alt}
key={alt || url}
src={url}
alt={alt}
class="shortcode-emoji emoji"

Wyświetl plik

@ -6,6 +6,15 @@ import Loader from './loader';
const supportsIntlSegmenter = !shouldPolyfill();
// Preload IntlSegmenter
setTimeout(() => {
queueMicrotask(() => {
if (!supportsIntlSegmenter) {
import('@formatjs/intl-segmenter/polyfill-force').catch(() => {});
}
});
}, 1000);
export default function IntlSegmenterSuspense({ children }) {
if (supportsIntlSegmenter) {
return <Suspense fallback={<Loader />}>{children}</Suspense>;

Wyświetl plik

@ -1,9 +1,12 @@
/*
Rendered but hidden. Only show when visible
*/
import { useLayoutEffect, useRef, useState } from 'preact/hooks';
import { useEffect, useRef, useState } from 'preact/hooks';
import { useInView } from 'react-intersection-observer';
// The sticky header, usually at the top
const TOP = 48;
export default function LazyShazam({ children }) {
const containerRef = useRef();
const [visible, setVisible] = useState(false);
@ -11,6 +14,7 @@ export default function LazyShazam({ children }) {
const { ref } = useInView({
root: null,
rootMargin: `-${TOP}px 0px 0px 0px`,
trackVisibility: true,
delay: 1000,
onChange: (inView) => {
@ -22,11 +26,15 @@ export default function LazyShazam({ children }) {
skip: visibleStart || visible,
});
useLayoutEffect(() => {
useEffect(() => {
if (!containerRef.current) return;
const rect = containerRef.current.getBoundingClientRect();
if (rect.bottom > 0) {
setVisibleStart(true);
if (rect.bottom > TOP) {
if (rect.top < window.innerHeight) {
setVisible(true);
} else {
setVisibleStart(true);
}
}
}, []);

Wyświetl plik

@ -1,8 +1,8 @@
import { MenuItem, SubMenu } from '@szhsin/react-menu';
import { MenuItem } from '@szhsin/react-menu';
import { cloneElement } from 'preact';
import { useRef } from 'preact/hooks';
import Menu2 from './menu2';
import SubMenu2 from './submenu2';
function MenuConfirm({
subMenu = false,
@ -23,11 +23,9 @@ function MenuConfirm({
}
return children;
}
const Parent = subMenu ? SubMenu : Menu2;
const menuRef = useRef();
const Parent = subMenu ? SubMenu2 : Menu2;
return (
<Parent
instanceRef={menuRef}
openTrigger="clickOnly"
direction="bottom"
overflow="auto"
@ -37,19 +35,6 @@ function MenuConfirm({
{...restProps}
menuButton={subMenu ? undefined : children}
label={subMenu ? children : undefined}
// Test fix for bug; submenus not opening on Android
itemProps={{
onPointerMove: (e) => {
if (e.pointerType === 'touch') {
menuRef.current?.openMenu?.();
}
},
onPointerLeave: (e) => {
if (e.pointerType === 'touch') {
menuRef.current?.openMenu?.();
}
},
}}
>
<MenuItem className={menuItemClassName} onClick={onClick}>
{confirmLabel}

Wyświetl plik

@ -1,11 +1,6 @@
import './nav-menu.css';
import {
ControlledMenu,
MenuDivider,
MenuItem,
SubMenu,
} from '@szhsin/react-menu';
import { ControlledMenu, MenuDivider, MenuItem } from '@szhsin/react-menu';
import { memo } from 'preact/compat';
import { useEffect, useMemo, useRef, useState } from 'preact/hooks';
import { useLongPress } from 'use-long-press';
@ -20,8 +15,7 @@ import store from '../utils/store';
import Avatar from './avatar';
import Icon from './icon';
import MenuLink from './menu-link';
const supportsTouch = 'ontouchstart' in window;
import SubMenu2 from './submenu2';
function NavMenu(props) {
const snapStates = useSnapshot(states);
@ -150,7 +144,7 @@ function NavMenu(props) {
}}
{...props}
overflow="auto"
// viewScroll="close"
viewScroll="close"
position="anchor"
align="center"
boundingBoxPadding={boundingBoxPadding}
@ -211,8 +205,7 @@ function NavMenu(props) {
</MenuLink>
)}
{lists?.length > 0 ? (
<SubMenu
openTrigger={supportsTouch ? 'clickOnly' : undefined}
<SubMenu2
menuClassName="nav-submenu"
overflow="auto"
gap={-8}
@ -237,7 +230,7 @@ function NavMenu(props) {
))}
</>
)}
</SubMenu>
</SubMenu2>
) : (
<MenuLink to="/l">
<Icon icon="list" size="l" />
@ -247,8 +240,7 @@ function NavMenu(props) {
<MenuLink to="/b">
<Icon icon="bookmark" size="l" /> <span>Bookmarks</span>
</MenuLink>
<SubMenu
openTrigger={supportsTouch ? 'clickOnly' : undefined}
<SubMenu2
menuClassName="nav-submenu"
overflow="auto"
gap={-8}
@ -297,7 +289,7 @@ function NavMenu(props) {
<Icon icon="block" size="l" />
Blocked users&hellip;
</MenuItem>{' '}
</SubMenu>
</SubMenu2>
<MenuDivider />
<MenuItem
onClick={() => {

Wyświetl plik

@ -1,6 +1,6 @@
import './shortcuts.css';
import { MenuDivider, SubMenu } from '@szhsin/react-menu';
import { MenuDivider } from '@szhsin/react-menu';
import { memo } from 'preact/compat';
import { useRef, useState } from 'preact/hooks';
import { useHotkeys } from 'react-hotkeys-hook';
@ -17,6 +17,7 @@ import Icon from './icon';
import Link from './link';
import Menu2 from './menu2';
import MenuLink from './menu-link';
import SubMenu2 from './submenu2';
function Shortcuts() {
const { instance } = api();
@ -182,7 +183,7 @@ function Shortcuts() {
{formattedShortcuts.map(({ id, path, title, subtitle, icon }, i) => {
if (id === 'lists') {
return (
<SubMenu
<SubMenu2
menuClassName="glass-menu"
overflow="auto"
gap={-8}
@ -205,7 +206,7 @@ function Shortcuts() {
<span>{list.title}</span>
</MenuLink>
))}
</SubMenu>
</SubMenu2>
);
}

Wyświetl plik

@ -1695,13 +1695,14 @@ a.card:is(:hover, :focus):visited {
}
.poll-label input:is([type='radio'], [type='checkbox']) {
flex-shrink: 0;
margin: 3px;
min-height: 1em;
margin: 0 3px;
min-height: 0.9em;
}
.poll-option-votes {
flex-shrink: 0;
font-size: 90%;
opacity: 0.75;
line-height: 1;
}
.poll-option-leading .poll-option-votes {
font-weight: bold;

Wyświetl plik

@ -1943,7 +1943,24 @@ function Status({
{!!emojiReactions?.length && (
<div class="emoji-reactions">
{emojiReactions.map((emojiReaction) => {
const { name, count, me } = emojiReaction;
const { name, count, me, url, staticUrl } = emojiReaction;
if (url) {
// Some servers return url and staticUrl
return (
<span
class={`emoji-reaction tag ${
me ? '' : 'insignificant'
}`}
>
<CustomEmoji
alt={name}
url={url}
staticUrl={staticUrl}
/>{' '}
{count}
</span>
);
}
const isShortCode = /^:.+?:$/.test(name);
if (isShortCode) {
const emoji = emojis.find(
@ -1962,7 +1979,7 @@ function Status({
alt={name}
url={emoji.url}
staticUrl={emoji.staticUrl}
/>
/>{' '}
{count}
</span>
);

Wyświetl plik

@ -0,0 +1,25 @@
import { SubMenu } from '@szhsin/react-menu';
import { useRef } from 'preact/hooks';
export default function SubMenu2(props) {
const menuRef = useRef();
return (
<SubMenu
{...props}
instanceRef={menuRef}
// Test fix for bug; submenus not opening on Android
itemProps={{
onPointerMove: (e) => {
if (e.pointerType === 'touch') {
menuRef.current?.openMenu?.();
}
},
onPointerLeave: (e) => {
if (e.pointerType === 'touch') {
menuRef.current?.openMenu?.();
}
},
}}
/>
);
}

Wyświetl plik

@ -10,6 +10,7 @@ import localeCode2Text from '../utils/localeCode2Text';
import pmem from '../utils/pmem';
import Icon from './icon';
import LazyShazam from './lazy-shazam';
import Loader from './loader';
const { PHANPY_LINGVA_INSTANCES } = import.meta.env;
@ -142,23 +143,21 @@ function TranslationBlock({
detectedLang !== targetLangText
) {
return (
<div class="shazam-container">
<div class="shazam-container-inner">
<div class="status-translation-block-mini">
<Icon
icon="translate"
alt={`Auto-translated from ${sourceLangText}`}
/>
<output
lang={targetLang}
dir="auto"
title={pronunciationContent || ''}
>
{translatedContent}
</output>
</div>
<LazyShazam>
<div class="status-translation-block-mini">
<Icon
icon="translate"
alt={`Auto-translated from ${sourceLangText}`}
/>
<output
lang={targetLang}
dir="auto"
title={pronunciationContent || ''}
>
{translatedContent}
</output>
</div>
</div>
</LazyShazam>
);
}
return null;

Wyświetl plik

@ -177,6 +177,7 @@ function Search({ columnMode, ...props }) {
['/', 'Slash'],
(e) => {
searchFormRef.current?.focus?.();
searchFormRef.current?.select?.();
},
{
preventDefault: true,

Wyświetl plik

@ -1,10 +1,16 @@
export default function localeCode2Text(code) {
import mem from './mem';
const IntlDN = new Intl.DisplayNames(navigator.languages, {
type: 'language',
});
function _localeCode2Text(code) {
try {
return new Intl.DisplayNames(navigator.languages, {
type: 'language',
}).of(code);
return IntlDN.of(code);
} catch (e) {
console.error(e);
return null;
}
}
export default mem(_localeCode2Text);