Compare commits

..

No commits in common. "ad0076156b14913e2665b0ea41feeae26b2342ac" and "88ff705d685c8f5ebcbe9482d4d0cdd4296dbc7b" have entirely different histories.

7 changed files with 81 additions and 131 deletions

View file

@ -33,7 +33,7 @@ Don't choose algorithm solely on the time complexity. GUI app needs smooth, not
But it comes with cost. Modern browsers are already very smart on rendering. Using `contain`, you are trading onething off for another:
- `layout` affects the reflow. This property usually won't make large change: mainline browsers already can incrementally reflow.
- `style` affects the style computation, is automatically enabled when using `container` property. Usually won't make large change too, unless you frequently change the styles (and/or your stylesheet is large and/or with complex selectors), containing the computation may help performance.
- `style` affacts the style computation, is automatically enabled when using `container` property. Usually won't make large change too, unless you frequently change the styles (and/or your stylesheet is large and/or with complex selectors).
- `paint` affects the shading, the pixel-filling process. This is useful - the shading is resource-heavy - but the browser may need more buffers and more time to compose the final frame.
- This containment may increase memory usage.
- `size` says the size is not affected by outside elements and is defined. It hints the user agent can use the pre-defined size and/or cache the computed size (with `auto` keyword).

View file

@ -58,10 +58,6 @@ import Menu, { createManagedMenuState } from "~material/Menu";
import { share } from "~platform/share";
import "./Profile.css";
import { useNavigator } from "~platform/StackedRouter";
import {
createSingluarItemSelection,
default as ItemSelectionProvider,
} from "../timelines/toots/ItemSelectionProvider";
const Profile: Component = () => {
const { pop } = useNavigator();
@ -74,7 +70,6 @@ const Profile: Component = () => {
}>();
const windowSize = useWindowSize();
const time = createTimeSource();
const [, selectionState] = createSingluarItemSelection();
const menuButId = createUniqueId();
const recentTootListId = createUniqueId();
@ -504,26 +499,22 @@ const Profile: Component = () => {
></TootFilterButton>
</div>
<ItemSelectionProvider value={selectionState}>
<TimeSourceProvider value={time}>
<Show
when={recentTootFilter().pinned && pinnedToots.list.length > 0}
>
<TootList
threads={pinnedToots.list}
onUnknownThread={pinnedToots.getPath}
onChangeToot={pinnedToots.set}
/>
<Divider />
</Show>
<TimeSourceProvider value={time}>
<Show when={recentTootFilter().pinned && pinnedToots.list.length > 0}>
<TootList
id={recentTootListId}
threads={recentToots.list}
onUnknownThread={recentToots.getPath}
onChangeToot={recentToots.set}
threads={pinnedToots.list}
onUnknownThread={pinnedToots.getPath}
onChangeToot={pinnedToots.set}
/>
</TimeSourceProvider>
</ItemSelectionProvider>
<Divider />
</Show>
<TootList
id={recentTootListId}
threads={recentToots.list}
onUnknownThread={recentToots.getPath}
onChangeToot={recentToots.set}
/>
</TimeSourceProvider>
<Show when={!recentTootChunk()?.done}>
<div

View file

@ -26,18 +26,11 @@ import { useStore } from "@nanostores/solid";
import TrendTimelinePanel from "./TrendTimelinePanel";
import TimelinePanel from "./TimelinePanel";
import { useSessions } from "../masto/clients";
import {
createSingluarItemSelection,
default as ItemSelectionProvider,
} from "./toots/ItemSelectionProvider";
const Home: ParentComponent = (props) => {
let panelList: HTMLDivElement;
useDocumentTitle("Timelines");
const now = createTimeSource();
const [, selectionState] = createSingluarItemSelection(
undefined as string | undefined,
);
const settings$ = useStore($settings);
@ -122,6 +115,7 @@ const Home: ParentComponent = (props) => {
}
};
css`
.tab-panel {
overflow: visible auto;
@ -201,42 +195,40 @@ const Home: ParentComponent = (props) => {
</AppBar>
}
>
<ItemSelectionProvider value={selectionState}>
<TimeSourceProvider value={now}>
<Show when={!!client()}>
<div
class="panel-list"
ref={panelList!}
onScroll={requestRecalculateTabIndicator}
>
<div class="tab-panel">
<div>
<TimelinePanel
client={client()}
name="home"
prefetch={prefetching()}
/>
</div>
<TimeSourceProvider value={now}>
<Show when={!!client()}>
<div
class="panel-list"
ref={panelList!}
onScroll={requestRecalculateTabIndicator}
>
<div class="tab-panel">
<div>
<TimelinePanel
client={client()}
name="home"
prefetch={prefetching()}
/>
</div>
<div class="tab-panel">
<div>
<TrendTimelinePanel client={client()} />
</div>
</div>
<div class="tab-panel">
<div>
<TimelinePanel
client={client()}
name="public"
prefetch={prefetching()}
/>
</div>
</div>
<div></div>
</div>
</Show>
</TimeSourceProvider>
</ItemSelectionProvider>
<div class="tab-panel">
<div>
<TrendTimelinePanel client={client()} />
</div>
</div>
<div class="tab-panel">
<div>
<TimelinePanel
client={client()}
name="public"
prefetch={prefetching()}
/>
</div>
</div>
<div></div>
</div>
</Show>
</TimeSourceProvider>
</Scaffold>
</>
);

View file

@ -4,6 +4,7 @@ import {
type Component,
type JSX,
Show,
createRenderEffect,
createSignal,
type Setter,
createContext,

View file

@ -7,7 +7,6 @@ import {
Index,
createMemo,
For,
createUniqueId,
} from "solid-js";
import { type mastodon } from "masto";
import { vibrate } from "~platform/hardware";
@ -22,7 +21,6 @@ import cardStyle from "~material/cards.module.css";
import type { ThreadNode } from "../masto/timelines";
import { useNavigator } from "~platform/StackedRouter";
import { ANIM_CURVE_STD } from "~material/theme";
import { useItemSelection } from "./toots/ItemSelectionProvider";
function durationOf(rect0: DOMRect, rect1: DOMRect) {
const distancelt = Math.sqrt(
@ -47,9 +45,6 @@ function positionTootInThread(index: number, threadLength: number) {
return "middle";
}
/**
* Full-feature toot list.
*/
const TootList: Component<{
ref?: Ref<HTMLDivElement>;
id?: string;
@ -58,7 +53,7 @@ const TootList: Component<{
onChangeToot: (id: string, value: mastodon.v1.Status) => void;
}> = (props) => {
const session = useDefaultSession();
const [isExpanded, setExpanded] = useItemSelection();
const [expandedThreadId, setExpandedThreadId] = createSignal<string>();
const { push } = useNavigator();
const onBookmark = async (status: mastodon.v1.Status) => {
@ -195,7 +190,7 @@ const TootList: Component<{
event.currentTarget,
);
if (actionableElement && isExpanded(event.currentTarget.id)) {
if (actionableElement && checkIsExpended(status)) {
if (actionableElement.dataset.action === "acct") {
event.stopPropagation();
@ -219,13 +214,18 @@ const TootList: Component<{
}
// else if (!actionableElement || !checkIsExpended(status) || <rel is not one of known action>)
if (!isExpanded(event.currentTarget.id)) {
setExpanded(event.currentTarget.id);
if (status.id !== expandedThreadId()) {
setExpandedThreadId((x) => (x ? undefined : status.id));
} else {
openFullScreenToot(status, event.currentTarget as HTMLElement);
}
};
const checkIsExpendedId = createSelector(expandedThreadId);
const checkIsExpended = (status: mastodon.v1.Status) =>
checkIsExpendedId(status.id);
const reply = (
status: mastodon.v1.Status,
event: { currentTarget: HTMLElement },
@ -234,7 +234,10 @@ const TootList: Component<{
openFullScreenToot(status, element, true);
};
const vote = async (status: mastodon.v1.Status, votes: readonly number[]) => {
const vote = async (
status: mastodon.v1.Status,
votes: readonly number[]
) => {
const client = session()?.client;
if (!client) return;
@ -268,15 +271,13 @@ const TootList: Component<{
return <p>Oops: {String(err)}</p>;
}}
>
<TootEnvProvider
value={{
boost: toggleBoost,
bookmark: onBookmark,
favourite: toggleFavourite,
reply: reply,
vote: vote,
}}
>
<TootEnvProvider value={{
boost: toggleBoost,
bookmark: onBookmark,
favourite: toggleFavourite,
reply: reply,
vote: vote
}}>
<div ref={props.ref} id={props.id} class="toot-list">
<For each={props.threads}>
{(threadId, threadIdx) => {
@ -290,13 +291,11 @@ const TootList: Component<{
<Index each={thread()}>
{(threadNode, index) => {
const status = () => threadNode().value;
const id = createUniqueId();
return (
<RegularToot
data-status-id={status().id}
data-thread-sort={index}
id={id}
status={status()}
thread={
threadLength() > 1
@ -304,8 +303,8 @@ const TootList: Component<{
: undefined
}
class={cardStyle.card}
evaluated={isExpanded(id)}
actionable={isExpanded(id)}
evaluated={checkIsExpended(status())}
actionable={checkIsExpended(status())}
onClick={[onItemClick, status()]}
/>
);

View file

@ -1,35 +0,0 @@
import {
createContext,
createSelector,
createSignal,
useContext,
type Accessor,
} from "solid-js";
export type ItemSelectionState<T> = [(value: T) => boolean, (value: T) => void];
const ItemSelectionContext = /* @__PURE__ */ createContext<
ItemSelectionState<any>
>([() => false, () => undefined]);
export function createSingluarItemSelection<T extends {}>(
intial?: T,
): readonly [Accessor<T | undefined>, ItemSelectionState<T | undefined>] {
const [value, setValue] = createSignal<T | undefined>(intial);
const select = createSelector(value, (a, b) =>
typeof b !== "undefined" ? a === b : false,
);
const toggle = (v: T | undefined) => {
setValue((o) => (o ? undefined : v));
};
return [value, [select, toggle]];
}
export function useItemSelection() {
return useContext(ItemSelectionContext);
}
export default ItemSelectionContext.Provider;

View file

@ -10,7 +10,7 @@
}
}
.TootAuthorGroup>.name-grp {
.TootAuthorGroup > .name-grp {
display: grid;
grid-template-columns: 1fr auto;
color: var(--tutu-color-secondary-text-on-surface);
@ -22,16 +22,18 @@
>time {
text-align: end;
}
&:hover {
> .name-primary {
text-decoration: underline;
}
}
}
.RegularToot.expanded .TootAuthorGroup>.name-grp>.name-primary {
text-decoration: underline;
}
.TootAuthorGroup>.name-grp>.name-primary {
.TootAuthorGroup > .name-grp > .name-primary {
color: var(--tutu-color-on-surface);
>.acct-mark {
> .acct-mark {
font-size: 1.2em;
color: var(--tutu-color-secondary-text-on-surface);
vertical-align: sub;
@ -39,7 +41,7 @@
}
}
.TootAuthorGroup>.avatar {
.TootAuthorGroup > .avatar {
width: calc(var(--toot-avatar-size, 40px) - 1px);
aspect-ratio: 1/1;
object-fit: contain;