feat: lazy load

This commit is contained in:
Shusui MOYATANI
2023-12-16 10:45:57 +09:00
parent de223c9367
commit e97eb9144c
7 changed files with 377 additions and 266 deletions

View File

@@ -1,5 +1,6 @@
import { Component, JSX, Switch, Match, createEffect } from 'solid-js';
import { Component, JSX, Switch, Match, createEffect, Show } from 'solid-js';
import LazyLoad from '@/components/utils/LazyLoad';
import SafeLink from '@/components/utils/SafeLink';
import useConfig from '@/core/useConfig';
import { useOgp } from '@/utils/ogp';
@@ -28,65 +29,89 @@ const youtubeUrl = (videoId: string): string => {
return iframeUrl.href;
};
const PreviewedLink: Component<PreviewdLinkProps> = (props) => {
const TwitterEmbed: Component<{ class?: string; href: string }> = (props) => {
let twitterRef: HTMLQuoteElement | undefined;
const { config } = useConfig();
const { ogp } = useOgp(() => ({
url: props.href,
}));
createEffect(() => {
if (isTwitterUrl(props.href)) {
window.twttr?.widgets?.load(twitterRef);
}
});
return (
<blockquote class="twitter-tweet" ref={twitterRef}>
<a
class={props.class}
href={twitterUrl(props.href)}
target="_blank"
rel="noreferrer noopener"
>
{twitterUrl(props.href)}
</a>
</blockquote>
);
};
const OgpEmbed: Component<{ url: string }> = (props) => {
const { ogp } = useOgp(() => ({
url: props.url,
}));
return (
<Show when={ogp()} fallback={<SafeLink href={props.url} />} keyed>
{(ogpProps) => (
<SafeLink href={props.url}>
<div class="my-2 rounded-lg border transition-colors hover:bg-slate-100">
<img
alt={ogpProps.title}
class="max-w-full rounded-t-lg object-contain shadow"
src={ogpProps.image}
/>
<div class="mb-1 p-1">
<div class="text-xs text-slate-500">{new URL(ogpProps.url).host}</div>
<div class="text-sm">{ogpProps.title}</div>
<div class="text-xs text-slate-500">{ogpProps.description}</div>
</div>
</div>
</SafeLink>
)}
</Show>
);
};
const PreviewedLink: Component<PreviewdLinkProps> = (props) => {
const { config } = useConfig();
return (
<Switch fallback={<SafeLink class={props.class} href={props.href} />}>
<Match when={config().embedding.twitter && isTwitterUrl(props.href)}>
<blockquote class="twitter-tweet" ref={twitterRef}>
<a
class={props.class}
href={twitterUrl(props.href)}
target="_blank"
rel="noreferrer noopener"
>
{twitterUrl(props.href)}
</a>
</blockquote>
<LazyLoad>{() => <TwitterEmbed class={props.class} href={props.href} />}</LazyLoad>
</Match>
<Match when={config().embedding.youtube && parseYouTubeVideoUrl(props.href)} keyed>
{({ videoId }) => (
<div class="my-2 aspect-video w-full">
<iframe
loading="lazy"
title="YouTube"
class="my-2 h-full w-full"
src={youtubeUrl(videoId)}
allowfullscreen
/>
</div>
<LazyLoad
fallback={
<div class="aspect-video max-w-full">
<SafeLink href={props.href} />
</div>
}
>
{() => (
<div class="my-2 aspect-video w-full">
<iframe
loading="lazy"
title="YouTube"
class="my-2 h-full w-full"
src={youtubeUrl(videoId)}
allowfullscreen
/>
</div>
)}
</LazyLoad>
)}
</Match>
<Match when={config().embedding.ogp && ogp()} keyed>
{(ogpProps) => (
<SafeLink href={props.href}>
<div class="my-2 rounded-lg border transition-colors hover:bg-slate-100">
<img
alt={ogpProps.title}
class="max-w-full rounded-t-lg object-contain shadow"
src={ogpProps.image}
/>
<div class="mb-1 p-1">
<div class="text-xs text-slate-500">{new URL(ogpProps.url).host}</div>
<div class="text-sm">{ogpProps.title}</div>
<div class="text-xs text-slate-500">{ogpProps.description}</div>
</div>
</div>
</SafeLink>
)}
<Match when={config().embedding.ogp}>
<LazyLoad>{() => <OgpEmbed url={props.href} />}</LazyLoad>
</Match>
</Switch>
);