commit
375da8d173
|
@ -1358,6 +1358,9 @@ body:has(.media-modal-container + .status-deck) .media-post-link {
|
||||||
.tag.collapsed {
|
.tag.collapsed {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
.tag.danger {
|
||||||
|
background-color: var(--red-color);
|
||||||
|
}
|
||||||
|
|
||||||
/* MENU POPUP */
|
/* MENU POPUP */
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import shortenNumber from '../utils/shorten-number';
|
||||||
import showToast from '../utils/show-toast';
|
import showToast from '../utils/show-toast';
|
||||||
import states, { hideAllModals } from '../utils/states';
|
import states, { hideAllModals } from '../utils/states';
|
||||||
import store from '../utils/store';
|
import store from '../utils/store';
|
||||||
|
import { updateAccount } from '../utils/store-utils';
|
||||||
|
|
||||||
import AccountBlock from './account-block';
|
import AccountBlock from './account-block';
|
||||||
import Avatar from './avatar';
|
import Avatar from './avatar';
|
||||||
|
@ -483,6 +484,12 @@ function RelatedActions({ info, instance, authenticated }) {
|
||||||
}
|
}
|
||||||
}, [info, authenticated]);
|
}, [info, authenticated]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (info && isSelf) {
|
||||||
|
updateAccount(info);
|
||||||
|
}
|
||||||
|
}, [info, isSelf]);
|
||||||
|
|
||||||
const loading = relationshipUIState === 'loading';
|
const loading = relationshipUIState === 'loading';
|
||||||
const menuInstanceRef = useRef(null);
|
const menuInstanceRef = useRef(null);
|
||||||
|
|
||||||
|
@ -524,6 +531,7 @@ function RelatedActions({ info, instance, authenticated }) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="actions">
|
<p class="actions">
|
||||||
|
<span>
|
||||||
{followedBy ? (
|
{followedBy ? (
|
||||||
<span class="tag">Following you</span>
|
<span class="tag">Following you</span>
|
||||||
) : !!lastStatusAt ? (
|
) : !!lastStatusAt ? (
|
||||||
|
@ -535,7 +543,10 @@ function RelatedActions({ info, instance, authenticated }) {
|
||||||
</small>
|
</small>
|
||||||
) : (
|
) : (
|
||||||
<span />
|
<span />
|
||||||
)}{' '}
|
)}
|
||||||
|
{muting && <span class="tag danger">Muted</span>}
|
||||||
|
{blocking && <span class="tag danger">Blocked</span>}
|
||||||
|
</span>{' '}
|
||||||
<span class="buttons">
|
<span class="buttons">
|
||||||
<Menu
|
<Menu
|
||||||
instanceRef={menuInstanceRef}
|
instanceRef={menuInstanceRef}
|
||||||
|
|
|
@ -12,6 +12,8 @@ import Icon from './icon';
|
||||||
import Link from './link';
|
import Link from './link';
|
||||||
import { formatDuration } from './status';
|
import { formatDuration } from './status';
|
||||||
|
|
||||||
|
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); // https://stackoverflow.com/a/23522755
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Media type
|
Media type
|
||||||
===
|
===
|
||||||
|
@ -117,6 +119,20 @@ function Media({ media, to, showOriginal, autoAnimate, onClick = () => {} }) {
|
||||||
if (isImage) {
|
if (isImage) {
|
||||||
// Note: type: unknown might not have width/height
|
// Note: type: unknown might not have width/height
|
||||||
quickPinchZoomProps.containerProps.style.display = 'inherit';
|
quickPinchZoomProps.containerProps.style.display = 'inherit';
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
if (!isSafari) return;
|
||||||
|
if (!showOriginal) return;
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
await fetch(mediaURL, { mode: 'no-cors' });
|
||||||
|
mediaRef.current.src = mediaURL;
|
||||||
|
} catch (e) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}, [mediaURL]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Parent
|
<Parent
|
||||||
ref={parentRef}
|
ref={parentRef}
|
||||||
|
@ -170,6 +186,7 @@ function Media({ media, to, showOriginal, autoAnimate, onClick = () => {} }) {
|
||||||
}}
|
}}
|
||||||
onLoad={(e) => {
|
onLoad={(e) => {
|
||||||
e.target.closest('.media-image').style.backgroundImage = '';
|
e.target.closest('.media-image').style.backgroundImage = '';
|
||||||
|
e.target.dataset.loaded = true;
|
||||||
}}
|
}}
|
||||||
onError={(e) => {
|
onError={(e) => {
|
||||||
const { src } = e.target;
|
const { src } = e.target;
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
import './search.css';
|
import './search.css';
|
||||||
|
|
||||||
import { forwardRef } from 'preact/compat';
|
import { forwardRef } from 'preact/compat';
|
||||||
import { useEffect, useImperativeHandle, useRef, useState } from 'preact/hooks';
|
import {
|
||||||
|
useEffect,
|
||||||
|
useImperativeHandle,
|
||||||
|
useLayoutEffect,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from 'preact/hooks';
|
||||||
|
import { InView } from 'react-intersection-observer';
|
||||||
import { useParams, useSearchParams } from 'react-router-dom';
|
import { useParams, useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
import AccountBlock from '../components/account-block';
|
import AccountBlock from '../components/account-block';
|
||||||
|
@ -13,6 +20,9 @@ import Status from '../components/status';
|
||||||
import { api } from '../utils/api';
|
import { api } from '../utils/api';
|
||||||
import useTitle from '../utils/useTitle';
|
import useTitle from '../utils/useTitle';
|
||||||
|
|
||||||
|
const SHORT_LIMIT = 5;
|
||||||
|
const LIMIT = 40;
|
||||||
|
|
||||||
function Search(props) {
|
function Search(props) {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const { masto, instance, authenticated } = api({
|
const { masto, instance, authenticated } = api({
|
||||||
|
@ -40,35 +50,78 @@ function Search(props) {
|
||||||
`/search`,
|
`/search`,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [showMore, setShowMore] = useState(false);
|
||||||
|
const offsetRef = useRef(0);
|
||||||
|
useEffect(() => {
|
||||||
|
offsetRef.current = 0;
|
||||||
|
}, [type]);
|
||||||
|
|
||||||
|
const scrollableRef = useRef();
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
scrollableRef.current?.scrollTo?.(0, 0);
|
||||||
|
}, [q, type]);
|
||||||
|
|
||||||
const [statusResults, setStatusResults] = useState([]);
|
const [statusResults, setStatusResults] = useState([]);
|
||||||
const [accountResults, setAccountResults] = useState([]);
|
const [accountResults, setAccountResults] = useState([]);
|
||||||
const [hashtagResults, setHashtagResults] = useState([]);
|
const [hashtagResults, setHashtagResults] = useState([]);
|
||||||
|
|
||||||
|
function loadResults(firstLoad) {
|
||||||
|
setUiState('loading');
|
||||||
|
if (firstLoad && !type) {
|
||||||
|
setStatusResults(statusResults.slice(0, SHORT_LIMIT));
|
||||||
|
setAccountResults(accountResults.slice(0, SHORT_LIMIT));
|
||||||
|
setHashtagResults(hashtagResults.slice(0, SHORT_LIMIT));
|
||||||
|
}
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const params = {
|
||||||
|
q,
|
||||||
|
resolve: authenticated,
|
||||||
|
limit: SHORT_LIMIT,
|
||||||
|
};
|
||||||
|
if (type) {
|
||||||
|
params.limit = LIMIT;
|
||||||
|
params.type = type;
|
||||||
|
params.offset = offsetRef.current;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const results = await masto.v2.search(params);
|
||||||
|
console.log(results);
|
||||||
|
if (type && !firstLoad) {
|
||||||
|
if (type === 'statuses') {
|
||||||
|
setStatusResults((prev) => [...prev, ...results.statuses]);
|
||||||
|
} else if (type === 'accounts') {
|
||||||
|
setAccountResults((prev) => [...prev, ...results.accounts]);
|
||||||
|
} else if (type === 'hashtags') {
|
||||||
|
setHashtagResults((prev) => [...prev, ...results.hashtags]);
|
||||||
|
}
|
||||||
|
offsetRef.current = offsetRef.current + LIMIT;
|
||||||
|
setShowMore(!!results[type]?.length);
|
||||||
|
} else {
|
||||||
|
setStatusResults(results.statuses);
|
||||||
|
setAccountResults(results.accounts);
|
||||||
|
setHashtagResults(results.hashtags);
|
||||||
|
}
|
||||||
|
setUiState('default');
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
setUiState('error');
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// searchFieldRef.current?.focus?.();
|
// searchFieldRef.current?.focus?.();
|
||||||
// searchFormRef.current?.focus?.();
|
// searchFormRef.current?.focus?.();
|
||||||
if (q) {
|
if (q) {
|
||||||
// searchFieldRef.current.value = q;
|
// searchFieldRef.current.value = q;
|
||||||
searchFormRef.current?.setValue?.(q);
|
searchFormRef.current?.setValue?.(q);
|
||||||
|
loadResults(true);
|
||||||
setUiState('loading');
|
|
||||||
(async () => {
|
|
||||||
const results = await masto.v2.search({
|
|
||||||
q,
|
|
||||||
limit: type ? 40 : 5,
|
|
||||||
resolve: authenticated,
|
|
||||||
type,
|
|
||||||
});
|
|
||||||
console.log(results);
|
|
||||||
setStatusResults(results.statuses);
|
|
||||||
setAccountResults(results.accounts);
|
|
||||||
setHashtagResults(results.hashtags);
|
|
||||||
setUiState('default');
|
|
||||||
})();
|
|
||||||
}
|
}
|
||||||
}, [q, type, instance]);
|
}, [q, type, instance]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="search-page" class="deck-container">
|
<div id="search-page" class="deck-container" ref={scrollableRef}>
|
||||||
<div class="timeline-deck deck">
|
<div class="timeline-deck deck">
|
||||||
<header>
|
<header>
|
||||||
<div class="header-grid">
|
<div class="header-grid">
|
||||||
|
@ -110,7 +163,7 @@ function Search(props) {
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!!q && uiState !== 'loading' ? (
|
{!!q ? (
|
||||||
<>
|
<>
|
||||||
{(!type || type === 'accounts') && (
|
{(!type || type === 'accounts') && (
|
||||||
<>
|
<>
|
||||||
|
@ -121,7 +174,7 @@ function Search(props) {
|
||||||
<>
|
<>
|
||||||
<ul class="timeline flat accounts-list">
|
<ul class="timeline flat accounts-list">
|
||||||
{accountResults.map((account) => (
|
{accountResults.map((account) => (
|
||||||
<li>
|
<li key={account.id}>
|
||||||
<AccountBlock
|
<AccountBlock
|
||||||
account={account}
|
account={account}
|
||||||
instance={instance}
|
instance={instance}
|
||||||
|
@ -140,8 +193,15 @@ function Search(props) {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
) : (
|
||||||
|
!type &&
|
||||||
|
(uiState === 'loading' ? (
|
||||||
|
<p class="ui-state">
|
||||||
|
<Loader abrupt />
|
||||||
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<p class="ui-state">No accounts found.</p>
|
<p class="ui-state">No accounts found.</p>
|
||||||
|
))
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
@ -154,7 +214,7 @@ function Search(props) {
|
||||||
<>
|
<>
|
||||||
<ul class="link-list hashtag-list">
|
<ul class="link-list hashtag-list">
|
||||||
{hashtagResults.map((hashtag) => (
|
{hashtagResults.map((hashtag) => (
|
||||||
<li>
|
<li key={hashtag.name}>
|
||||||
<Link
|
<Link
|
||||||
to={
|
to={
|
||||||
instance
|
instance
|
||||||
|
@ -179,8 +239,15 @@ function Search(props) {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
) : (
|
||||||
|
!type &&
|
||||||
|
(uiState === 'loading' ? (
|
||||||
|
<p class="ui-state">
|
||||||
|
<Loader abrupt />
|
||||||
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<p class="ui-state">No hashtags found.</p>
|
<p class="ui-state">No hashtags found.</p>
|
||||||
|
))
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
@ -193,7 +260,7 @@ function Search(props) {
|
||||||
<>
|
<>
|
||||||
<ul class="timeline">
|
<ul class="timeline">
|
||||||
{statusResults.map((status) => (
|
{statusResults.map((status) => (
|
||||||
<li>
|
<li key={status.id}>
|
||||||
<Link
|
<Link
|
||||||
class="status-link"
|
class="status-link"
|
||||||
to={
|
to={
|
||||||
|
@ -218,11 +285,51 @@ function Search(props) {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
) : (
|
||||||
|
!type &&
|
||||||
|
(uiState === 'loading' ? (
|
||||||
|
<p class="ui-state">
|
||||||
|
<Loader abrupt />
|
||||||
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<p class="ui-state">No posts found.</p>
|
<p class="ui-state">No posts found.</p>
|
||||||
|
))
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{!!type &&
|
||||||
|
(uiState === 'default' ? (
|
||||||
|
showMore ? (
|
||||||
|
<InView
|
||||||
|
onChange={(inView) => {
|
||||||
|
if (inView) {
|
||||||
|
loadResults();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="plain block"
|
||||||
|
onClick={() => loadResults()}
|
||||||
|
style={{ marginBlockEnd: '6em' }}
|
||||||
|
>
|
||||||
|
Show more…
|
||||||
|
</button>
|
||||||
|
</InView>
|
||||||
|
) : (
|
||||||
|
<p class="ui-state insignificant">The end.</p>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
!!(
|
||||||
|
hashtagResults.length ||
|
||||||
|
accountResults.length ||
|
||||||
|
statusResults.length
|
||||||
|
) && (
|
||||||
|
<p class="ui-state">
|
||||||
|
<Loader abrupt />
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
))}
|
||||||
</>
|
</>
|
||||||
) : uiState === 'loading' ? (
|
) : uiState === 'loading' ? (
|
||||||
<p class="ui-state">
|
<p class="ui-state">
|
||||||
|
|
|
@ -119,7 +119,10 @@ function StatusPage(params) {
|
||||||
instance={instance}
|
instance={instance}
|
||||||
index={mediaIndex - 1}
|
index={mediaIndex - 1}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
if (snapStates.prevLocation) {
|
if (
|
||||||
|
!window.matchMedia('(min-width: calc(40em + 350px))').matches &&
|
||||||
|
snapStates.prevLocation
|
||||||
|
) {
|
||||||
history.back();
|
history.back();
|
||||||
} else {
|
} else {
|
||||||
if (showMediaOnly) {
|
if (showMediaOnly) {
|
||||||
|
@ -638,6 +641,14 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
|
||||||
} ${initialPageState.current === 'status' ? 'slide-in' : ''} ${
|
} ${initialPageState.current === 'status' ? 'slide-in' : ''} ${
|
||||||
viewMode ? `deck-view-${viewMode}` : ''
|
viewMode ? `deck-view-${viewMode}` : ''
|
||||||
}`}
|
}`}
|
||||||
|
onAnimationEnd={(e) => {
|
||||||
|
// Fix the bounce effect when switching viewMode
|
||||||
|
// `slide-in` animation kicks in when switching viewMode
|
||||||
|
if (initialPageState.current === 'status') {
|
||||||
|
// e.target.classList.remove('slide-in');
|
||||||
|
initialPageState.current = null;
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<header
|
<header
|
||||||
class={`${heroInView ? 'inview' : ''} ${
|
class={`${heroInView ? 'inview' : ''} ${
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { Menu, MenuItem } from '@szhsin/react-menu';
|
import { Menu, MenuItem } from '@szhsin/react-menu';
|
||||||
import { useRef } from 'preact/hooks';
|
import { useMemo, useRef, useState } from 'preact/hooks';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { useSnapshot } from 'valtio';
|
import { useSnapshot } from 'valtio';
|
||||||
|
|
||||||
import Icon from '../components/icon';
|
import Icon from '../components/icon';
|
||||||
|
import Link from '../components/link';
|
||||||
import Menu2 from '../components/menu2';
|
import Menu2 from '../components/menu2';
|
||||||
import Timeline from '../components/timeline';
|
import Timeline from '../components/timeline';
|
||||||
import { api } from '../utils/api';
|
import { api } from '../utils/api';
|
||||||
|
@ -25,12 +26,23 @@ function Trending(props) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const latestItem = useRef();
|
const latestItem = useRef();
|
||||||
|
|
||||||
|
const [hashtags, setHashtags] = useState([]);
|
||||||
const trendIterator = useRef();
|
const trendIterator = useRef();
|
||||||
async function fetchTrend(firstLoad) {
|
async function fetchTrend(firstLoad) {
|
||||||
if (firstLoad || !trendIterator.current) {
|
if (firstLoad || !trendIterator.current) {
|
||||||
trendIterator.current = masto.v1.trends.listStatuses({
|
trendIterator.current = masto.v1.trends.listStatuses({
|
||||||
limit: LIMIT,
|
limit: LIMIT,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Get hashtags
|
||||||
|
try {
|
||||||
|
const iterator = masto.v1.trends.listTags();
|
||||||
|
const { value: tags } = await iterator.next();
|
||||||
|
console.log(tags);
|
||||||
|
setHashtags(tags);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const results = await trendIterator.current.next();
|
const results = await trendIterator.current.next();
|
||||||
let { value } = results;
|
let { value } = results;
|
||||||
|
@ -71,6 +83,28 @@ function Trending(props) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TimelineStart = useMemo(() => {
|
||||||
|
if (!hashtags.length) return null;
|
||||||
|
return (
|
||||||
|
<div class="filter-bar">
|
||||||
|
<Icon icon="chart" class="insignificant" size="l" />
|
||||||
|
{hashtags.map((tag, i) => {
|
||||||
|
const { name, history } = tag;
|
||||||
|
const total = history.reduce((acc, cur) => acc + +cur.uses, 0);
|
||||||
|
return (
|
||||||
|
<Link to={`/${instance}/t/${name}`}>
|
||||||
|
<span>
|
||||||
|
<span class="more-insignificant">#</span>
|
||||||
|
{name}
|
||||||
|
</span>
|
||||||
|
<span class="filter-count">{total.toLocaleString()}</span>
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}, [hashtags]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Timeline
|
<Timeline
|
||||||
key={instance}
|
key={instance}
|
||||||
|
@ -92,6 +126,7 @@ function Trending(props) {
|
||||||
headerStart={<></>}
|
headerStart={<></>}
|
||||||
boostsCarousel={snapStates.settings.boostsCarousel}
|
boostsCarousel={snapStates.settings.boostsCarousel}
|
||||||
allowFilters
|
allowFilters
|
||||||
|
timelineStart={TimelineStart}
|
||||||
headerEnd={
|
headerEnd={
|
||||||
<Menu2
|
<Menu2
|
||||||
portal
|
portal
|
||||||
|
|
|
@ -3,6 +3,7 @@ export default function isMastodonLinkMaybe(url) {
|
||||||
return (
|
return (
|
||||||
/^\/.*\/\d+$/i.test(pathname) ||
|
/^\/.*\/\d+$/i.test(pathname) ||
|
||||||
/^\/@[^/]+\/statuses\/\w+$/i.test(pathname) || // GoToSocial
|
/^\/@[^/]+\/statuses\/\w+$/i.test(pathname) || // GoToSocial
|
||||||
/^\/notes\/[a-z0-9]+$/i.test(pathname) // Misskey, Calckey
|
/^\/notes\/[a-z0-9]+$/i.test(pathname) || // Misskey, Calckey
|
||||||
|
/^\/(notice|objects)\/[a-z0-9-]+$/i.test(pathname) // Pleroma
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,25 @@ export function saveAccount(account) {
|
||||||
store.session.set('currentAccount', account.info.id);
|
store.session.set('currentAccount', account.info.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function updateAccount(accountInfo) {
|
||||||
|
// Only update if displayName or avatar or avatar_static is different
|
||||||
|
const accounts = store.local.getJSON('accounts') || [];
|
||||||
|
const acc = accounts.find((a) => a.info.id === accountInfo.id);
|
||||||
|
if (acc) {
|
||||||
|
if (
|
||||||
|
acc.info.displayName !== accountInfo.displayName ||
|
||||||
|
acc.info.avatar !== accountInfo.avatar ||
|
||||||
|
acc.info.avatar_static !== accountInfo.avatar_static
|
||||||
|
) {
|
||||||
|
acc.info = {
|
||||||
|
...acc.info,
|
||||||
|
...accountInfo,
|
||||||
|
};
|
||||||
|
store.local.setJSON('accounts', accounts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let currentInstance = null;
|
let currentInstance = null;
|
||||||
export function getCurrentInstance() {
|
export function getCurrentInstance() {
|
||||||
if (currentInstance) return currentInstance;
|
if (currentInstance) return currentInstance;
|
||||||
|
|
Loading…
Reference in a new issue