feat(bento): skeleton components

This commit is contained in:
Jason
2023-09-26 16:22:38 -07:00
parent 03d8342fa7
commit b89bc531ea
8 changed files with 108 additions and 8 deletions

View File

@@ -18,7 +18,7 @@
This is a list of the various technologies used to build this website:
| Name | Link |
| Category | Technology Name |
| ------------------- | ------------------------------------------------------------------------- |
| Framework | [Next.js](https://nextjs.org/) |
| Deployment | [Vercel](https://vercel.com) |

View File

@@ -6,20 +6,22 @@ import { useState } from 'react'
interface ExtendedImageProps extends ImageProps {
noSkeleton?: boolean
noRelative?: boolean
skeletonClassName?: string
}
const Image = ({
onLoad,
className,
noSkeleton,
noSkeleton = false,
noRelative = false,
skeletonClassName,
...rest
}: ExtendedImageProps) => {
const [isLoading, setIsLoading] = useState(true)
return (
<div className="relative">
<div className={`${noRelative ? 'inline-block' : 'relative'}`}>
{!noSkeleton && isLoading && (
<Skeleton
className={`absolute left-0 top-0 h-full w-full rounded-md object-contain ${skeletonClassName}`}

View File

@@ -1,12 +1,13 @@
'use client'
import { lgLayout, mdLayout, smLayout } from '@/scripts/utils/bento-layouts'
import Image from 'next/image'
import React, { useEffect, useState } from 'react'
import { Responsive, WidthProvider } from 'react-grid-layout'
import { FaGithub, FaTwitter } from 'react-icons/fa'
import { useLanyard } from 'react-use-lanyard'
import Image from '../Image'
import { Skeleton } from '../shadcn/skeleton'
import DiscordPresence from './DiscordPresence'
import ExternalLink from './ExternalLink'
import SilhouetteHover from './SilhouetteHover'
@@ -22,6 +23,9 @@ const BentoBox = ({ posts }) => {
const [rowHeight, setRowHeight] = useState(280)
const [introSilhouette, setIntroSilhouette] = useState(false)
const [isDiscordLoaded, setDiscordLoaded] = useState(false)
const [isSpotifyLoaded, setIsSpotifyLoaded] = useState(false)
const timeoutRef = React.useRef<ReturnType<typeof setTimeout> | null>(null)
const handleWidthChange = (width) => {
@@ -89,6 +93,8 @@ const BentoBox = ({ posts }) => {
className={`rounded-3xl object-cover transition-opacity duration-300 ${
introSilhouette ? 'opacity-100' : 'opacity-0 delay-75'
}`}
skeletonClassName="rounded-3xl"
noRelative
unoptimized
priority
/>
@@ -99,6 +105,8 @@ const BentoBox = ({ posts }) => {
className={`rounded-3xl object-cover transition-opacity duration-300 ${
introSilhouette ? 'opacity-0 delay-75' : 'opacity-100'
}`}
skeletonClassName="rounded-3xl"
noRelative
unoptimized
priority
/>
@@ -126,12 +134,22 @@ const BentoBox = ({ posts }) => {
src="/static/images/bento/bento-image-1.svg"
alt="Bento Box 1"
fill={true}
noRelative
className="rounded-3xl object-cover"
skeletonClassName="rounded-3xl"
unoptimized
priority
/>
</div>
<div key="discord">
{!lanyard.isValidating && <DiscordPresence lanyard={lanyard.data} />}
{lanyard.data && !lanyard.isValidating ? (
<DiscordPresence
lanyard={lanyard.data}
onLoad={() => setDiscordLoaded(true)}
/>
) : (
<Skeleton className="w-full h-full rounded-3xl" />
)}
</div>
<div
key="latest-post"
@@ -152,6 +170,8 @@ const BentoBox = ({ posts }) => {
width={0}
height={0}
className="m-2 w-[80%] rounded-2xl border border-border md:m-3 lg:m-4"
skeletonClassName="rounded-3xl"
noRelative
unoptimized
/>
</SilhouetteHover>
@@ -163,7 +183,9 @@ const BentoBox = ({ posts }) => {
alt="Bento Box 2"
fill={true}
className="rounded-3xl object-cover"
noRelative
unoptimized
priority
/>
</div>
<div key="wakatime">Child G</div>
@@ -191,7 +213,14 @@ const BentoBox = ({ posts }) => {
onMouseEnter={() => setIntroSilhouette(true)}
onMouseLeave={() => setIntroSilhouette(false)}
>
{!lanyard.isValidating && <SpotifyPresence lanyard={lanyard.data} />}
{lanyard.data && !lanyard.isValidating ? (
<SpotifyPresence
lanyard={lanyard.data}
onLoad={() => setIsSpotifyLoaded(true)}
/>
) : (
<Skeleton className="w-full h-full rounded-3xl z-[1]" />
)}
<SilhouetteHover
silhouetteSrc="/static/images/bento/bento-spotify-silhouette.svg"
silhouetteAlt="Bento Spotify Silhouette"
@@ -213,6 +242,8 @@ const BentoBox = ({ posts }) => {
alt="Bento Technologies"
fill={true}
className="rounded-3xl object-cover"
skeletonClassName="rounded-3xl"
noRelative
unoptimized
/>
</div>

View File

@@ -2,7 +2,7 @@ import Image from 'next/image'
import React, { useEffect, useState } from 'react'
import { FaDiscord } from 'react-icons/fa'
const DiscordPresence = ({ lanyard }) => {
const DiscordPresence = ({ lanyard, onLoad }) => {
const mainActivity = lanyard.data.activities.filter(
(activity) => activity.type === 0 && activity.assets
)[0]
@@ -25,6 +25,12 @@ const DiscordPresence = ({ lanyard }) => {
}
}, [mainActivity?.timestamps?.start])
useEffect(() => {
if (hasMainActivity && onLoad) {
onLoad()
}
}, [hasMainActivity, onLoad])
return (
<>
<div className="hidden bento-lg:relative w-full h-full bento-lg:flex flex-col">

View File

@@ -5,7 +5,7 @@ import { set } from 'react-use-lanyard'
import ExternalLink from './ExternalLink'
const SpotifyPresence = ({ lanyard }) => {
const SpotifyPresence = ({ lanyard, onLoad }) => {
useEffect(() => {
if (
JSON.parse(lanyard.data.kv.spotify_last_played) !== lanyard.data.spotify &&
@@ -37,6 +37,12 @@ const SpotifyPresence = ({ lanyard }) => {
const { song, artist, album, album_art_url, track_id } = displayData
useEffect(() => {
if (lanyard && onLoad) {
onLoad()
}
}, [lanyard, onLoad])
return (
<>
<div className="flex bento-md:hidden z-[1] bento-lg:flex h-full w-full flex-col justify-between p-6">

View File

@@ -13,6 +13,8 @@ import { formatDate } from 'pliny/utils/formatDate'
/* eslint-disable jsx-a11y/anchor-is-valid */
/* eslint-disable jsx-a11y/anchor-is-valid */
interface PaginationProps {
totalPages: number
currentPage: number

52
package-lock.json generated
View File

@@ -28,6 +28,7 @@
"postcss": "^8.4.24",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-github-calendar": "^4.0.1",
"react-grid-layout": "^1.4.1",
"react-icons": "^4.11.0",
"react-markdown": "^8.0.7",
@@ -4572,6 +4573,11 @@
"@types/estree": "*"
}
},
"node_modules/@types/chroma-js": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/@types/chroma-js/-/chroma-js-2.4.1.tgz",
"integrity": "sha512-YIm3RLfWdDU0/3rsNnu/Hh4uKCLQ9p/w1NvnFfBOBL/BGqOvuLNuhXwkJMUKMscmFJdan25lYqv2+qh1l7tZLg=="
},
"node_modules/@types/debug": {
"version": "4.1.8",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz",
@@ -5793,6 +5799,11 @@
"fsevents": "~2.3.2"
}
},
"node_modules/chroma-js": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz",
"integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A=="
},
"node_modules/citeproc": {
"version": "2.4.63",
"resolved": "https://registry.npmjs.org/citeproc/-/citeproc-2.4.63.tgz",
@@ -6411,6 +6422,21 @@
"node": ">= 12"
}
},
"node_modules/date-fns": {
"version": "2.30.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
"integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
"dependencies": {
"@babel/runtime": "^7.21.0"
},
"engines": {
"node": ">=0.11"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/date-fns"
}
},
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -12589,6 +12615,20 @@
"node": ">=0.10.0"
}
},
"node_modules/react-activity-calendar": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/react-activity-calendar/-/react-activity-calendar-2.0.2.tgz",
"integrity": "sha512-gUm7j8rgBgYnrfBQkR4y3gl/gPI1By2Yfg1O1EpYuOdYdRsTtn404H4eH9+iZBCAeZjG49NBPo/BmjvOSyaChg==",
"dependencies": {
"@types/chroma-js": "^2.4.0",
"chroma-js": "^2.4.0",
"date-fns": "^2.30.0"
},
"peerDependencies": {
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0"
}
},
"node_modules/react-dom": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
@@ -12622,6 +12662,18 @@
"node": ">=6"
}
},
"node_modules/react-github-calendar": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/react-github-calendar/-/react-github-calendar-4.0.1.tgz",
"integrity": "sha512-WTJFto5i628k8XhRKv/VsV93RL9jGoMl6thxv7UWPaF1Okyo3u/mHhEg261nkPI+8CbPSzmlgfoGUnldZKJgvA==",
"dependencies": {
"react-activity-calendar": "^2.0.0"
},
"peerDependencies": {
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0"
}
},
"node_modules/react-grid-layout": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/react-grid-layout/-/react-grid-layout-1.4.1.tgz",

View File

@@ -32,6 +32,7 @@
"postcss": "^8.4.24",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-github-calendar": "^4.0.1",
"react-grid-layout": "^1.4.1",
"react-icons": "^4.11.0",
"react-markdown": "^8.0.7",