Skip to content

Commit

Permalink
feat(discover): improve trending style and discover no image placeholer
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <[email protected]>
  • Loading branch information
Innei committed Oct 25, 2024
1 parent 33b3ac4 commit 86be1a2
Show file tree
Hide file tree
Showing 16 changed files with 128 additions and 93 deletions.
37 changes: 25 additions & 12 deletions apps/renderer/src/modules/discover/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Input } from "@follow/components/ui/input/index.js"
import { Radio } from "@follow/components/ui/radio-group/index.js"
import { RadioGroup } from "@follow/components/ui/radio-group/RadioGroup.jsx"
import type { FeedViewType } from "@follow/constants"
import { getBackgroundGradient } from "@follow/utils/color"
import { zodResolver } from "@hookform/resolvers/zod"
import { useMutation } from "@tanstack/react-query"
import { produce } from "immer"
Expand Down Expand Up @@ -299,18 +300,7 @@ const SearchCard: FC<{
className="flex min-w-0 flex-1 flex-col items-center gap-1"
rel="noreferrer"
>
{assertEntry.media?.[0] ? (
<Media
src={assertEntry.media?.[0].url}
type={assertEntry.media?.[0].type}
previewImageUrl={assertEntry.media?.[0].preview_image_url}
className="aspect-square w-full"
/>
) : (
<div className="flex aspect-square w-full overflow-hidden rounded bg-stone-100 p-2 text-xs leading-tight text-zinc-500">
{assertEntry.title}
</div>
)}
<FeedCardMediaThumbnail entry={assertEntry} />
<div className="line-clamp-2 w-full text-xs leading-tight">
{assertEntry.title}
</div>
Expand Down Expand Up @@ -351,3 +341,26 @@ const SearchCard: FC<{
</Card>
)
})

const FeedCardMediaThumbnail: FC<{
entry: NonUndefined<DiscoverSearchData[number]["entries"]>[number]
}> = ({ entry }) => {
const [, , , bgAccent, bgAccentLight, bgAccentUltraLight] = getBackgroundGradient(entry.title)
return entry.media?.[0] ? (
<Media
src={entry.media?.[0].url}
type={entry.media?.[0].type}
previewImageUrl={entry.media?.[0].preview_image_url}
className="aspect-square w-full"
/>
) : (
<div
className="relative flex aspect-square w-full items-end overflow-hidden rounded p-2 text-xs leading-tight text-zinc-900"
style={{
background: `linear-gradient(37deg, ${bgAccent} 27.82%, ${bgAccentLight} 79.68%, ${bgAccentUltraLight} 100%)`,
}}
>
<div className="line-clamp-2 text-right font-medium">{entry.title}</div>
</div>
)
}
34 changes: 18 additions & 16 deletions apps/renderer/src/modules/trending/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ const TrendingLists: FC<{
follow({ isList: true, id: item.id })
}}
>
<div className="absolute -inset-y-1 inset-x-0 rounded-lg duration-200 group-hover:bg-theme-item-hover" />
<div className="absolute -inset-y-1 inset-x-0 z-[-1] rounded-lg duration-200 group-hover:bg-theme-item-hover" />
<FeedIcon feed={item as any} size={40} />

<div className={cn("ml-1 flex w-full flex-col text-left")}>
Expand All @@ -135,11 +135,11 @@ const TrendingLists: FC<{
)
}

