diff --git a/.env b/.env index b5ff8ea..e36e49c 100644 --- a/.env +++ b/.env @@ -2,4 +2,4 @@ DEV_SERVER_HTTPS_CERT_BASE= DEV_SERVER_HTTPS_CERT_PASS= DEV_LOCATOR_EDITOR=vscode VITE_DEVTOOLS_OVERLAY=true -VITE_PLATFROM_MASONRY_ALWAYS_COMPAT= \ No newline at end of file +VITE_PLATFORM_MASONRY_ALWAYS_COMPAT= \ No newline at end of file diff --git a/src/masto/toot.ts b/src/masto/toot.ts index 2651577..f3ea94d 100644 --- a/src/masto/toot.ts +++ b/src/masto/toot.ts @@ -20,17 +20,6 @@ export function resolveCustomEmoji( }); } -export function appliedCustomEmoji( - target: { innerHTML: string }, - content: string, - emojis?: mastodon.v1.CustomEmoji[], -) { - createRenderEffect(() => { - const result = emojis ? resolveCustomEmoji(content, emojis) : content; - target.innerHTML = result; - }); -} - export function hasCustomEmoji(s: string) { return CUSTOM_EMOJI_REGEX.test(s); } diff --git a/src/overrides.d.ts b/src/overrides.d.ts index e8db98c..46a3af6 100644 --- a/src/overrides.d.ts +++ b/src/overrides.d.ts @@ -14,7 +14,7 @@ interface ImportMetaEnv { /** * Always use compatible version of Masonry. */ - readonly VITE_PLATFROM_MASONRY_ALWAYS_COMPAT?: string + readonly VITE_PLATFORM_MASONRY_ALWAYS_COMPAT?: string } interface ImportMeta { diff --git a/src/platform/Masonry.tsx b/src/platform/Masonry.tsx index bd461b9..ab9f002 100644 --- a/src/platform/Masonry.tsx +++ b/src/platform/Masonry.tsx @@ -46,30 +46,49 @@ function createCompatMasonry( const size = createElementSize(element); - const treeMutObx = new MutationObserver(() => { - layout.reloadItems?.(); - }); + let layoutNotRequested = true; - onCleanup(() => treeMutObx.disconnect()); + const reflow = () => { + layout.layout?.(); + layoutNotRequested = true; + }; createRenderEffect(() => { const opts = options(); layout.option?.(opts); }); + const treeMutObx = new MutationObserver(() => { + layout.reloadItems?.(); + if (layoutNotRequested) { + layoutNotRequested = false; + requestAnimationFrame(reflow); + } + }); + + onCleanup(() => treeMutObx.disconnect()); + createRenderEffect(() => { treeMutObx.observe(element, { childList: true }); }); createRenderEffect(() => { const width = size.width; // only tracking width - layout.layout?.(); + if (layoutNotRequested) { + layoutNotRequested = false; + requestAnimationFrame(reflow); + } }); if (import.meta.hot) { - import.meta.hot.on("vite:afterUpdate", () => { - layout.layout?.(); - }); + const onHotReloadUpdate = () => { + if (layoutNotRequested) { + layoutNotRequested = false; + requestAnimationFrame(reflow); + } + }; + import.meta.hot.on("vite:afterUpdate", onHotReloadUpdate); + import.meta.hot.off("vite:afterUpdate", onHotReloadUpdate); } } @@ -80,11 +99,11 @@ const supportsCSSMasonryLayout = /* @__PURE__ */ CSS.supports( console.debug("supports css masonry layout", supportsCSSMasonryLayout); -const useNativeImpl = import.meta.env.VITE_PLATFROM_MASONRY_ALWAYS_COMPAT +const useNativeImpl = import.meta.env.VITE_PLATFORM_MASONRY_ALWAYS_COMPAT ? false : supportsCSSMasonryLayout; -if (import.meta.env.VITE_PLATFROM_MASONRY_ALWAYS_COMPAT) { +if (import.meta.env.VITE_PLATFORM_MASONRY_ALWAYS_COMPAT) { console.warn( "Masonry is in compat mode because VITE_PLATFORM_MASONRY_ALWAYS_COMPAT is enabled", ); diff --git a/src/profiles/Profile.tsx b/src/profiles/Profile.tsx index 56f6c8e..cc29999 100644 --- a/src/profiles/Profile.tsx +++ b/src/profiles/Profile.tsx @@ -171,10 +171,6 @@ const Profile: Component = () => { ), ); - const useSessionDisplayName = (e: HTMLElement) => { - createRenderEffect(() => (e.innerHTML = sessionDisplayName())); - }; - const toggleSubscribeHome = async (event: Event) => { const client = session().client; if (!session().account) return; @@ -218,9 +214,7 @@ const Profile: Component = () => { style={{ visibility: scrolledPastBanner() ? undefined : "hidden", }} - ref={(e: HTMLElement) => - createRenderEffect(() => (e.innerHTML = displayName())) - } + innerHTML={displayName()} > { - + {/* // for future */} @@ -384,7 +378,7 @@ const Profile: Component = () => { : undefined } > - + 's Home @@ -419,9 +413,7 @@ const Profile: Component = () => { - createRenderEffect(() => (e.innerHTML = displayName())) - } + innerHTML={displayName()} aria-label="Display name" > @@ -464,9 +456,7 @@ const Profile: Component = () => {
- createRenderEffect(() => (e.innerHTML = description() || "")) - } + innerHTML={description() || ""} >
{ - + ); }} diff --git a/src/timelines/RegularToot.tsx b/src/timelines/RegularToot.tsx index fd5c80d..63ef7c1 100644 --- a/src/timelines/RegularToot.tsx +++ b/src/timelines/RegularToot.tsx @@ -10,23 +10,19 @@ import { createContext, useContext, } from "solid-js"; -import tootStyle from "./toot.module.css"; -import { formatRelative } from "date-fns"; -import Img from "~material/Img.js"; import { Body2 } from "~material/typography.js"; -import { SmartToySharp, Lock } from "@suid/icons-material"; import { useTimeSource } from "~platform/timesrc.js"; import { resolveCustomEmoji } from "../masto/toot.js"; import { Divider } from "@suid/material"; import cardStyle from "~material/cards.module.css"; import MediaAttachmentGrid from "./toots/MediaAttachmentGrid.jsx"; -import { useDateFnLocale } from "~platform/i18n"; import { makeAcctText, useDefaultSession } from "../masto/clients"; import TootContent from "./toots/TootContent"; import BoostIcon from "./toots/BoostIcon"; import PreviewCard from "./toots/PreviewCard"; import TootPoll from "./toots/TootPoll"; import TootActionGroup from "./toots/TootActionGroup.js"; +import TootAuthorGroup from "./toots/TootAuthorGroup.js"; import "./RegularToot.css"; export type TootEnv = { @@ -66,63 +62,15 @@ type RegularTootProps = { export function findRootToot(element: HTMLElement) { let current: HTMLElement | null = element; - while (current && !current.classList.contains(tootStyle.toot)) { + while (current && !current.classList.contains("RegularToot")) { current = current.parentElement; } if (!current) { - throw Error( - `the element must be placed under a element with ${tootStyle.toot}`, - ); + throw Error(`the element must be placed under a element with .RegularToot`); } return current; } -function TootAuthorGroup( - props: { - status: mastodon.v1.Status; - now: Date; - } & JSX.HTMLElementTags["div"], -) { - const [managed, rest] = splitProps(props, ["status", "now"]); - const toot = () => managed.status; - const dateFnLocale = useDateFnLocale(); - - return ( -
- -
-
- - - - - - - { - createRenderEffect(() => { - e.innerHTML = resolveCustomEmoji( - toot().account.displayName, - toot().account.emojis, - ); - }); - }} - /> -
- - - @{toot().account.username}@{new URL(toot().account.url).hostname} - -
-
- ); -} - /** * find bottom-to-top the element with `data-action`. */ @@ -195,8 +143,8 @@ const RegularToot: Component = (oprops) => { <>
= (oprops) => {
{ - createRenderEffect(() => { - e.innerHTML = resolveCustomEmoji( - status().account.displayName, - toot().emojis, - ); - }); - }} + innerHTML={resolveCustomEmoji( + status().account.displayName, + toot().emojis, + )} > boosts
diff --git a/src/timelines/TootBottomSheet.tsx b/src/timelines/TootBottomSheet.tsx index 09465db..065a754 100644 --- a/src/timelines/TootBottomSheet.tsx +++ b/src/timelines/TootBottomSheet.tsx @@ -261,13 +261,7 @@ const TootBottomSheet: Component = (props) => { > - <span - ref={(e: HTMLElement) => - createRenderEffect( - () => (e.innerHTML = tootDisplayName() ?? "Someone"), - ) - } - ></span> + <span innerHTML={tootDisplayName() ?? "Someone"}></span> <span>'s toot</span> diff --git a/src/timelines/TootComposer.tsx b/src/timelines/TootComposer.tsx index 2895c67..450f9ad 100644 --- a/src/timelines/TootComposer.tsx +++ b/src/timelines/TootComposer.tsx @@ -44,7 +44,7 @@ import "./TootComposer.css"; import BottomSheet from "~material/BottomSheet"; import { useAppLocale } from "~platform/i18n"; import iso639_1 from "iso-639-1"; -import ChooseTootLang from "./ChooseTootLang"; +import ChooseTootLang from "./TootLangPicker"; import type { mastodon } from "masto"; import cardStyles from "~material/cards.module.css"; import Menu, { createManagedMenuState } from "~material/Menu"; @@ -349,15 +349,10 @@ const TootComposer: Component<{ { - createRenderEffect(() => { - const inf = session()?.account.inf; - return (e.innerHTML = resolveCustomEmoji( - inf?.displayName || "", - inf?.emojis ?? [], - )); - }); - }} + innerHTML={resolveCustomEmoji( + session()?.account.inf?.displayName || "", + session()?.account.inf?.emojis ?? [], + )} > diff --git a/src/timelines/TootLangPicker.css b/src/timelines/TootLangPicker.css new file mode 100644 index 0000000..f092267 --- /dev/null +++ b/src/timelines/TootLangPicker.css @@ -0,0 +1,4 @@ + +.TootLangPicker { + overflow: auto; +} diff --git a/src/timelines/ChooseTootLang.tsx b/src/timelines/TootLangPicker.tsx similarity index 94% rename from src/timelines/ChooseTootLang.tsx rename to src/timelines/TootLangPicker.tsx index 8177783..e86f69e 100644 --- a/src/timelines/ChooseTootLang.tsx +++ b/src/timelines/TootLangPicker.tsx @@ -1,9 +1,4 @@ -import { - For, - onMount, - type Component, - type JSX, -} from "solid-js"; +import { For, onMount, type Component, type JSX } from "solid-js"; import Scaffold from "~material/Scaffold"; import { AppBar, @@ -19,6 +14,7 @@ import { Close as CloseIcon } from "@suid/icons-material"; import iso639_1 from "iso-639-1"; import { createTranslator } from "~platform/i18n"; import { Title } from "~material/typography"; +import "./TootLangPicker.css"; type ChooseTootLangProps = { code: string; @@ -58,6 +54,7 @@ const ChooseTootLang: Component = (props) => { } + class="TootLangPicker" > .name-grp { display: grid; grid-template-columns: 1fr auto; color: var(--tutu-color-secondary-text-on-surface); @@ -30,10 +30,10 @@ } } -.tootAuthorNamePrimary { +.TootAuthorGroup > .name-grp > .name-primary { color: var(--tutu-color-on-surface); - > :global(.acct-mark) { + > .acct-mark { font-size: 1.2em; color: var(--tutu-color-secondary-text-on-surface); vertical-align: sub; @@ -41,7 +41,7 @@ } } -.tootAvatar { +.TootAuthorGroup > .avatar { width: calc(var(--toot-avatar-size, 40px) - 1px); aspect-ratio: 1/1; object-fit: contain; @@ -49,4 +49,4 @@ overflow: hidden; border: 1px solid var(--tutu-color-surface); background-color: var(--tutu-color-surface-d); -} +} \ No newline at end of file diff --git a/src/timelines/toots/TootAuthorGroup.tsx b/src/timelines/toots/TootAuthorGroup.tsx new file mode 100644 index 0000000..121b2c5 --- /dev/null +++ b/src/timelines/toots/TootAuthorGroup.tsx @@ -0,0 +1,53 @@ +import { SmartToySharp, Lock } from "@suid/icons-material"; +import { formatRelative } from "date-fns"; +import type { mastodon } from "masto"; +import { createRenderEffect, Show, splitProps, type JSX } from "solid-js"; +import Img from "~material/Img"; +import { Body2 } from "~material/typography"; +import { useAppLocale } from "~platform/i18n"; +import { resolveCustomEmoji } from "../../masto/toot"; +import "./TootAuthorGroup.css"; + +function TootAuthorGroup( + props: { + status: mastodon.v1.Status; + now: Date; + } & JSX.HTMLElementTags["div"], +) { + const [managed, rest] = splitProps(props, ["status", "now"]); + const toot = () => managed.status; + const { dateFn: dateFnLocale } = useAppLocale(); + + return ( +
+ +
+
+ + + + + + + +
+ + + @{toot().account.username}@{new URL(toot().account.url).hostname} + +
+
+ ); +} + +export default TootAuthorGroup; diff --git a/src/timelines/toots/TootContent.tsx b/src/timelines/toots/TootContent.tsx index a4643a2..2960794 100644 --- a/src/timelines/toots/TootContent.tsx +++ b/src/timelines/toots/TootContent.tsx @@ -81,15 +81,13 @@ const TootContent: Component = (oprops) => {
{ - createRenderEffect(() => { - ref.innerHTML = props.spoilerText - ? props.emojis - ? resolveCustomEmoji(props.spoilerText, props.emojis) - : props.spoilerText - : ""; - }); - }} + innerHTML={ + props.spoilerText + ? props.emojis + ? resolveCustomEmoji(props.spoilerText, props.emojis) + : props.spoilerText + : "" + } >
@@ -97,14 +95,12 @@ const TootContent: Component = (oprops) => {
- createRenderEffect(() => { - ref.innerHTML = props.source - ? props.emojis - ? resolveCustomEmoji(props.source, props.emojis) - : props.source - : ""; - }) + innerHTML={ + props.source + ? props.emojis + ? resolveCustomEmoji(props.source, props.emojis) + : props.source + : "" } >
diff --git a/src/timelines/toots/TootPoll.tsx b/src/timelines/toots/TootPoll.tsx index a148fcb..a2b9dc6 100644 --- a/src/timelines/toots/TootPoll.tsx +++ b/src/timelines/toots/TootPoll.tsx @@ -20,10 +20,7 @@ import { ListItemText, Radio, } from "@suid/material"; -import { - formatDistance, - isBefore, -} from "date-fns"; +import { formatDistance, isBefore } from "date-fns"; import { useTimeSource } from "~platform/timesrc"; import { useDateFnLocale } from "~platform/i18n"; import TootPollDialog from "./TootPollDialog"; @@ -31,13 +28,13 @@ import { ANIM_CURVE_STD } from "~material/theme"; import { useTootEnv } from "../RegularToot"; type TootPollProps = { - value: mastodon.v1.Poll - status: mastodon.v1.Status + value: mastodon.v1.Poll; + status: mastodon.v1.Status; }; const TootPoll: Component = (props) => { let list: HTMLUListElement; - const {vote}= useTootEnv() + const { vote } = useTootEnv(); const now = useTimeSource(); const dateFnLocale = useDateFnLocale(); @@ -46,7 +43,7 @@ const TootPoll: Component = (props) => { const [initialVote, setInitialVote] = createSignal(0); - const poll = () => props.value + const poll = () => props.value; const isShowResult = () => { const n = mustShowResult(); @@ -118,14 +115,10 @@ const TootPoll: Component = (props) => { > - createRenderEffect(() => { - e.innerHTML = resolveCustomEmoji( - option().title, - option().emojis, - ); - }) - } + innerHTML={resolveCustomEmoji( + option().title, + option().emojis, + )} > diff --git a/src/timelines/toots/TootPollDialog.tsx b/src/timelines/toots/TootPollDialog.tsx index 7374b0c..f63d204 100644 --- a/src/timelines/toots/TootPollDialog.tsx +++ b/src/timelines/toots/TootPollDialog.tsx @@ -96,15 +96,10 @@ const TootPollDialog: Component = (props) => { > - createRenderEffect( - () => - (e.innerHTML = resolveCustomEmoji( - option().title, - option().emojis, - )), - ) - } + innerHTML={resolveCustomEmoji( + option().title, + option().emojis, + )} >
{ - createRenderEffect(() => (e.innerHTML = item.value)); - }} - >