diff --git a/.env b/.env index e36e49c..b5ff8ea 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_PLATFORM_MASONRY_ALWAYS_COMPAT= \ No newline at end of file +VITE_PLATFROM_MASONRY_ALWAYS_COMPAT= \ No newline at end of file diff --git a/src/masto/toot.ts b/src/masto/toot.ts index f3ea94d..2651577 100644 --- a/src/masto/toot.ts +++ b/src/masto/toot.ts @@ -20,6 +20,17 @@ 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 46a3af6..e8db98c 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_PLATFORM_MASONRY_ALWAYS_COMPAT?: string + readonly VITE_PLATFROM_MASONRY_ALWAYS_COMPAT?: string } interface ImportMeta { diff --git a/src/platform/Masonry.tsx b/src/platform/Masonry.tsx index ab9f002..bd461b9 100644 --- a/src/platform/Masonry.tsx +++ b/src/platform/Masonry.tsx @@ -46,49 +46,30 @@ function createCompatMasonry( const size = createElementSize(element); - let layoutNotRequested = true; + const treeMutObx = new MutationObserver(() => { + layout.reloadItems?.(); + }); - const reflow = () => { - layout.layout?.(); - layoutNotRequested = true; - }; + onCleanup(() => treeMutObx.disconnect()); 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 - if (layoutNotRequested) { - layoutNotRequested = false; - requestAnimationFrame(reflow); - } + layout.layout?.(); }); if (import.meta.hot) { - const onHotReloadUpdate = () => { - if (layoutNotRequested) { - layoutNotRequested = false; - requestAnimationFrame(reflow); - } - }; - import.meta.hot.on("vite:afterUpdate", onHotReloadUpdate); - import.meta.hot.off("vite:afterUpdate", onHotReloadUpdate); + import.meta.hot.on("vite:afterUpdate", () => { + layout.layout?.(); + }); } } @@ -99,11 +80,11 @@ const supportsCSSMasonryLayout = /* @__PURE__ */ CSS.supports( console.debug("supports css masonry layout", supportsCSSMasonryLayout); -const useNativeImpl = import.meta.env.VITE_PLATFORM_MASONRY_ALWAYS_COMPAT +const useNativeImpl = import.meta.env.VITE_PLATFROM_MASONRY_ALWAYS_COMPAT ? false : supportsCSSMasonryLayout; -if (import.meta.env.VITE_PLATFORM_MASONRY_ALWAYS_COMPAT) { +if (import.meta.env.VITE_PLATFROM_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 cc29999..56f6c8e 100644 --- a/src/profiles/Profile.tsx +++ b/src/profiles/Profile.tsx @@ -171,6 +171,10 @@ const Profile: Component = () => { ), ); + const useSessionDisplayName = (e: HTMLElement) => { + createRenderEffect(() => (e.innerHTML = sessionDisplayName())); + }; + const toggleSubscribeHome = async (event: Event) => { const client = session().client; if (!session().account) return; @@ -214,7 +218,9 @@ const Profile: Component = () => { style={{ visibility: scrolledPastBanner() ? undefined : "hidden", }} - innerHTML={displayName()} + ref={(e: HTMLElement) => + createRenderEffect(() => (e.innerHTML = displayName())) + } > { - + {/* // for future */} @@ -378,7 +384,7 @@ const Profile: Component = () => { : undefined } > - + 's Home @@ -413,7 +419,9 @@ const Profile: Component = () => { + createRenderEffect(() => (e.innerHTML = displayName())) + } aria-label="Display name" > @@ -456,7 +464,9 @@ const Profile: Component = () => {
+ createRenderEffect(() => (e.innerHTML = description() || "")) + } >
{ - + ); }} diff --git a/src/timelines/TootLangPicker.tsx b/src/timelines/ChooseTootLang.tsx similarity index 94% rename from src/timelines/TootLangPicker.tsx rename to src/timelines/ChooseTootLang.tsx index e86f69e..8177783 100644 --- a/src/timelines/TootLangPicker.tsx +++ b/src/timelines/ChooseTootLang.tsx @@ -1,4 +1,9 @@ -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, @@ -14,7 +19,6 @@ 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; @@ -54,7 +58,6 @@ const ChooseTootLang: Component = (props) => { } - class="TootLangPicker" > 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`. */ @@ -143,8 +195,8 @@ const RegularToot: Component = (oprops) => { <>
= (oprops) => {
{ + createRenderEffect(() => { + e.innerHTML = resolveCustomEmoji( + status().account.displayName, + toot().emojis, + ); + }); + }} > boosts
diff --git a/src/timelines/TootBottomSheet.tsx b/src/timelines/TootBottomSheet.tsx index 065a754..09465db 100644 --- a/src/timelines/TootBottomSheet.tsx +++ b/src/timelines/TootBottomSheet.tsx @@ -261,7 +261,13 @@ const TootBottomSheet: Component = (props) => { > - <span innerHTML={tootDisplayName() ?? "Someone"}></span> + <span + ref={(e: HTMLElement) => + createRenderEffect( + () => (e.innerHTML = tootDisplayName() ?? "Someone"), + ) + } + ></span> <span>'s toot</span> diff --git a/src/timelines/TootComposer.tsx b/src/timelines/TootComposer.tsx index 450f9ad..2895c67 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 "./TootLangPicker"; +import ChooseTootLang from "./ChooseTootLang"; import type { mastodon } from "masto"; import cardStyles from "~material/cards.module.css"; import Menu, { createManagedMenuState } from "~material/Menu"; @@ -349,10 +349,15 @@ const TootComposer: Component<{ { + createRenderEffect(() => { + const inf = session()?.account.inf; + return (e.innerHTML = resolveCustomEmoji( + inf?.displayName || "", + inf?.emojis ?? [], + )); + }); + }} > diff --git a/src/timelines/TootLangPicker.css b/src/timelines/TootLangPicker.css deleted file mode 100644 index f092267..0000000 --- a/src/timelines/TootLangPicker.css +++ /dev/null @@ -1,4 +0,0 @@ - -.TootLangPicker { - overflow: auto; -} diff --git a/src/timelines/toots/TootAuthorGroup.css b/src/timelines/toot.module.css similarity index 85% rename from src/timelines/toots/TootAuthorGroup.css rename to src/timelines/toot.module.css index bbef056..e666f66 100644 --- a/src/timelines/toots/TootAuthorGroup.css +++ b/src/timelines/toot.module.css @@ -1,4 +1,4 @@ -.TootAuthorGroup { +.tootAuthorGrp { display: flex; align-items: flex-start; gap: 8px; @@ -10,7 +10,7 @@ } } -.TootAuthorGroup > .name-grp { +.tootAuthorNameGrp { display: grid; grid-template-columns: 1fr auto; color: var(--tutu-color-secondary-text-on-surface); @@ -30,10 +30,10 @@ } } -.TootAuthorGroup > .name-grp > .name-primary { +.tootAuthorNamePrimary { color: var(--tutu-color-on-surface); - > .acct-mark { + > :global(.acct-mark) { font-size: 1.2em; color: var(--tutu-color-secondary-text-on-surface); vertical-align: sub; @@ -41,7 +41,7 @@ } } -.TootAuthorGroup > .avatar { +.tootAvatar { 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 deleted file mode 100644 index 121b2c5..0000000 --- a/src/timelines/toots/TootAuthorGroup.tsx +++ /dev/null @@ -1,53 +0,0 @@ -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 2960794..a4643a2 100644 --- a/src/timelines/toots/TootContent.tsx +++ b/src/timelines/toots/TootContent.tsx @@ -81,13 +81,15 @@ const TootContent: Component = (oprops) => {
{ + createRenderEffect(() => { + ref.innerHTML = props.spoilerText + ? props.emojis + ? resolveCustomEmoji(props.spoilerText, props.emojis) + : props.spoilerText + : ""; + }); + }} >
@@ -95,12 +97,14 @@ const TootContent: Component = (oprops) => {
+ createRenderEffect(() => { + ref.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 a2b9dc6..a148fcb 100644 --- a/src/timelines/toots/TootPoll.tsx +++ b/src/timelines/toots/TootPoll.tsx @@ -20,7 +20,10 @@ 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"; @@ -28,13 +31,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(); @@ -43,7 +46,7 @@ const TootPoll: Component = (props) => { const [initialVote, setInitialVote] = createSignal(0); - const poll = () => props.value; + const poll = () => props.value const isShowResult = () => { const n = mustShowResult(); @@ -115,10 +118,14 @@ const TootPoll: Component = (props) => { > + createRenderEffect(() => { + e.innerHTML = resolveCustomEmoji( + option().title, + option().emojis, + ); + }) + } > diff --git a/src/timelines/toots/TootPollDialog.tsx b/src/timelines/toots/TootPollDialog.tsx index f63d204..7374b0c 100644 --- a/src/timelines/toots/TootPollDialog.tsx +++ b/src/timelines/toots/TootPollDialog.tsx @@ -96,10 +96,15 @@ const TootPollDialog: Component = (props) => { > + createRenderEffect( + () => + (e.innerHTML = resolveCustomEmoji( + option().title, + option().emojis, + )), + ) + } >
{ + createRenderEffect(() => (e.innerHTML = item.value)); + }} + >