More code porting

This commit is contained in:
Lim Chee Aun 2023-02-08 19:11:33 +08:00
parent 9921e487e8
commit f511b0a5ab
9 changed files with 282 additions and 240 deletions

View file

@ -84,43 +84,46 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
}
.deck > header {
min-height: 3em;
position: sticky;
top: 0;
background-color: var(--bg-blur-color);
background-image: linear-gradient(to bottom, var(--bg-color), transparent);
backdrop-filter: saturate(180%) blur(20px);
border-bottom: var(--hairline-width) solid var(--divider-color);
z-index: 1;
cursor: default;
z-index: 10;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
align-items: center;
user-select: none;
transition: transform 0.5s ease-in-out;
user-select: none;
}
.deck > header[hidden] {
display: block;
transform: translateY(-100%);
pointer-events: none;
user-select: none;
}
.deck > header > .header-side:last-of-type {
.deck > header .header-grid {
background-color: var(--bg-blur-color);
background-image: linear-gradient(to bottom, var(--bg-color), transparent);
backdrop-filter: saturate(180%) blur(20px);
border-bottom: var(--hairline-width) solid var(--divider-color);
min-height: 3em;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
align-items: center;
}
.deck > header .header-grid > .header-side:last-of-type {
text-align: right;
grid-column: 3;
}
.deck > header :is(button, .button).plain {
.deck > header .header-grid :is(button, .button).plain {
backdrop-filter: none;
}
.deck > header h1 {
.deck > header .header-grid h1 {
margin: 0 8px;
padding: 0;
font-size: 1.2em;
text-align: center;
white-space: nowrap;
}
.deck > header h1:first-child {
.deck > header .header-grid h1:first-child {
text-align: left;
padding-left: 8px;
}
@ -1211,14 +1214,16 @@ meter.donut:is(.danger, .explode):after {
}
.timeline-deck > header {
--margin-top: 8px;
min-height: 4em;
top: var(--margin-top);
border-bottom: 0;
background-color: var(--bg-faded-blur-color);
background-image: none;
margin-inline: 8px;
}
.timeline-deck > header .header-grid {
border-bottom: 0;
border-radius: 16px;
margin-inline: 8px;
background-color: var(--bg-faded-blur-color);
background-image: none;
border-radius: 16px;
min-height: 4em;
}
.timeline-deck > header[hidden] {
transform: translate3d(0, calc((100% + var(--margin-top)) * -1), 0);

View file

@ -2,6 +2,7 @@ import { useEffect, useRef, useState } from 'preact/hooks';
import { useHotkeys } from 'react-hotkeys-hook';
import { useDebouncedCallback } from 'use-debounce';
import useInterval from '../utils/useInterval';
import usePageVisibility from '../utils/usePageVisibility';
import useScroll from '../utils/useScroll';
@ -21,11 +22,13 @@ function Timeline({
boostsCarousel,
fetchItems = () => {},
checkForUpdates = () => {},
checkForUpdatesInterval = 60_000, // 1 minute
}) {
const [items, setItems] = useState([]);
const [uiState, setUIState] = useState('default');
const [showMore, setShowMore] = useState(false);
const [showNew, setShowNew] = useState(false);
const [visible, setVisible] = useState(true);
const scrollableRef = useRef();
const loadItems = useDebouncedCallback(
@ -185,9 +188,8 @@ function Timeline({
usePageVisibility(
(visible) => {
if (visible) {
if (lastHiddenTime.current) {
const timeDiff = Date.now() - lastHiddenTime.current;
if (timeDiff > 1000 * 60) {
if (!lastHiddenTime.current || timeDiff > 1000 * 60) {
(async () => {
console.log('✨ Check updates');
const hasUpdate = await checkForUpdates();
@ -197,14 +199,29 @@ function Timeline({
}
})();
}
}
} else {
lastHiddenTime.current = Date.now();
}
setVisible(visible);
},
[checkForUpdates],
);
// checkForUpdates interval
useInterval(
() => {
(async () => {
console.log('✨ Check updates');
const hasUpdate = await checkForUpdates();
if (hasUpdate) {
console.log('✨ Has new updates');
setShowNew(true);
}
})();
},
visible && !showNew ? checkForUpdatesInterval : null,
);
const hiddenUI = scrollDirection === 'end' && !nearReachStart;
return (
@ -231,6 +248,7 @@ function Timeline({
}
}}
>
<div class="header-grid">
<div class="header-side">
<Link to="/" class="button plain">
<Icon icon="home" size="l" />
@ -240,6 +258,7 @@ function Timeline({
<div class="header-side">
<Loader hidden={uiState !== 'loading'} />
</div>
</div>
{items.length > 0 &&
uiState !== 'loading' &&
!hiddenUI &&

View file

@ -61,7 +61,8 @@ function Following() {
}
const ws = useRef();
async function streamUser() {
const streamUser = async () => {
console.log('🎏 Start streaming user', ws.current);
if (
ws.current &&
(ws.current.readyState === WebSocket.CONNECTING ||
@ -72,7 +73,8 @@ function Following() {
}
const stream = await masto.v1.stream.streamUser();
ws.current = stream.ws;
console.log('🎏 Streaming user');
ws.current.__id = Math.random();
console.log('🎏 Streaming user', ws.current);
stream.on('status.update', (status) => {
console.log(`🔄 Status ${status.id} updated`);
@ -86,14 +88,20 @@ function Following() {
if (s) s._deleted = true;
});
stream.ws.onclose = () => {
console.log('🎏 Streaming user closed');
};
return stream;
}
};
useEffect(() => {
streamUser();
let stream;
(async () => {
stream = await streamUser();
})();
return () => {
if (ws.current) {
console.log('🎏 Closing streaming user');
ws.current.close();
if (stream) {
stream.ws.close();
ws.current = null;
}
};

View file

@ -320,6 +320,7 @@ function Home({ hidden }) {
loadStatuses(true);
}}
>
<div class="header-grid">
<div class="header-side">
<button
type="button"
@ -348,7 +349,7 @@ function Home({ hidden }) {
<Icon icon="notification" size="l" alt="Notifications" />
</Link>
</div>
</header>
</div>
{snapStates.homeNew.length > 0 &&
uiState !== 'loading' &&
((scrollDirection === 'start' &&
@ -361,7 +362,8 @@ function Home({ hidden }) {
onClick={() => {
if (!snapStates.settings.boostsCarousel) {
const uniqueHomeNew = snapStates.homeNew.filter(
(status) => !states.home.some((s) => s.id === status.id),
(status) =>
!states.home.some((s) => s.id === status.id),
);
states.home.unshift(...uniqueHomeNew);
}
@ -377,6 +379,7 @@ function Home({ hidden }) {
<Icon icon="arrow-up" /> New posts
</button>
)}
</header>
{snapStates.home.length ? (
<>
<ul class="timeline">

View file

@ -143,6 +143,7 @@ function Notifications() {
scrollableRef.current?.scrollTo({ top: 0, behavior: 'smooth' });
}}
>
<div class="header-grid">
<div class="header-side">
<Link to="/" class="button plain">
<Icon icon="home" size="l" />
@ -152,6 +153,7 @@ function Notifications() {
<div class="header-side">
<Loader hidden={uiState !== 'loading'} />
</div>
</div>
</header>
{snapStates.notificationsNew.length > 0 && uiState !== 'loading' && (
<button

View file

@ -2,8 +2,6 @@
grid-column: 1 / 3;
}
.status-deck header {
display: flex;
align-items: center;
white-space: nowrap;
}
.status-deck header h1 {

View file

@ -469,6 +469,7 @@ function StatusPage() {
<Icon icon="chevron-left" size="xl" />
</Link>
</div> */}
<div class="header-grid">
<h1>
{!heroInView && heroStatus && uiState !== 'loading' ? (
<>
@ -557,7 +558,8 @@ function StatusPage() {
});
}}
>
<Icon icon="eye-open" /> <span>Show all sensitive content</span>
<Icon icon="eye-open" />{' '}
<span>Show all sensitive content</span>
</MenuItem>
{import.meta.env.DEV && !authenticated && (
<MenuItem
@ -596,6 +598,7 @@ function StatusPage() {
<Icon icon="x" size="xl" />
</Link>
</div>
</div>
</header>
{!!statuses.length && heroStatus ? (
<ul

View file

@ -1,22 +1,25 @@
// useInterval with Preact
import { useEffect, useRef } from 'preact/hooks';
export default function useInterval(callback, delay) {
const savedCallback = useRef();
const noop = () => {};
function useInterval(callback, delay, immediate) {
const savedCallback = useRef(noop);
// Remember the latest callback.
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
}, []);
// Set up the interval.
useEffect(() => {
function tick() {
if (!immediate || delay === null || delay === false) return;
savedCallback.current();
}
if (delay !== null) {
let id = setInterval(tick, delay);
}, [immediate]);
useEffect(() => {
if (delay === null || delay === false) return;
const tick = () => savedCallback.current();
const id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
}
export default useInterval;

View file

@ -4,6 +4,7 @@ export default function usePageVisibility(fn = () => {}, deps = []) {
useEffect(() => {
const handleVisibilityChange = () => {
const hidden = document.hidden || document.visibilityState === 'hidden';
console.log('👀 Page visibility changed', hidden);
fn(!hidden);
};