show placeholder when favicon is loading

This commit is contained in:
Athou
2022-11-08 11:51:26 +01:00
parent 9e65f5726c
commit 9466bc544c
6 changed files with 40 additions and 15 deletions

View File

@@ -10,6 +10,9 @@ interface ImageWithPlaceholderWhileLoadingProps {
height?: number | "auto" height?: number | "auto"
placeholderWidth?: number placeholderWidth?: number
placeholderHeight?: number placeholderHeight?: number
placeholderBackgroundColor?: string
placeholderIconSize?: number
placeholderIconColor?: string
} }
const useStyles = createStyles((theme, props: ImageWithPlaceholderWhileLoadingProps) => ({ const useStyles = createStyles((theme, props: ImageWithPlaceholderWhileLoadingProps) => ({
@@ -17,8 +20,8 @@ const useStyles = createStyles((theme, props: ImageWithPlaceholderWhileLoadingPr
width: props.placeholderWidth ?? 400, width: props.placeholderWidth ?? 400,
height: props.placeholderHeight ?? 600, height: props.placeholderHeight ?? 600,
maxWidth: "100%", maxWidth: "100%",
color: theme.fn.variant({ color: theme.primaryColor, variant: "subtle" }).color, color: props.placeholderIconColor ?? theme.fn.variant({ color: theme.primaryColor, variant: "subtle" }).color,
backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[5] : theme.colors.gray[1], backgroundColor: props.placeholderBackgroundColor ?? (theme.colorScheme === "dark" ? theme.colors.dark[5] : theme.colors.gray[1]),
}, },
})) }))
@@ -32,7 +35,7 @@ export function ImageWithPlaceholderWhileLoading(props: ImageWithPlaceholderWhil
<Box> <Box>
<Center className={classes.placeholder}> <Center className={classes.placeholder}>
<div> <div>
<TbPhoto size={48} /> <TbPhoto size={props.placeholderIconSize ?? 48} />
</div> </div>
</Center> </Center>
</Box> </Box>

View File

@@ -1,8 +1,9 @@
import { Box, createStyles, Image, Text } from "@mantine/core" import { Box, createStyles, Text } from "@mantine/core"
import { Entry } from "app/types" import { Entry } from "app/types"
import { RelativeDate } from "components/RelativeDate" import { RelativeDate } from "components/RelativeDate"
import { OnDesktop } from "components/responsive/OnDesktop" import { OnDesktop } from "components/responsive/OnDesktop"
import { FeedEntryTitle } from "./FeedEntryTitle" import { FeedEntryTitle } from "./FeedEntryTitle"
import { FeedFavicon } from "./FeedFavicon"
export interface FeedEntryHeaderProps { export interface FeedEntryHeaderProps {
entry: Entry entry: Entry
@@ -37,7 +38,7 @@ export function FeedEntryCompactHeader(props: FeedEntryHeaderProps) {
return ( return (
<Box className={classes.wrapper}> <Box className={classes.wrapper}>
<Box> <Box>
<Image withPlaceholder src={props.entry.iconUrl} alt="feed icon" width={18} height={18} /> <FeedFavicon url={props.entry.iconUrl} />
</Box> </Box>
<OnDesktop> <OnDesktop>
<Text color="dimmed" className={classes.feedName}> <Text color="dimmed" className={classes.feedName}>

View File

@@ -1,7 +1,8 @@
import { Box, createStyles, Image, Text } from "@mantine/core" import { Box, createStyles, Text } from "@mantine/core"
import { Entry } from "app/types" import { Entry } from "app/types"
import { RelativeDate } from "components/RelativeDate" import { RelativeDate } from "components/RelativeDate"
import { FeedEntryTitle } from "./FeedEntryTitle" import { FeedEntryTitle } from "./FeedEntryTitle"
import { FeedFavicon } from "./FeedFavicon"
export interface FeedEntryHeaderProps { export interface FeedEntryHeaderProps {
entry: Entry entry: Entry
@@ -33,7 +34,7 @@ export function FeedEntryHeader(props: FeedEntryHeaderProps) {
</Box> </Box>
<Box className={classes.headerSubtext}> <Box className={classes.headerSubtext}>
<Box mr={6}> <Box mr={6}>
<Image withPlaceholder src={props.entry.iconUrl} alt="feed icon" width={18} height={18} /> <FeedFavicon url={props.entry.iconUrl} />
</Box> </Box>
<Box> <Box>
<Text color="dimmed">{props.entry.feedName}</Text> <Text color="dimmed">{props.entry.feedName}</Text>

View File

@@ -0,0 +1,22 @@
import { ImageWithPlaceholderWhileLoading } from "components/ImageWithPlaceholderWhileLoading"
export interface FeedFaviconProps {
url: string
size?: number
}
export function FeedFavicon({ url, size = 18 }: FeedFaviconProps) {
return (
<ImageWithPlaceholderWhileLoading
src={url}
alt="feed favicon"
width={size}
height={size}
placeholderWidth={size}
placeholderHeight={size}
placeholderBackgroundColor="inherit"
placeholderIconSize={size}
placeholderIconColor="inherit"
/>
)
}

View File

@@ -1,4 +1,5 @@
import { Box, createStyles, Image } from "@mantine/core" import { Box, createStyles } from "@mantine/core"
import { FeedFavicon } from "components/content/FeedFavicon"
import React, { ReactNode } from "react" import React, { ReactNode } from "react"
import { UnreadCount } from "./UnreadCount" import { UnreadCount } from "./UnreadCount"
@@ -49,11 +50,7 @@ export function TreeNode(props: TreeNodeProps) {
return ( return (
<Box py={1} pl={props.level * 20} className={classes.node} onClick={(e: React.MouseEvent) => props.onClick(e, props.id)}> <Box py={1} pl={props.level * 20} className={classes.node} onClick={(e: React.MouseEvent) => props.onClick(e, props.id)}>
<Box mr={6} onClick={(e: React.MouseEvent) => props.onIconClick && props.onIconClick(e, props.id)}> <Box mr={6} onClick={(e: React.MouseEvent) => props.onIconClick && props.onIconClick(e, props.id)}>
{typeof props.icon === "string" ? ( {typeof props.icon === "string" ? <FeedFavicon url={props.icon} /> : props.icon}
<Image withPlaceholder src={props.icon} alt="favicon" width={18} height={18} />
) : (
props.icon
)}
</Box> </Box>
<Box className={classes.nodeText}>{props.name}</Box> <Box className={classes.nodeText}>{props.name}</Box>
{!props.expanded && ( {!props.expanded && (

View File

@@ -1,9 +1,10 @@
import { t } from "@lingui/macro" import { t } from "@lingui/macro"
import { Box, Center, Image, Kbd, TextInput } from "@mantine/core" import { Box, Center, Kbd, TextInput } from "@mantine/core"
import { openSpotlight, SpotlightAction, SpotlightProvider } from "@mantine/spotlight" import { openSpotlight, SpotlightAction, SpotlightProvider } from "@mantine/spotlight"
import { redirectToFeed } from "app/slices/redirect" import { redirectToFeed } from "app/slices/redirect"
import { useAppDispatch } from "app/store" import { useAppDispatch } from "app/store"
import { Subscription } from "app/types" import { Subscription } from "app/types"
import { FeedFavicon } from "components/content/FeedFavicon"
import { useMousetrap } from "hooks/useMousetrap" import { useMousetrap } from "hooks/useMousetrap"
import { TbSearch } from "react-icons/tb" import { TbSearch } from "react-icons/tb"
@@ -17,7 +18,7 @@ export function TreeSearch(props: TreeSearchProps) {
.sort((f1, f2) => f1.name.localeCompare(f2.name)) .sort((f1, f2) => f1.name.localeCompare(f2.name))
.map(f => ({ .map(f => ({
title: f.name, title: f.name,
icon: <Image withPlaceholder src={f.iconUrl} alt="favicon" width={18} height={18} />, icon: <FeedFavicon url={f.iconUrl} />,
onTrigger: () => dispatch(redirectToFeed(f.id)), onTrigger: () => dispatch(redirectToFeed(f.id)),
})) }))