const UserCount = ({ count }: { count: number }) => {
const UserCount: Component<{ count: number }> = ({ count, className }) => {
return (
<span className="flex -translate-y-0.5 items-center gap-0.5 text-xs tabular-nums text-gray-500">
<span className={cn("flex items-center gap-0.5 text-xs tabular-nums opacity-60", className)}>
<PhUsersBold className="size-3" />
{count}
<span>{count}</span>
</span>
)
}
Expand Down Expand Up @@ -215,7 +215,7 @@ const TrendingUsers: FC<{ data: User[] }> = ({ data }) => {
profile(user.id)
}}
>
<div className="absolute -inset-2 right-0 rounded-lg duration-200 group-hover:bg-theme-item-hover" />
<div className="absolute -inset-2 right-0 z-[-1] rounded-lg duration-200 group-hover:bg-theme-item-hover" />
<Avatar className="block aspect-square size-[40px] overflow-hidden rounded-full border border-border ring-1 ring-background">
<AvatarImage src={user?.image || undefined} />
<AvatarFallback>{user.name?.slice(0, 2)}</AvatarFallback>
Expand Down Expand Up @@ -261,7 +261,7 @@ const TrendingFeeds = ({ data }: { data: FeedModel[] }) => {
</a>

<div className="pr-2">
<UserCount count={(feed as any).subscriberCount} />
<UserCount className="-mr-2" count={(feed as any).subscriberCount} />

<Button
type="button"
Expand Down Expand Up @@ -295,17 +295,19 @@ const TrendingEntries = ({ data }: { data: Models.TrendingEntry[] }) => {
return (
<li
key={entry.id}
className="relative w-[calc(100%-2.5rem)] truncate whitespace-nowrap py-0.5 marker:text-accent"
className="relative grid w-full grid-cols-[1fr_auto] gap-2 whitespace-nowrap py-0.5 marker:text-accent"
>
<a
href={entry.url}
target="_blank"
rel="noopener noreferrer"
className="follow-link--underline truncate text-sm"
>
{entry.title}
</a>
<span className="absolute right-0 top-0 flex items-center gap-0.5 text-xs opacity-60">
<div className="m-0 min-w-0 truncate p-0">
<a
href={entry.url}
target="_blank"
rel="noopener noreferrer"
className="follow-link--underline truncate text-sm"
>
{entry.title}
</a>
</div>
<span className="flex items-center gap-0.5 text-xs tabular-nums opacity-60">
<i className="i-mingcute-book-2-line" />
<span>{entry.readCount}</span>
</span>
Expand Down
1 change: 0 additions & 1 deletion apps/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
"satori": "0.11.2",
"sonner": "^1.5.0",
"tailwindcss": "3.4.14",
"uniqolor": "1.1.1",
"use-context-selector": "2.0.0"
},
"devDependencies": {
Expand Down
59 changes: 1 addition & 58 deletions apps/server/src/router/og/__base.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getBackgroundGradient } from "@follow/utils/color"
import * as React from "react"
import uniqolor from "uniqolor"

export const OGCanvas = ({ children, seed }: { children: React.ReactNode; seed: string }) => {
const [bgAccent, bgAccentLight, bgAccentUltraLight] = getBackgroundGradient(seed)
Expand Down Expand Up @@ -55,63 +55,6 @@ export const OGCanvas = ({ children, seed }: { children: React.ReactNode; seed:
</div>
)
}
const lerp = (a: number, b: number, t: number) => a + (b - a) * t

const hexToRgb = (hex: string) => {
const bigint = Number.parseInt(hex.slice(1), 16)
return [(bigint >> 16) & 255, (bigint >> 8) & 255, bigint & 255]
}

const rgbToHex = (r: number, g: number, b: number) => {
return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`
}

const adjustColorTowardsTarget = (color: string, targetColor: string, factor: number) => {
const [r1, g1, b1] = hexToRgb(color)
const [r2, g2, b2] = hexToRgb(targetColor)

const r = Math.round(lerp(r1, r2, factor))
const g = Math.round(lerp(g1, g2, factor))
const b = Math.round(lerp(b1, b2, factor))

return rgbToHex(r, g, b)
}

export const getBackgroundGradient = (seed?: Nullable<string>) => {
const nextSeed = seed ?? Math.random().toString(36).slice(7)

const bgAccent = uniqolor(nextSeed, {
saturation: [30, 35],
lightness: [60, 70],
}).color

const bgAccentLight = uniqolor(nextSeed, {
saturation: [30, 35],
lightness: [80, 90],
}).color

const bgAccentUltraLight = uniqolor(nextSeed, {
saturation: [30, 35],
lightness: [95, 96],
}).color

const targetColor = "#FF5C02"
const factor = 0.3 // Adjust this value to control how close the color gets to the target color

const adjustedAccent = adjustColorTowardsTarget(bgAccent, targetColor, factor)
const adjustedAccentLight = adjustColorTowardsTarget(bgAccentLight, targetColor, factor)
const adjustedAccentUltraLight = adjustColorTowardsTarget(bgAccentUltraLight, targetColor, factor)

return [
adjustedAccent,
adjustedAccentLight,
adjustedAccentUltraLight,
bgAccent,
bgAccentLight,
bgAccentUltraLight,
]
}

function FollowIcon() {
return (
<svg
Expand Down
1 change: 1 addition & 0 deletions packages/atoms/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"name": "@follow/atoms",
"version": "0.0.1",
"sideEffects": false,
"exports": {
"./atoms/*": {
"import": "./src/atoms/*",
Expand Down
1 change: 1 addition & 0 deletions packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "@follow/components",
"version": "0.0.1",
"private": true,
"sideEffects": false,
"exports": {
"./tailwind": "./assets/index.css",
"./modules/*": "./src/modules/*",
Expand Down
1 change: 1 addition & 0 deletions packages/constants/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"name": "@follow/constants",
"version": "0.0.1",
"sideEffects": false,
"exports": {
".": "./src/index.ts"
},
Expand Down
1 change: 1 addition & 0 deletions packages/hooks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "@follow/hooks",
"version": "0.0.1",
"private": true,
"sideEffects": false,
"exports": {
".": {
"import": "./src/index.ts",
Expand Down
1 change: 1 addition & 0 deletions packages/models/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "@follow/models",
"version": "0.0.1",
"private": true,
"sideEffects": false,
"exports": {
".": {
"import": "./src/index.ts",
Expand Down
1 change: 1 addition & 0 deletions packages/shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"url": "https://github.com/RSSNext/follow",
"type": "git"
},
"sideEffects": false,
"exports": {
".": {
"types": "./src/index.ts",
Expand Down
5 changes: 5 additions & 0 deletions packages/types/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ declare global {
type IsLiteralString<T> = T extends string ? (string extends T ? never : T) : never

type OmitStringType<T> = T extends any[] ? OmitStringType<T[number]> : IsLiteralString<T>
type NonUndefined<T> = T extends undefined
? never
: T extends object
? { [K in keyof T]: NonUndefined<T[K]> }
: T

export const APP_NAME = "Follow"
}
Expand Down
1 change: 1 addition & 0 deletions packages/types/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"name": "@follow/types",
"version": "0.0.1",
"sideEffects": false,
"exports": {
"./react": "./react-global.d.ts",
"./global": "./global.d.ts"
Expand Down
5 changes: 4 additions & 1 deletion packages/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"url": "https://github.com/RSSNext/follow",
"type": "git"
},
"sideEffects": false,
"exports": {
".": {
"require": "./src/index.ts",
Expand All @@ -26,10 +27,12 @@
},
"dependencies": {
"@follow/shared": "workspace:*",
"@follow/types": "workspace:*",
"clsx": "2.1.1",
"framer-motion": "11.11.9",
"lodash-es": "4.17.21",
"tailwind-merge": "2.5.4",
"tldts": "6.1.51"
"tldts": "6.1.51",
"uniqolor": "1.1.1"
}
}
59 changes: 59 additions & 0 deletions packages/utils/src/color.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import uniqolor from "uniqolor"

const getRandomColor = (lightness: [number, number], saturation: [number, number], hue: number) => {
const satAccent = Math.floor(Math.random() * (saturation[1] - saturation[0] + 1) + saturation[0])
const lightAccent = Math.floor(Math.random() * (lightness[1] - lightness[0] + 1) + lightness[0])
Expand Down Expand Up @@ -52,3 +54,60 @@ export const getColorScheme = (hue?: number, memo?: boolean) => {
}
return result
}

const lerp = (a: number, b: number, t: number) => a + (b - a) * t

export const hexToRgb = (hex: string) => {
const bigint = Number.parseInt(hex.slice(1), 16)
return [(bigint >> 16) & 255, (bigint >> 8) & 255, bigint & 255]
}

export const rgbToHex = (r: number, g: number, b: number) => {
return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`
}

const adjustColorTowardsTarget = (color: string, targetColor: string, factor: number) => {
const [r1, g1, b1] = hexToRgb(color)
const [r2, g2, b2] = hexToRgb(targetColor)

const r = Math.round(lerp(r1, r2, factor))
const g = Math.round(lerp(g1, g2, factor))
const b = Math.round(lerp(b1, b2, factor))

return rgbToHex(r, g, b)
}

export const getBackgroundGradient = (seed?: Nullable<string>) => {
const nextSeed = seed ?? Math.random().toString(36).slice(7)

const bgAccent = uniqolor(nextSeed, {
saturation: [30, 35],
lightness: [60, 70],
}).color

const bgAccentLight = uniqolor(nextSeed, {
saturation: [30, 35],
lightness: [80, 90],
}).color

const bgAccentUltraLight = uniqolor(nextSeed, {
saturation: [30, 35],
lightness: [95, 96],
}).color

const targetColor = "#FF5C02"
const factor = 0.3 // Adjust this value to control how close the color gets to the target color

const adjustedAccent = adjustColorTowardsTarget(bgAccent, targetColor, factor)
const adjustedAccentLight = adjustColorTowardsTarget(bgAccentLight, targetColor, factor)
const adjustedAccentUltraLight = adjustColorTowardsTarget(bgAccentUltraLight, targetColor, factor)

return [
adjustedAccent,
adjustedAccentLight,
adjustedAccentUltraLight,
bgAccent,
bgAccentLight,
bgAccentUltraLight,
]
}
1 change: 1 addition & 0 deletions packages/utils/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"compilerOptions": {
"baseUrl": ".",
"declaration": true,
"types": ["@follow/types/global"],
"paths": {
"@follow/utils/*": ["./src/*"]
}
Expand Down
Loading

0 comments on commit 86be1a2

Please sign in to comment.