Compare commits
	
		
			No commits in common. "ad0076156b14913e2665b0ea41feeae26b2342ac" and "88ff705d685c8f5ebcbe9482d4d0cdd4296dbc7b" have entirely different histories.
		
	
	
		
			ad0076156b
			...
			88ff705d68
		
	
		
					 7 changed files with 81 additions and 131 deletions
				
			
		| 
						 | 
				
			
			@ -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).
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,11 +499,8 @@ const Profile: Component = () => {
 | 
			
		|||
          ></TootFilterButton>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <ItemSelectionProvider value={selectionState}>
 | 
			
		||||
        <TimeSourceProvider value={time}>
 | 
			
		||||
            <Show
 | 
			
		||||
              when={recentTootFilter().pinned && pinnedToots.list.length > 0}
 | 
			
		||||
            >
 | 
			
		||||
          <Show when={recentTootFilter().pinned && pinnedToots.list.length > 0}>
 | 
			
		||||
            <TootList
 | 
			
		||||
              threads={pinnedToots.list}
 | 
			
		||||
              onUnknownThread={pinnedToots.getPath}
 | 
			
		||||
| 
						 | 
				
			
			@ -523,7 +515,6 @@ const Profile: Component = () => {
 | 
			
		|||
            onChangeToot={recentToots.set}
 | 
			
		||||
          />
 | 
			
		||||
        </TimeSourceProvider>
 | 
			
		||||
        </ItemSelectionProvider>
 | 
			
		||||
 | 
			
		||||
        <Show when={!recentTootChunk()?.done}>
 | 
			
		||||
          <div
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,7 +195,6 @@ const Home: ParentComponent = (props) => {
 | 
			
		|||
          </AppBar>
 | 
			
		||||
        }
 | 
			
		||||
      >
 | 
			
		||||
        <ItemSelectionProvider value={selectionState}>
 | 
			
		||||
        <TimeSourceProvider value={now}>
 | 
			
		||||
          <Show when={!!client()}>
 | 
			
		||||
            <div
 | 
			
		||||
| 
						 | 
				
			
			@ -236,7 +229,6 @@ const Home: ParentComponent = (props) => {
 | 
			
		|||
            </div>
 | 
			
		||||
          </Show>
 | 
			
		||||
        </TimeSourceProvider>
 | 
			
		||||
        </ItemSelectionProvider>
 | 
			
		||||
      </Scaffold>
 | 
			
		||||
    </>
 | 
			
		||||
  );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,7 @@ import {
 | 
			
		|||
  type Component,
 | 
			
		||||
  type JSX,
 | 
			
		||||
  Show,
 | 
			
		||||
  createRenderEffect,
 | 
			
		||||
  createSignal,
 | 
			
		||||
  type Setter,
 | 
			
		||||
  createContext,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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={{
 | 
			
		||||
      <TootEnvProvider value={{
 | 
			
		||||
        boost: toggleBoost,
 | 
			
		||||
        bookmark: onBookmark,
 | 
			
		||||
        favourite: toggleFavourite,
 | 
			
		||||
        reply: reply,
 | 
			
		||||
          vote: vote,
 | 
			
		||||
        }}
 | 
			
		||||
      >
 | 
			
		||||
        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()]}
 | 
			
		||||
                      />
 | 
			
		||||
                    );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.RegularToot.expanded .TootAuthorGroup>.name-grp>.name-primary {
 | 
			
		||||
  &:hover {
 | 
			
		||||
    > .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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue