toot medias: extract color from blurhash
All checks were successful
/ depoly (push) Successful in 1m17s
All checks were successful
/ depoly (push) Successful in 1m17s
This commit is contained in:
parent
c372ea4a92
commit
2aa2cf21da
5 changed files with 226 additions and 40 deletions
|
@ -6,6 +6,7 @@ import {
|
|||
Show,
|
||||
createRenderEffect,
|
||||
createEffect,
|
||||
createMemo,
|
||||
} from "solid-js";
|
||||
import tootStyle from "./toot.module.css";
|
||||
import { formatRelative } from "date-fns";
|
||||
|
@ -29,13 +30,13 @@ import { Divider } from "@suid/material";
|
|||
import cardStyle from "../material/cards.module.css";
|
||||
import Button from "../material/Button.js";
|
||||
import MediaAttachmentGrid from "./MediaAttachmentGrid.js";
|
||||
import { FastAverageColor } from "fast-average-color";
|
||||
import Color from "colorjs.io";
|
||||
import { useDateFnLocale } from "../platform/i18n";
|
||||
import { canShare, share } from "../platform/share";
|
||||
import { makeAcctText, useDefaultSession } from "../masto/clients";
|
||||
import TootContent from "./toot-components/TootContent";
|
||||
import BoostIcon from "./toot-components/BoostIcon";
|
||||
import { averageColorHex } from "../platform/blurhash";
|
||||
|
||||
type TootActionGroupProps<T extends mastodon.v1.Status> = {
|
||||
onRetoot?: (value: T) => void;
|
||||
|
@ -205,31 +206,44 @@ export function TootPreviewCard(props: {
|
|||
}
|
||||
});
|
||||
|
||||
const onImgLoad = (event: Event & { currentTarget: HTMLImageElement }) => {
|
||||
// TODO: better extraction algorithm
|
||||
// I'd like to use a pattern panel and match one in the panel from the extracted color
|
||||
const fac = new FastAverageColor();
|
||||
const result = fac.getColor(event.currentTarget);
|
||||
if (result.error) {
|
||||
console.error(result.error);
|
||||
fac.destroy();
|
||||
const imgAverageColor = createMemo(() => {
|
||||
if (!props.src.image) return;
|
||||
return new Color(averageColorHex(props.src.blurhash));
|
||||
});
|
||||
|
||||
const prefersWhiteText = createMemo(() => {
|
||||
const oc = imgAverageColor();
|
||||
if (!oc) return;
|
||||
const colorWhite = new Color("white");
|
||||
|
||||
return colorWhite.luminance / oc.luminance > 3.5;
|
||||
});
|
||||
|
||||
const focusSurfaceColor = createMemo(() => {
|
||||
const oc = imgAverageColor();
|
||||
if (!oc) return;
|
||||
if (prefersWhiteText()) {
|
||||
return new Color(oc).darken(0.2);
|
||||
} else {
|
||||
return new Color(oc).lighten(0.2);
|
||||
}
|
||||
});
|
||||
|
||||
const textColorName = createMemo(() => {
|
||||
const useWhiteText = prefersWhiteText();
|
||||
if (typeof useWhiteText === "undefined") {
|
||||
return;
|
||||
}
|
||||
root.style.setProperty("--tutu-color-surface", result.hex);
|
||||
const focusSurface = result.isDark
|
||||
? new Color(result.hex).darken(0.2)
|
||||
: new Color(result.hex).lighten(0.2);
|
||||
root.style.setProperty("--tutu-color-surface-d", focusSurface.toString());
|
||||
const textColor = result.isDark ? "white" : "black";
|
||||
const secondaryTextColor = new Color(textColor);
|
||||
secondaryTextColor.alpha = 0.75;
|
||||
root.style.setProperty("--tutu-color-on-surface", textColor);
|
||||
root.style.setProperty(
|
||||
"--tutu-color-secondary-text-on-surface",
|
||||
secondaryTextColor.toString(),
|
||||
);
|
||||
fac.destroy();
|
||||
};
|
||||
return useWhiteText ? "white" : "black";
|
||||
});
|
||||
|
||||
const secondaryTextColor = createMemo(() => {
|
||||
const tcn = textColorName();
|
||||
if (!tcn) return;
|
||||
const tc = new Color(tcn);
|
||||
tc.alpha = 0.75;
|
||||
return tc;
|
||||
});
|
||||
|
||||
return (
|
||||
<a
|
||||
|
@ -238,12 +252,18 @@ export function TootPreviewCard(props: {
|
|||
href={props.src.url}
|
||||
target="_blank"
|
||||
referrerPolicy="unsafe-url"
|
||||
style={{
|
||||
"--tutu-color-surface": imgAverageColor()?.toString(),
|
||||
"--tutu-color-surface-d": focusSurfaceColor()?.toString(),
|
||||
"--tutu-color-on-surface": textColorName(),
|
||||
"--tutu-color-secondary-text-on-surface":
|
||||
secondaryTextColor()?.toString(),
|
||||
}}
|
||||
>
|
||||
<Show when={props.src.image}>
|
||||
<img
|
||||
crossOrigin="anonymous"
|
||||
src={props.src.image!}
|
||||
onLoad={onImgLoad}
|
||||
width={props.src.width || undefined}
|
||||
height={props.src.height || undefined}
|
||||
loading="lazy"
|
||||
|
@ -373,16 +393,16 @@ const RegularToot: Component<TootCardProps> = (props) => {
|
|||
<Show when={!!status().reblog}>
|
||||
<div class={tootStyle.tootRetootGrp}>
|
||||
<BoostIcon />
|
||||
<Body2
|
||||
ref={(e: { innerHTML: string }) => {
|
||||
createRenderEffect(() => {
|
||||
e.innerHTML = resolveCustomEmoji(
|
||||
status().account.displayName,
|
||||
toot().emojis,
|
||||
);
|
||||
});
|
||||
}}
|
||||
></Body2>
|
||||
<Body2
|
||||
ref={(e: { innerHTML: string }) => {
|
||||
createRenderEffect(() => {
|
||||
e.innerHTML = resolveCustomEmoji(
|
||||
status().account.displayName,
|
||||
toot().emojis,
|
||||
);
|
||||
});
|
||||
}}
|
||||
></Body2>
|
||||
<span>boosts</span>
|
||||
</div>
|
||||
</Show>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue