Skip to content

Commit

Permalink
feat(shiny): handle shiny watch resources
Browse files Browse the repository at this point in the history
  • Loading branch information
gdarchen committed Jul 12, 2024
1 parent d913943 commit 2da9173
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 43 deletions.
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,8 @@
<!-- TODO: Contentsquare
- update screenshot in README
- update About
- new skills section
- new screenshot in metadata
- update profile README
-->
<!-- TODO: profile README (and dynamic svg) -->

<!-- TODO: uncomment when public -->
<!-- [![last commit](https://badgen.net/github/last-commit/gdarchen/portfolio?icon=https://simpleicons.now.sh/git/fff)](https://github.com/gdarchen/portfolio) -->
Expand Down
1 change: 1 addition & 0 deletions src/app/watch/dto/watchResource.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ export const transformWatchResourceToDTO = (resource: any): WatchResource => {
date: new Date(properties.Date.date.start),
source: properties.Source.select.name,
subSource: properties['Sub-source'].rich_text?.[0]?.plain_text,
shiny: properties.Shiny.checkbox,
}
}
1 change: 1 addition & 0 deletions src/app/watch/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export type WatchResource = {
date: Date
source?: string
subSource?: string
shiny?: boolean
}
97 changes: 57 additions & 40 deletions src/app/watch/watchResource.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,29 @@ import { FC, ReactNode } from 'react'
import { tv } from 'tailwind-variants'

import Badge from '@/components/badge/Badge'
import Meteors from '@/components/cards/Meteors'

import type { WatchResource } from './types'

const VariantMapping = {
Article: {
color: 'teal',
emoji: '📝',
},
Video: {
color: 'red',
emoji: '📹',
},
Podcast: {
color: 'yellow',
emoji: '🎧',
},
Book: {
color: 'blue',
emoji: '📙',
},
} as const

type Props = {
resource: WatchResource
query?: string
Expand Down Expand Up @@ -53,22 +73,9 @@ const highlightQuery = (str: string, query: string): ReactNode => {
}

const ResourceType: FC<{ type: WatchResource['type'] }> = ({ type }) => {
const variant =
type === 'Article'
? 'teal'
: type === 'Video'
? 'red'
: type === 'Podcast'
? 'yellow'
: 'default'
const emoji =
type === 'Article'
? '📝'
: type === 'Video'
? '📹'
: type === 'Podcast'
? '🎧'
: ''
const variantMapping = VariantMapping[type]
const variant = variantMapping?.color ?? 'default'
const emoji = variantMapping?.emoji ?? ''

return (
<Badge variant={variant}>
Expand Down Expand Up @@ -108,34 +115,44 @@ const Tldr: FC<{ parts: WatchResource['tldr']; query?: string }> = ({
}

const WatchResource: FC<Props> = ({ resource, query, truncate = true }) => {
const { title, tldr, source, subSource, url, type } = resource
const { title, tldr, source, subSource, url, type, shiny } = resource

return (
<a
href={url}
target="_blank"
rel="noreferrer"
className="group flex max-w-sm flex-col justify-between rounded-lg border border-gray-200 bg-white p-4 shadow hover:bg-gray-100 dark:border-gray-700 dark:bg-gray-800 dark:hover:bg-gray-700"
>
<div>
<h5 className={resourceTitle({ truncate })}>
{query ? highlightQuery(title, query) : title}
</h5>
<div className="grid grid-cols-6 gap-4 font-normal text-gray-700 dark:text-gray-400">
<div className={resourceTldr({ truncate })}>
<Tldr parts={tldr} query={query} />
<div className="group relative flex">
{shiny && (
<div className="absolute inset-0 z-0 rounded-lg bg-gradient-to-r from-purple-600 to-pink-600 opacity-25 blur transition duration-1000 group-hover:opacity-100 group-hover:duration-200" />
)}
<a
href={url}
target="_blank"
rel="noreferrer"
className="relative z-10 flex max-w-sm flex-col justify-between overflow-hidden rounded-lg border border-gray-200 bg-white p-4 shadow hover:bg-gray-100 dark:border-gray-700 dark:bg-gray-800 dark:hover:bg-gray-700"
>
<div>
<h5 className={resourceTitle({ truncate })}>
{query ? highlightQuery(title, query) : title}
</h5>
<div className="grid grid-cols-6 gap-4 font-normal text-gray-700 dark:text-gray-400">
<div className={resourceTldr({ truncate })}>
<Tldr parts={tldr} query={query} />
</div>
</div>
</div>
</div>

<div className="mt-3 md:mt-6">
<Badge className="mr-2 inline group-hover:bg-white dark:group-hover:bg-white/10">
{source}
{subSource && <span className="ml-2">{subSource}</span>}
</Badge>
<ResourceType type={type} />
</div>
</a>

<div className="mt-3 md:mt-6">
<Badge className="mr-2 inline group-hover:bg-white dark:group-hover:bg-white/10">
{source}
{subSource && <span className="ml-2">{subSource}</span>}
</Badge>
<ResourceType type={type} />
</div>
{shiny && (
<div>
<Meteors number={25} />
</div>
)}
</a>
</div>
)
}

Expand Down
31 changes: 31 additions & 0 deletions src/components/cards/Meteors.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React, { FC } from 'react'
import clsx from 'clsx'

type Props = {
number?: number
}

const Meteors: FC<Props> = ({ number = 20 }) => {
const meteors = new Array(number).fill(true)
return (
<>
{meteors.map((el, idx) => (
<span
key={'meteor' + idx}
className={clsx(
'absolute left-1/2 top-1/2 size-0.5 rotate-[215deg] animate-meteor-effect rounded-full bg-slate-500 shadow-[0_0_0_1px_#ffffff10]',
"before:absolute before:top-1/2 before:h-px before:w-[50px] before:-translate-y-1/2 before:bg-gradient-to-r before:from-slate-300 before:to-transparent before:content-[''] group-hover:before:from-blue-400",
)}
style={{
top: 0,
left: Math.floor(Math.random() * (400 - -400) + -400) + 'px',
animationDelay: Math.random() * (0.8 - 0.2) + 0.2 + 's',
animationDuration: Math.floor(Math.random() * (10 - 2) + 2) + 's',
}}
/>
))}
</>
)
}

export default Meteors
13 changes: 13 additions & 0 deletions tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,19 @@ export default {
'5xl': '3840px',
},
},
animation: {
'meteor-effect': 'meteor 5s linear infinite',
},
keyframes: {
meteor: {
'0%': { transform: 'rotate(215deg) translateX(0)', opacity: '1' },
'70%': { opacity: '1' },
'100%': {
transform: 'rotate(215deg) translateX(-500px)',
opacity: '0',
},
},
},
},
plugins: [
require('tailwind-scrollbar-hide'),
Expand Down

0 comments on commit 2da9173

Please sign in to comment.