mirror of
https://github.com/cheeaun/phanpy.git
synced 2025-03-23 14:13:21 +01:00
Preliminary steps in adding filter bar
This commit is contained in:
parent
04b4101e55
commit
c7f4087ed2
4 changed files with 135 additions and 10 deletions
57
src/app.css
57
src/app.css
|
@ -1641,6 +1641,63 @@ ul.link-list li a .icon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FILTER BAR */
|
||||||
|
|
||||||
|
.filter-bar {
|
||||||
|
padding: 8px 16px;
|
||||||
|
background-color: var(--bg-faded-color);
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
overflow-x: auto;
|
||||||
|
mask-image: linear-gradient(
|
||||||
|
to right,
|
||||||
|
transparent,
|
||||||
|
black 16px,
|
||||||
|
black calc(100% - 16px),
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
@media (min-width: 40em) {
|
||||||
|
.filter-bar {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.filter-bar > a {
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
color: var(--link-color);
|
||||||
|
text-decoration: none;
|
||||||
|
white-space: nowrap;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
transition: all 0.3s ease-out;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.filter-bar > a:is(:hover, :focus) {
|
||||||
|
border-color: var(--link-light-color);
|
||||||
|
}
|
||||||
|
.filter-bar > a > * {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.filter-bar > a.is-active {
|
||||||
|
border-color: var(--link-color);
|
||||||
|
box-shadow: inset 0 0 8px var(--link-faded-color);
|
||||||
|
}
|
||||||
|
.filter-bar > a > .filter-count {
|
||||||
|
font-size: 80%;
|
||||||
|
display: inline-block;
|
||||||
|
color: var(--text-insignificant-color);
|
||||||
|
min-width: 16px;
|
||||||
|
min-height: 16px;
|
||||||
|
padding: 4px;
|
||||||
|
margin: -4px -8px -4px 0;
|
||||||
|
background-color: var(--bg-faded-color);
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
||||||
|
|
||||||
/* OTHERS */
|
/* OTHERS */
|
||||||
|
|
||||||
@media (min-width: 40em) {
|
@media (min-width: 40em) {
|
||||||
|
|
|
@ -74,6 +74,7 @@ const ICONS = {
|
||||||
time: 'mingcute:time-line',
|
time: 'mingcute:time-line',
|
||||||
refresh: 'mingcute:refresh-2-line',
|
refresh: 'mingcute:refresh-2-line',
|
||||||
emoji2: 'mingcute:emoji-2-line',
|
emoji2: 'mingcute:emoji-2-line',
|
||||||
|
filter: 'mingcute:filter-2-line',
|
||||||
};
|
};
|
||||||
|
|
||||||
const modules = import.meta.glob('/node_modules/@iconify-icons/mingcute/*.js');
|
const modules = import.meta.glob('/node_modules/@iconify-icons/mingcute/*.js');
|
||||||
|
|
|
@ -33,6 +33,7 @@ function Timeline({
|
||||||
headerEnd,
|
headerEnd,
|
||||||
timelineStart,
|
timelineStart,
|
||||||
allowFilters,
|
allowFilters,
|
||||||
|
refresh,
|
||||||
}) {
|
}) {
|
||||||
const [items, setItems] = useState([]);
|
const [items, setItems] = useState([]);
|
||||||
const [uiState, setUIState] = useState('default');
|
const [uiState, setUIState] = useState('default');
|
||||||
|
@ -184,6 +185,9 @@ function Timeline({
|
||||||
scrollableRef.current?.scrollTo({ top: 0 });
|
scrollableRef.current?.scrollTo({ top: 0 });
|
||||||
loadItems(true);
|
loadItems(true);
|
||||||
}, []);
|
}, []);
|
||||||
|
useEffect(() => {
|
||||||
|
loadItems(true);
|
||||||
|
}, [refresh]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (reachStart) {
|
if (reachStart) {
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import { useEffect, useMemo, useRef, useState } from 'preact/hooks';
|
import { useEffect, useMemo, useRef, useState } from 'preact/hooks';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams, useSearchParams } from 'react-router-dom';
|
||||||
import { useSnapshot } from 'valtio';
|
import { useSnapshot } from 'valtio';
|
||||||
|
|
||||||
import AccountInfo from '../components/account-info';
|
import AccountInfo from '../components/account-info';
|
||||||
|
import Icon from '../components/icon';
|
||||||
|
import Link from '../components/link';
|
||||||
import Timeline from '../components/timeline';
|
import Timeline from '../components/timeline';
|
||||||
import { api } from '../utils/api';
|
import { api } from '../utils/api';
|
||||||
import emojifyText from '../utils/emojify-text';
|
import emojifyText from '../utils/emojify-text';
|
||||||
|
@ -15,6 +17,11 @@ const LIMIT = 20;
|
||||||
function AccountStatuses() {
|
function AccountStatuses() {
|
||||||
const snapStates = useSnapshot(states);
|
const snapStates = useSnapshot(states);
|
||||||
const { id, ...params } = useParams();
|
const { id, ...params } = useParams();
|
||||||
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
|
const excludeReplies = !searchParams.get('replies');
|
||||||
|
const tagged = searchParams.get('tagged');
|
||||||
|
const media = !!searchParams.get('media');
|
||||||
|
console.log({ excludeReplies });
|
||||||
const { masto, instance, authenticated } = api({ instance: params.instance });
|
const { masto, instance, authenticated } = api({ instance: params.instance });
|
||||||
const accountStatusesIterator = useRef();
|
const accountStatusesIterator = useRef();
|
||||||
async function fetchAccountStatuses(firstLoad) {
|
async function fetchAccountStatuses(firstLoad) {
|
||||||
|
@ -25,7 +32,7 @@ function AccountStatuses() {
|
||||||
pinned: true,
|
pinned: true,
|
||||||
})
|
})
|
||||||
.next();
|
.next();
|
||||||
if (pinnedStatuses?.length) {
|
if (pinnedStatuses?.length && !tagged && !media) {
|
||||||
pinnedStatuses.forEach((status) => {
|
pinnedStatuses.forEach((status) => {
|
||||||
status._pinned = true;
|
status._pinned = true;
|
||||||
saveStatus(status, instance);
|
saveStatus(status, instance);
|
||||||
|
@ -45,6 +52,9 @@ function AccountStatuses() {
|
||||||
if (firstLoad || !accountStatusesIterator.current) {
|
if (firstLoad || !accountStatusesIterator.current) {
|
||||||
accountStatusesIterator.current = masto.v1.accounts.listStatuses(id, {
|
accountStatusesIterator.current = masto.v1.accounts.listStatuses(id, {
|
||||||
limit: LIMIT,
|
limit: LIMIT,
|
||||||
|
exclude_replies: excludeReplies,
|
||||||
|
only_media: media,
|
||||||
|
tagged,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const { value, done } = await accountStatusesIterator.current.next();
|
const { value, done } = await accountStatusesIterator.current.next();
|
||||||
|
@ -62,6 +72,7 @@ function AccountStatuses() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const [account, setAccount] = useState();
|
const [account, setAccount] = useState();
|
||||||
|
const [featuredTags, setFeaturedTags] = useState([]);
|
||||||
useTitle(
|
useTitle(
|
||||||
`${account?.displayName ? account.displayName + ' ' : ''}@${
|
`${account?.displayName ? account.displayName + ' ' : ''}@${
|
||||||
account?.acct ? account.acct : 'Account posts'
|
account?.acct ? account.acct : 'Account posts'
|
||||||
|
@ -77,6 +88,13 @@ function AccountStatuses() {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
const featuredTags = await masto.v1.accounts.listFeaturedTags(id);
|
||||||
|
console.log({ featuredTags });
|
||||||
|
setFeaturedTags(featuredTags);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
}, [id]);
|
}, [id]);
|
||||||
|
|
||||||
|
@ -85,15 +103,59 @@ function AccountStatuses() {
|
||||||
const TimelineStart = useMemo(() => {
|
const TimelineStart = useMemo(() => {
|
||||||
const cachedAccount = snapStates.accounts[`${id}@${instance}`];
|
const cachedAccount = snapStates.accounts[`${id}@${instance}`];
|
||||||
return (
|
return (
|
||||||
<AccountInfo
|
<>
|
||||||
instance={instance}
|
<AccountInfo
|
||||||
account={cachedAccount || id}
|
instance={instance}
|
||||||
fetchAccount={() => masto.v1.accounts.fetch(id)}
|
account={cachedAccount || id}
|
||||||
authenticated={authenticated}
|
fetchAccount={() => masto.v1.accounts.fetch(id)}
|
||||||
standalone
|
authenticated={authenticated}
|
||||||
/>
|
standalone
|
||||||
|
/>
|
||||||
|
<div class="filter-bar">
|
||||||
|
<Icon icon="filter" class="insignificant" size="l" />
|
||||||
|
<Link
|
||||||
|
to={`/${instance}/a/${id}${excludeReplies ? '?replies=1' : ''}`}
|
||||||
|
class={excludeReplies ? '' : 'is-active'}
|
||||||
|
>
|
||||||
|
+ Replies
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
to={`/${instance}/a/${id}${media ? '' : '?media=1'}`}
|
||||||
|
class={media ? 'is-active' : ''}
|
||||||
|
>
|
||||||
|
Media
|
||||||
|
</Link>
|
||||||
|
{featuredTags.map((tag) => (
|
||||||
|
<Link
|
||||||
|
to={`/${instance}/a/${id}${
|
||||||
|
tagged === tag.name
|
||||||
|
? ''
|
||||||
|
: `?tagged=${encodeURIComponent(tag.name)}`
|
||||||
|
}`}
|
||||||
|
class={tagged === tag.name ? 'is-active' : ''}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
<span class="more-insignificant">#</span>
|
||||||
|
{tag.name}
|
||||||
|
</span>
|
||||||
|
{
|
||||||
|
// The count differs based on instance 😅
|
||||||
|
}
|
||||||
|
{/* <span class="filter-count">{tag.statusesCount}</span> */}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}, [id, instance, authenticated]);
|
}, [
|
||||||
|
id,
|
||||||
|
instance,
|
||||||
|
authenticated,
|
||||||
|
excludeReplies,
|
||||||
|
featuredTags,
|
||||||
|
tagged,
|
||||||
|
media,
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Timeline
|
<Timeline
|
||||||
|
@ -127,6 +189,7 @@ function AccountStatuses() {
|
||||||
useItemID
|
useItemID
|
||||||
boostsCarousel={snapStates.settings.boostsCarousel}
|
boostsCarousel={snapStates.settings.boostsCarousel}
|
||||||
timelineStart={TimelineStart}
|
timelineStart={TimelineStart}
|
||||||
|
refresh={excludeReplies + tagged + media}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue