Merge pull request #3984 from RSSNext/sync/main-to-dev-20250623
Sync main branch to dev branch
This commit is contained in:
commit
c474c9c805
|
|
@ -1,7 +1,5 @@
|
|||
import { name } from "../../package.json"
|
||||
|
||||
export const defineGlobalConstants = () => {
|
||||
Object.assign(globalThis, {
|
||||
APP_NAME: name,
|
||||
APP_NAME: "Folo",
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import type { Document } from "linkedom"
|
||||
import xss from "xss"
|
||||
|
||||
export function buildSeoMetaTags(
|
||||
|
|
|
|||
|
|
@ -7,17 +7,16 @@ export const OGCanvas = ({ children, seed }: { children: React.ReactNode; seed:
|
|||
return (
|
||||
<div
|
||||
style={{
|
||||
background: `linear-gradient(135deg, #000000 0%, #1a1a1a 50%, #2d2d2d 100%)`,
|
||||
background: "#0a0f1a",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
textAlign: "center",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
position: "relative",
|
||||
fontFamily: "SN Pro",
|
||||
color: "#e6edf3",
|
||||
}}
|
||||
>
|
||||
{/* Subtle background pattern */}
|
||||
{/* Background Grid Pattern */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
|
|
@ -25,12 +24,14 @@ export const OGCanvas = ({ children, seed }: { children: React.ReactNode; seed:
|
|||
left: 0,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
background: `radial-gradient(circle at 20% 80%, ${bgAccent}15 0%, transparent 50%), radial-gradient(circle at 80% 20%, ${bgAccentLight}10 0%, transparent 50%)`,
|
||||
opacity: 0.6,
|
||||
background: `
|
||||
linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px)
|
||||
`,
|
||||
backgroundSize: "40px 40px",
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Grid pattern overlay */}
|
||||
{/* Background Glows */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
|
|
@ -38,65 +39,83 @@ export const OGCanvas = ({ children, seed }: { children: React.ReactNode; seed:
|
|||
left: 0,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
backgroundImage: "radial-gradient(circle, #ffffff08 1px, transparent 1px)",
|
||||
backgroundSize: "32px 32px",
|
||||
opacity: 0.3,
|
||||
background: `
|
||||
radial-gradient(circle at 15% 20%, ${bgAccent}20 0%, transparent 40%),
|
||||
radial-gradient(circle at 85% 80%, ${bgAccentLight}15 0%, transparent 40%)
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Main content card */}
|
||||
{/* Main layout container */}
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
width: "calc(100% - 100px)",
|
||||
height: "calc(100% - 100px)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
background: "linear-gradient(145deg, #ffffff 0%, #fafafa 100%)",
|
||||
borderRadius: 32,
|
||||
border: "1px solid #e5e5e5",
|
||||
boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25), 0 0 0 1px rgba(255, 255, 255, 0.1)",
|
||||
gap: "3rem",
|
||||
padding: "3rem",
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
padding: "40px 60px",
|
||||
gap: 40,
|
||||
}}
|
||||
>
|
||||
{/* Brand mark */}
|
||||
{/* Header */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
right: 32,
|
||||
bottom: 32,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
gap: "1rem",
|
||||
opacity: 0.8,
|
||||
alignItems: "center",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<FollowIcon />
|
||||
<span
|
||||
style={{
|
||||
fontSize: "2rem",
|
||||
color: "#FF5C02",
|
||||
fontWeight: 700,
|
||||
letterSpacing: "-0.02em",
|
||||
}}
|
||||
>
|
||||
Folo
|
||||
</span>
|
||||
{/* Follow Logo */}
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 16 }}>
|
||||
<FollowIcon />
|
||||
<span
|
||||
style={{ fontSize: 28, fontWeight: "bold", color: "white", letterSpacing: "0.05em" }}
|
||||
>
|
||||
Folo
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* AI RSS */}
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 12 }}>
|
||||
<span style={{ fontSize: 20, color: "#afb8c1" }}>Follow everything in one place</span>
|
||||
<RSSIcon color={bgAccent || "#e6edf3"} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{children}
|
||||
{/* Content */}
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function RSSIcon({ color }: { color: string }) {
|
||||
return (
|
||||
<svg width="40" height="40" viewBox="0 0 24 24" fill="none">
|
||||
<path
|
||||
d="M8.24 2.546c-2.117.11-3.311.502-4.229 1.387-.813.783-1.204 1.745-1.401 3.439-.062.542-.07 1.047-.07 4.628 0 3.581.008 4.086.07 4.628.197 1.694.588 2.656 1.401 3.439.804.775 1.708 1.131 3.361 1.323.542.062 1.047.07 4.628.07 3.581 0 4.086-.008 4.628-.07 1.653-.192 2.557-.548 3.361-1.323.813-.783 1.204-1.745 1.401-3.439.062-.542.07-1.047.07-4.628 0-3.581-.008-4.086-.07-4.628-.197-1.694-.588-2.656-1.401-3.439-.796-.768-1.702-1.128-3.32-1.319-.49-.058-1.094-.068-4.369-.074-2.09-.004-3.917-.001-4.06.006m1.1 4.494c2.476.272 4.679 1.553 6.087 3.54 1.06 1.495 1.627 3.369 1.565 5.167-.015.43-.033.544-.11.704a1.06 1.06 0 0 1-.618.53c-.252.075-.328.074-.579-.007a.976.976 0 0 1-.605-.542c-.079-.184-.09-.272-.084-.692.024-1.916-.614-3.527-1.913-4.822-1.306-1.302-2.917-1.941-4.823-1.913-.421.006-.506-.004-.69-.084-.373-.162-.582-.485-.582-.901 0-.489.302-.864.792-.983.181-.044 1.152-.042 1.56.003m-.411 3.543a5.77 5.77 0 0 1 2.25.93 6.866 6.866 0 0 1 1.308 1.308c.611.86.984 1.979 1.002 3.003.005.301-.01.434-.063.556-.154.353-.552.619-.926.619-.373 0-.777-.269-.921-.615-.036-.086-.081-.356-.1-.6-.074-.942-.371-1.596-1.019-2.244-.648-.648-1.302-.945-2.244-1.019-.494-.039-.691-.104-.891-.293a.984.984 0 0 1-.231-1.128c.148-.316.391-.505.766-.594.119-.028.671.012 1.069.077m.172 3.552c.313.143.622.45.766.761.098.21.113.293.113.604 0 .31-.015.393-.112.6a1.698 1.698 0 0 1-.764.767c-.21.098-.293.113-.604.113-.31 0-.393-.015-.6-.112a1.698 1.698 0 0 1-.767-.764c-.098-.21-.113-.293-.113-.604 0-.32.014-.389.124-.62.273-.573.795-.893 1.417-.867.223.009.362.041.54.122"
|
||||
fill={color}
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function FollowIcon() {
|
||||
return (
|
||||
<svg width="48" height="48" viewBox="0 0 91 89" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="91" height="89" rx="26" fill="#FF5C02" />
|
||||
<svg width="48" height="48" viewBox="0 0 91 89" fill="none">
|
||||
<rect width="91" height="89" rx="20" fill="#FF5C02" />
|
||||
<path
|
||||
d="M69.0242 22.0703H37.1962C33.3473 22.0703 30.2272 25.1785 30.2272 29.0126C30.2272 32.8468 33.3473 35.955 37.1962 35.955H69.0242C72.8731 35.955 75.9933 32.8468 75.9933 29.0126C75.9933 25.1785 72.8731 22.0703 69.0242 22.0703Z"
|
||||
fill="white"
|
||||
|
|
@ -140,7 +159,7 @@ export const OGAvatar: React.FC<{ base64?: Nullable<string>; title: string }> =
|
|||
base64,
|
||||
title,
|
||||
}) => {
|
||||
const [, , , bgAccent, bgAccentLight, bgAccentUltraLight] = getBackgroundGradient(title)
|
||||
const [, , , bgAccent, bgAccentLight] = getBackgroundGradient(title)
|
||||
return (
|
||||
<>
|
||||
{base64 ? (
|
||||
|
|
@ -155,12 +174,11 @@ export const OGAvatar: React.FC<{ base64?: Nullable<string>; title: string }> =
|
|||
<img
|
||||
src={base64}
|
||||
style={{
|
||||
width: 180,
|
||||
height: 180,
|
||||
width: 160,
|
||||
height: 160,
|
||||
borderRadius: "50%",
|
||||
border: "4px solid #ffffff",
|
||||
boxShadow:
|
||||
"0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)",
|
||||
border: `3px solid ${bgAccentLight}50`,
|
||||
boxShadow: `0 0 25px ${bgAccent}40`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -168,20 +186,20 @@ export const OGAvatar: React.FC<{ base64?: Nullable<string>; title: string }> =
|
|||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
width: 180,
|
||||
height: 180,
|
||||
width: 160,
|
||||
height: 160,
|
||||
borderRadius: "50%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
background: `linear-gradient(135deg, ${bgAccent} 0%, ${bgAccentLight} 50%, ${bgAccentUltraLight} 100%)`,
|
||||
border: "4px solid #ffffff",
|
||||
boxShadow: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)",
|
||||
background: `linear-gradient(135deg, ${bgAccent} 0%, ${bgAccentLight} 100%)`,
|
||||
border: `3px solid ${bgAccentLight}50`,
|
||||
boxShadow: `0 0 25px ${bgAccent}40`,
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 72,
|
||||
fontSize: 64,
|
||||
fontWeight: 700,
|
||||
color: "white",
|
||||
letterSpacing: "-0.02em",
|
||||
|
|
|
|||
|
|
@ -34,55 +34,56 @@ export const renderFeedOG = async (apiClient: ApiClient, feedId: string) => {
|
|||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexGrow: 1,
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
flexShrink: 0,
|
||||
width: "40%",
|
||||
textAlign: "center",
|
||||
gap: 15,
|
||||
padding: "0 60px",
|
||||
}}
|
||||
>
|
||||
<OGAvatar base64={imageBase64} title={title!} />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexGrow: 1,
|
||||
flexShrink: 1,
|
||||
width: "60%",
|
||||
flexDirection: "column",
|
||||
overflow: "hidden",
|
||||
textAlign: "left",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<h3
|
||||
<div
|
||||
style={{
|
||||
color: "#000000",
|
||||
fontSize: "3.5rem",
|
||||
whiteSpace: "nowrap",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
gap: 10,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</h3>
|
||||
{description && (
|
||||
<p
|
||||
<h3
|
||||
style={{
|
||||
fontSize: "1.8rem",
|
||||
height: "5.6rem",
|
||||
overflow: "hidden",
|
||||
lineClamp: 2,
|
||||
color: "#000000",
|
||||
color: "#e6edf3",
|
||||
fontSize: "3.2rem",
|
||||
fontWeight: 600,
|
||||
margin: 0,
|
||||
}}
|
||||
>
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{title}
|
||||
</h3>
|
||||
{description && (
|
||||
<p
|
||||
style={{
|
||||
fontSize: "1.8rem",
|
||||
color: "#8b949e",
|
||||
margin: 0,
|
||||
maxHeight: "5.4rem",
|
||||
lineHeight: 1.5,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<p
|
||||
style={{
|
||||
fontSize: "1.5rem",
|
||||
color: "#000000",
|
||||
color: "#afb8c1",
|
||||
fontWeight: 500,
|
||||
margin: 0,
|
||||
paddingTop: 10,
|
||||
}}
|
||||
>
|
||||
{formatNumber(feed.data.subscriptionCount || 0)} followers with{" "}
|
||||
|
|
|
|||
|
|
@ -37,55 +37,56 @@ export const renderListOG = async (apiClient: ApiClient, listId: string) => {
|
|||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexGrow: 1,
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
flexShrink: 0,
|
||||
width: "45%",
|
||||
textAlign: "center",
|
||||
gap: 15,
|
||||
padding: "0 60px",
|
||||
}}
|
||||
>
|
||||
<OGAvatar base64={imageBase64} title={title!} />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexGrow: 1,
|
||||
flexShrink: 1,
|
||||
width: "52%",
|
||||
flexDirection: "column",
|
||||
overflow: "hidden",
|
||||
textAlign: "left",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<h3
|
||||
<div
|
||||
style={{
|
||||
color: "#000000",
|
||||
fontSize: "3.5rem",
|
||||
whiteSpace: "nowrap",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
gap: 10,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</h3>
|
||||
{description && (
|
||||
<p
|
||||
<h3
|
||||
style={{
|
||||
fontSize: "1.8rem",
|
||||
height: "5.8rem",
|
||||
overflow: "hidden",
|
||||
lineClamp: 2,
|
||||
color: "#000000",
|
||||
color: "#e6edf3",
|
||||
fontSize: "3.2rem",
|
||||
fontWeight: 600,
|
||||
margin: 0,
|
||||
}}
|
||||
>
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{title}
|
||||
</h3>
|
||||
{description && (
|
||||
<p
|
||||
style={{
|
||||
fontSize: "1.8rem",
|
||||
color: "#8b949e",
|
||||
margin: 0,
|
||||
maxHeight: "5.4rem",
|
||||
lineHeight: 1.5,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<p
|
||||
style={{
|
||||
fontSize: "1.5rem",
|
||||
color: "#000000",
|
||||
color: "#afb8c1",
|
||||
fontWeight: 500,
|
||||
margin: 0,
|
||||
paddingTop: 10,
|
||||
}}
|
||||
>
|
||||
{numberFormatter.format(feed.data.subscriptionCount)} followers with{" "}
|
||||
|
|
|
|||
|
|
@ -27,52 +27,47 @@ export const renderUserOG = async (apiClient: ApiClient, id: string) => {
|
|||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexGrow: 1,
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
flexShrink: 0,
|
||||
width: "45%",
|
||||
|
||||
overflow: "hidden",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
gap: 25,
|
||||
}}
|
||||
>
|
||||
<OGAvatar base64={imageBase64} title={user.data.name!} />
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexGrow: 1,
|
||||
flexShrink: 1,
|
||||
width: "52%",
|
||||
flexDirection: "column",
|
||||
overflow: "hidden",
|
||||
textAlign: "left",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<h3
|
||||
<div
|
||||
style={{
|
||||
color: "#000000",
|
||||
fontSize: "3.5rem",
|
||||
whiteSpace: "nowrap",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
{user.data.name}
|
||||
</h3>
|
||||
{user.data.handle && (
|
||||
<p
|
||||
<h3
|
||||
style={{
|
||||
fontSize: "1.8rem",
|
||||
height: "5.8rem",
|
||||
overflow: "hidden",
|
||||
lineClamp: 2,
|
||||
color: "#000022",
|
||||
color: "#ffffff",
|
||||
fontSize: "4.5rem",
|
||||
fontWeight: 700,
|
||||
margin: 0,
|
||||
letterSpacing: "-0.02em",
|
||||
}}
|
||||
>
|
||||
@{user.data.handle}
|
||||
</p>
|
||||
)}
|
||||
{user.data.name}
|
||||
</h3>
|
||||
{user.data.handle && (
|
||||
<p
|
||||
style={{
|
||||
fontSize: "2.5rem",
|
||||
color: "#8b949e",
|
||||
margin: 0,
|
||||
marginTop: 12,
|
||||
}}
|
||||
>
|
||||
@{user.data.handle}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</OGCanvas>,
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue