fix: ssr server move to esm (#3994)
* chore: fix prettier error * refactor: migrate to ES modules and update global constants handling - Changed the global constants definition to use Object.assign for better clarity. - Replaced usage of `isDev` with `__DEV__` throughout the codebase for consistency. - Updated imports to use ES module syntax, including dynamic imports where necessary. - Removed the deprecated `env.ts` file and adjusted related logic in the build scripts. - Ensured compatibility with ES module format in various files, including Vite and API client configurations. Signed-off-by: Innei <tukon479@gmail.com> * refactor(api): migrate handler to ES module syntax - Updated the API handler to use ES module export syntax. - Removed commented-out configuration for Node.js runtime. Signed-off-by: Innei <tukon479@gmail.com> * feat(404): enhance 404 page with animations and improve accessibility - Replaced `motion` components with `m` shorthand for better readability. - Introduced animation controls for various elements on the 404 page to enhance user experience. - Updated the glitch text array for consistency. - Adjusted layout and styling for improved visual presentation. - Removed unused `framer-lazy-feature` file and updated `MotionProvider` to use `domMax` for performance optimization. Signed-off-by: Innei <tukon479@gmail.com> * feat(og): replace Folo text with SVG logo in OGCanvas component - Updated the OGCanvas component to replace the static "Folo" text with a new LogoText SVG component for improved branding. - Added the LogoText function that defines the SVG structure for the logo. Signed-off-by: Innei <tukon479@gmail.com> * refactor(tsdown): update font imports to use dynamic loading - Modified font imports in `tsdown.config.ts` to utilize dynamic loading with `then` for improved performance and error handling. - Introduced a no-operation function to handle the promise resolution of font imports. Signed-off-by: Innei <tukon479@gmail.com> * refactor(404): replace Jotai provider with RootProviders for improved context management - Updated the 404 component to use `RootProviders` instead of the Jotai store provider for better context handling. - Simplified the component structure while maintaining functionality. Signed-off-by: Innei <tukon479@gmail.com> --------- Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
parent
93574a7deb
commit
db53bdb468
|
|
@ -1,10 +1,8 @@
|
|||
const { createApp } = require("../dist/server/index.js")
|
||||
// @ts-ignore
|
||||
// eslint-disable-next-line antfu/no-import-dist
|
||||
import { createApp } from "../dist/server/index.js"
|
||||
|
||||
// export const config = {
|
||||
// runtime: "nodejs", // this is a pre-requisite
|
||||
// }
|
||||
|
||||
module.exports = async function handler(req: any, res: any) {
|
||||
export default async function handler(req: any, res: any) {
|
||||
const app = await createApp()
|
||||
await app.ready()
|
||||
app.server.emit("request", req, res)
|
||||
|
|
|
|||
|
|
@ -1,30 +1,82 @@
|
|||
import { Header } from "@client/components/layout/header"
|
||||
import { openInFollowApp } from "@client/lib/helper"
|
||||
import { jotaiStore } from "@client/lib/store"
|
||||
import { RootProviders } from "@client/providers/root-providers"
|
||||
import { MemoedDangerousHTMLStyle } from "@follow/components/common/MemoedDangerousHTMLStyle.jsx"
|
||||
import { PoweredByFooter } from "@follow/components/common/PoweredByFooter.jsx"
|
||||
import { Button } from "@follow/components/ui/button/index.jsx"
|
||||
import { useSyncThemeWebApp, useTitle } from "@follow/hooks"
|
||||
import { Provider } from "jotai"
|
||||
import { m as motion } from "motion/react"
|
||||
import { m, useAnimationControls } from "motion/react"
|
||||
import { Fragment, useEffect, useState } from "react"
|
||||
|
||||
const NotFoundContent = () => {
|
||||
const [isVisible, setIsVisible] = useState(false)
|
||||
const [glitchText, setGlitchText] = useState("404")
|
||||
const [isGlitching, setIsGlitching] = useState(false)
|
||||
|
||||
// Animation controls
|
||||
const iconControls = useAnimationControls()
|
||||
const messageControls = useAnimationControls()
|
||||
const titleControls = useAnimationControls()
|
||||
const descriptionControls = useAnimationControls()
|
||||
const buttonsControls = useAnimationControls()
|
||||
const helpControls = useAnimationControls()
|
||||
|
||||
useTitle("404 - Page Not Found")
|
||||
useSyncThemeWebApp()
|
||||
|
||||
useEffect(() => {
|
||||
setIsVisible(true)
|
||||
}, [])
|
||||
// Start all animations in parallel with their respective delays
|
||||
iconControls.start({
|
||||
scale: 1,
|
||||
rotate: 0,
|
||||
transition: {
|
||||
duration: 0.8,
|
||||
type: "spring",
|
||||
stiffness: 100,
|
||||
delay: 0.2,
|
||||
},
|
||||
})
|
||||
|
||||
messageControls.start({
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: { duration: 0.6, delay: 0.4 },
|
||||
})
|
||||
|
||||
titleControls.start({
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: { duration: 0.5, delay: 0.6 },
|
||||
})
|
||||
|
||||
descriptionControls.start({
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: { duration: 0.5, delay: 0.8 },
|
||||
})
|
||||
|
||||
buttonsControls.start({
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
transition: { duration: 0.5, delay: 1 },
|
||||
})
|
||||
|
||||
helpControls.start({
|
||||
opacity: 1,
|
||||
transition: { duration: 0.5, delay: 1.2 },
|
||||
})
|
||||
}, [
|
||||
iconControls,
|
||||
messageControls,
|
||||
titleControls,
|
||||
descriptionControls,
|
||||
buttonsControls,
|
||||
helpControls,
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
if (!isGlitching) return
|
||||
|
||||
const glitchTexts = ["404", "40₄", "4Ø4", "404", "4◯4", "4○4", "4𝟘4"]
|
||||
const glitchTexts = ["404", "40₄", "4Ø4", "404", "4◯4", "4○4", "4𝟘4"]
|
||||
|
||||
const glitchInterval = setInterval(() => {
|
||||
const randomText = glitchTexts[Math.floor(Math.random() * glitchTexts.length)]
|
||||
|
|
@ -95,21 +147,15 @@ const NotFoundContent = () => {
|
|||
}`}
|
||||
</MemoedDangerousHTMLStyle>
|
||||
<Header />
|
||||
<main className="relative mx-auto flex w-full max-w-[var(--container-max-width)] flex-1 flex-col items-center justify-center pt-20">
|
||||
<main className="relative mx-auto my-8 flex w-full max-w-[var(--container-max-width)] flex-1 flex-col items-center justify-center pt-20">
|
||||
<Fragment>
|
||||
{/* 404 Icon with animations */}
|
||||
<motion.div
|
||||
<m.div
|
||||
className="mb-8 flex items-center justify-center"
|
||||
initial={{ scale: 0, rotate: -180 }}
|
||||
animate={{ scale: isVisible ? 1 : 0, rotate: isVisible ? 0 : -180 }}
|
||||
transition={{
|
||||
duration: 0.8,
|
||||
type: "spring",
|
||||
stiffness: 100,
|
||||
delay: 0.2,
|
||||
}}
|
||||
animate={iconControls}
|
||||
>
|
||||
<motion.div
|
||||
<m.div
|
||||
className="float-animation pulse-glow-animation flex size-32 cursor-pointer items-center justify-center rounded-full bg-zinc-100 dark:bg-zinc-800"
|
||||
whileHover={{
|
||||
scale: 1.1,
|
||||
|
|
@ -131,7 +177,7 @@ const NotFoundContent = () => {
|
|||
setIsGlitching(false)
|
||||
}}
|
||||
>
|
||||
<motion.span
|
||||
<m.span
|
||||
className={`select-none text-4xl font-bold text-zinc-400 dark:text-zinc-600 ${isGlitching ? "glitch-animation" : ""}`}
|
||||
key={glitchText}
|
||||
initial={{ opacity: 0 }}
|
||||
|
|
@ -139,51 +185,47 @@ const NotFoundContent = () => {
|
|||
transition={{ duration: 0.1 }}
|
||||
>
|
||||
{glitchText}
|
||||
</motion.span>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</m.span>
|
||||
</m.div>
|
||||
</m.div>
|
||||
{/* Error Message with stagger animation */}
|
||||
<motion.div
|
||||
<m.div
|
||||
className="mb-8 flex flex-col items-center text-center"
|
||||
initial={{ opacity: 0, y: 50 }}
|
||||
animate={{ opacity: isVisible ? 1 : 0, y: isVisible ? 0 : 50 }}
|
||||
transition={{ duration: 0.6, delay: 0.4 }}
|
||||
animate={messageControls}
|
||||
>
|
||||
<motion.h1
|
||||
<m.h1
|
||||
className="mb-4 text-3xl font-bold text-zinc-900 dark:text-zinc-100"
|
||||
initial={{ opacity: 0, x: -30 }}
|
||||
animate={{ opacity: isVisible ? 1 : 0, x: isVisible ? 0 : -30 }}
|
||||
transition={{ duration: 0.5, delay: 0.6 }}
|
||||
animate={titleControls}
|
||||
>
|
||||
Page Not Found
|
||||
</motion.h1>
|
||||
<motion.p
|
||||
className="max-w-md text-lg text-zinc-500 dark:text-zinc-400"
|
||||
</m.h1>
|
||||
<m.p
|
||||
className="max-w-md text-base text-zinc-500 dark:text-zinc-400"
|
||||
initial={{ opacity: 0, x: 30 }}
|
||||
animate={{ opacity: isVisible ? 1 : 0, x: isVisible ? 0 : 30 }}
|
||||
transition={{ duration: 0.5, delay: 0.8 }}
|
||||
animate={descriptionControls}
|
||||
>
|
||||
Sorry, the page you are looking for doesn't exist or has been moved. Please check the
|
||||
URL or return to the homepage to continue browsing.
|
||||
</motion.p>
|
||||
</motion.div>
|
||||
</m.p>
|
||||
</m.div>
|
||||
{/* Action Buttons with hover effects */}
|
||||
<motion.div
|
||||
<m.div
|
||||
className="flex flex-col items-center gap-4 sm:flex-row"
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{ opacity: isVisible ? 1 : 0, scale: isVisible ? 1 : 0.8 }}
|
||||
transition={{ duration: 0.5, delay: 1 }}
|
||||
animate={buttonsControls}
|
||||
>
|
||||
<motion.div whileHover={{ scale: 1.05, y: -2 }} whileTap={{ scale: 0.95 }}>
|
||||
<m.div whileHover={{ scale: 1.05, y: -2 }} whileTap={{ scale: 0.95 }}>
|
||||
<Button
|
||||
onClick={handleGoHome}
|
||||
buttonClassName="px-6 py-2 transition-all duration-200"
|
||||
>
|
||||
Go Home
|
||||
</Button>
|
||||
</motion.div>
|
||||
</m.div>
|
||||
|
||||
<motion.div whileHover={{ scale: 1.05, y: -2 }} whileTap={{ scale: 0.95 }}>
|
||||
<m.div whileHover={{ scale: 1.05, y: -2 }} whileTap={{ scale: 0.95 }}>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={handleOpenInApp}
|
||||
|
|
@ -191,18 +233,13 @@ const NotFoundContent = () => {
|
|||
>
|
||||
Open {APP_NAME}
|
||||
</Button>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</m.div>
|
||||
</m.div>
|
||||
{/* Additional Help with fade in */}
|
||||
<motion.div
|
||||
className="mt-12 text-center"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: isVisible ? 1 : 0 }}
|
||||
transition={{ duration: 0.5, delay: 1.2 }}
|
||||
>
|
||||
<m.div className="mt-12 text-center" initial={{ opacity: 0 }} animate={helpControls}>
|
||||
<p className="text-sm text-zinc-400 dark:text-zinc-500">
|
||||
If you believe this is an error, please submit a issue on{" "}
|
||||
<motion.a
|
||||
<m.a
|
||||
className="text-accent transition-colors duration-200"
|
||||
href="https://github.com/rssnext/folo/issues"
|
||||
target="_blank"
|
||||
|
|
@ -211,13 +248,13 @@ const NotFoundContent = () => {
|
|||
style={{ display: "inline-block" }}
|
||||
>
|
||||
GitHub
|
||||
</motion.a>
|
||||
</m.a>
|
||||
</p>
|
||||
</motion.div>
|
||||
</m.div>
|
||||
{/* Floating particles effect */}
|
||||
<div className="pointer-events-none absolute inset-0 overflow-hidden">
|
||||
{Array.from({ length: 6 }).map((_, i) => (
|
||||
<motion.div
|
||||
<m.div
|
||||
key={i}
|
||||
className="absolute size-1 rounded-full bg-zinc-300 opacity-30 dark:bg-zinc-600"
|
||||
initial={{
|
||||
|
|
@ -245,8 +282,8 @@ const NotFoundContent = () => {
|
|||
|
||||
export const NotFound = () => {
|
||||
return (
|
||||
<Provider store={jotaiStore}>
|
||||
<RootProviders>
|
||||
<NotFoundContent />
|
||||
</Provider>
|
||||
</RootProviders>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
export const defineGlobalConstants = () => {
|
||||
Object.assign(globalThis, {
|
||||
APP_NAME: "Folo",
|
||||
})
|
||||
|
||||
try {
|
||||
void __DEV__
|
||||
} catch {
|
||||
Object.assign(globalThis, {
|
||||
APP_NAME: "Folo",
|
||||
__DEV__: process.env.NODE_ENV === "development",
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
import "./global"
|
||||
import "./src/lib/load-env"
|
||||
|
||||
import os from "node:os"
|
||||
|
||||
import middie from "@fastify/middie"
|
||||
import { fastifyRequestContext } from "@fastify/request-context"
|
||||
import { env } from "@follow/shared/env.ssr"
|
||||
|
|
@ -8,16 +11,12 @@ import Fastify from "fastify"
|
|||
import { nanoid } from "nanoid"
|
||||
import { FetchError } from "ofetch"
|
||||
|
||||
import { isDev } from "~/lib/env"
|
||||
import { MetaError } from "~/meta-handler"
|
||||
import { staticRoute } from "~/router/static"
|
||||
|
||||
import { defineGlobalConstants } from "./global"
|
||||
import { globalRoute } from "./src/router/global"
|
||||
import { ogRoute } from "./src/router/og"
|
||||
|
||||
defineGlobalConstants()
|
||||
|
||||
const isVercel = process.env.VERCEL === "1"
|
||||
|
||||
declare module "@fastify/request-context" {
|
||||
|
|
@ -64,7 +63,7 @@ export const createApp = async () => {
|
|||
const finalHost = forwardedHost || host
|
||||
|
||||
const upstreamEnv = finalHost?.includes("dev") ? "dev" : "prod"
|
||||
if (!isDev) req.requestContext.set("upstreamEnv", upstreamEnv)
|
||||
if (!__DEV__) req.requestContext.set("upstreamEnv", upstreamEnv)
|
||||
if (upstreamEnv === "prod") {
|
||||
req.requestContext.set("upstreamOrigin", env.VITE_WEB_PROD_URL || env.VITE_WEB_URL)
|
||||
} else {
|
||||
|
|
@ -74,8 +73,8 @@ export const createApp = async () => {
|
|||
done()
|
||||
})
|
||||
|
||||
if (isDev) {
|
||||
const devVite = require("./src/lib/dev-vite")
|
||||
if (__DEV__) {
|
||||
const devVite = await import("./src/lib/dev-vite")
|
||||
await devVite.registerDevViteServer(app)
|
||||
}
|
||||
|
||||
|
|
@ -97,11 +96,11 @@ if (!isVercel) {
|
|||
}
|
||||
|
||||
function getIPAddress() {
|
||||
const interfaces = require("node:os").networkInterfaces()
|
||||
const interfaces = os.networkInterfaces()
|
||||
for (const devName in interfaces) {
|
||||
const iface = interfaces[devName]
|
||||
|
||||
for (const alias of iface) {
|
||||
for (const alias of iface || []) {
|
||||
if (alias.family === "IPv4" && alias.address !== "127.0.0.1" && !alias.internal)
|
||||
return alias.address
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"name": "@follow/ssr",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "cross-env NODE_ENV=production vite build && tsx scripts/prepare-vercel-build.ts && tsdown && tsx scripts/cleanup-vercel-build.ts",
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
import { rmSync, writeFileSync } from "node:fs"
|
||||
import { resolve } from "node:path"
|
||||
import { rmSync } from "node:fs"
|
||||
import { dirname, resolve } from "node:path"
|
||||
import { fileURLToPath } from "node:url"
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
rmSync(resolve(__dirname, "../.generated"), { recursive: true, force: true })
|
||||
// restore env file
|
||||
|
||||
writeFileSync(
|
||||
resolve(__dirname, "../src/lib/env.ts"),
|
||||
`export const isDev = process.env.NODE_ENV === "development"`,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import { mkdirSync } from "node:fs"
|
||||
import fs from "node:fs/promises"
|
||||
import path from "node:path"
|
||||
import path, { dirname } from "node:path"
|
||||
import { fileURLToPath } from "node:url"
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
mkdirSync(path.join(__dirname, "../.generated"), { recursive: true })
|
||||
|
||||
|
|
@ -12,21 +15,8 @@ async function generateIndexHtmlData() {
|
|||
)
|
||||
}
|
||||
|
||||
async function replaceEnvFile() {
|
||||
const envFile = await fs.readFile(path.join(__dirname, "../src/lib/env.ts"), "utf-8")
|
||||
|
||||
await fs.writeFile(
|
||||
path.join(__dirname, "../src/lib/env.ts"),
|
||||
// For tree shaking
|
||||
envFile.replace(
|
||||
`export const isDev = process.env.NODE_ENV === "development"`,
|
||||
`export const isDev = ${process.env.NODE_ENV === "development"}`,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
async function main() {
|
||||
await Promise.all([generateIndexHtmlData(), replaceEnvFile()])
|
||||
await generateIndexHtmlData()
|
||||
}
|
||||
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import { hc } from "hono/client"
|
|||
import { ofetch } from "ofetch"
|
||||
|
||||
import PKG from "../../../desktop/package.json"
|
||||
import { isDev } from "./env"
|
||||
|
||||
const getBaseURL = () => {
|
||||
const req = requestContext.get("req")!
|
||||
|
|
@ -34,7 +33,7 @@ export const createApiFetch = () => {
|
|||
credentials: "include",
|
||||
retry: false,
|
||||
onRequest(context) {
|
||||
if (isDev) console.info(`request: ${context.request}`)
|
||||
if (__DEV__) console.info(`request: ${context.request}`)
|
||||
|
||||
context.options.headers.set("User-Agent", `Folo External Server Api Client/${PKG.version}`)
|
||||
},
|
||||
|
|
@ -57,7 +56,7 @@ export const createApiClient = () => {
|
|||
headers() {
|
||||
return {
|
||||
"X-App-Version": PKG.version,
|
||||
"X-App-Dev": isDev ? "1" : "0",
|
||||
"X-App-Dev": __DEV__ ? "1" : "0",
|
||||
"User-Agent": `Folo External Server Api Client/${PKG.version}`,
|
||||
Cookie: authSessionToken ? `__Secure-better-auth.session_token=${authSessionToken}` : "",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
import { resolve } from "node:path"
|
||||
import { dirname, resolve } from "node:path"
|
||||
import { fileURLToPath } from "node:url"
|
||||
|
||||
import type { FastifyInstance } from "fastify"
|
||||
import type { ViteDevServer } from "vite"
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const root = resolve(__dirname, "../..")
|
||||
|
||||
let globalVite: ViteDevServer
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
export const isDev = process.env.NODE_ENV === "development"
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
import fs from "node:fs"
|
||||
import { createRequire } from "node:module"
|
||||
import path, { resolve } from "node:path"
|
||||
|
||||
const require = createRequire(import.meta.url)
|
||||
|
||||
const weights = [
|
||||
{
|
||||
name: "Thin",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { readFileSync } from "node:fs"
|
||||
import path, { resolve } from "node:path"
|
||||
import path, { dirname, resolve } from "node:path"
|
||||
import { fileURLToPath } from "node:url"
|
||||
|
||||
import { env } from "@follow/shared/env.ssr"
|
||||
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"
|
||||
|
|
@ -8,7 +9,6 @@ import { parseHTML } from "linkedom"
|
|||
import { FetchError } from "ofetch"
|
||||
import xss from "xss"
|
||||
|
||||
import { isDev } from "~/lib/env"
|
||||
import { NotFoundError } from "~/lib/not-found"
|
||||
import { buildSeoMetaTags } from "~/lib/seo"
|
||||
|
||||
|
|
@ -17,10 +17,11 @@ import { injectMetaHandler, MetaError } from "../meta-handler"
|
|||
const devHandler = (app: FastifyInstance) => {
|
||||
app.get("*", async (req, reply) => {
|
||||
const url = req.originalUrl
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const root = resolve(__dirname, "../..")
|
||||
|
||||
const vite = require("../lib/dev-vite").getViteServer()
|
||||
const vite = await import("../lib/dev-vite").then((m) => m.getViteServer())
|
||||
try {
|
||||
let template = readFileSync(path.resolve(root, vite.config.root, "index.html"), "utf-8")
|
||||
template = await vite.transformIndexHtml(url, template)
|
||||
|
|
@ -30,14 +31,15 @@ const devHandler = (app: FastifyInstance) => {
|
|||
reply.type("text/html")
|
||||
reply.send(document.toString())
|
||||
} catch (e) {
|
||||
vite.ssrFixStacktrace(e)
|
||||
vite.ssrFixStacktrace(e as Error)
|
||||
reply.code(500).send(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
const prodHandler = (app: FastifyInstance) => {
|
||||
app.get("*", async (req, reply) => {
|
||||
const template = require("../../.generated/index.template").default
|
||||
// @ts-expect-error
|
||||
const template = await import("../../.generated/index.template").then((m) => m.default)
|
||||
const { document } = parseHTML(template)
|
||||
await safeInjectMetaToTemplate(document, req, reply)
|
||||
|
||||
|
|
@ -91,7 +93,7 @@ injectEnv({"VITE_API_URL":"${apiUrl}","VITE_EXTERNAL_API_URL":"${apiUrl}","VITE_
|
|||
)
|
||||
})
|
||||
}
|
||||
export const globalRoute = isDev ? devHandler : prodHandler
|
||||
export const globalRoute = __DEV__ ? devHandler : prodHandler
|
||||
|
||||
async function safeInjectMetaToTemplate(
|
||||
document: Document,
|
||||
|
|
|
|||
|
|
@ -69,11 +69,7 @@ export const OGCanvas = ({ children, seed }: { children: React.ReactNode; seed:
|
|||
{/* Follow Logo */}
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 16 }}>
|
||||
<FollowIcon />
|
||||
<span
|
||||
style={{ fontSize: 28, fontWeight: "bold", color: "white", letterSpacing: "0.05em" }}
|
||||
>
|
||||
Folo
|
||||
</span>
|
||||
<LogoText />
|
||||
</div>
|
||||
|
||||
{/* AI RSS */}
|
||||
|
|
@ -132,6 +128,35 @@ function FollowIcon() {
|
|||
)
|
||||
}
|
||||
|
||||
function LogoText() {
|
||||
return (
|
||||
<svg
|
||||
// width="115"
|
||||
height="30"
|
||||
viewBox="0 0 115 50"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M97.4813 49.2552C87.5432 49.2552 80.678 42.0631 80.678 31.9288C80.678 21.6637 87.4778 14.4062 97.4813 14.4062C107.55 14.4062 114.35 21.6637 114.35 31.9288C114.35 42.0631 107.485 49.2552 97.4813 49.2552ZM97.4813 42.1939C102.843 42.1939 106.112 37.944 106.112 31.8634C106.112 25.7174 102.843 21.4676 97.4813 21.4676C92.1199 21.4676 88.9816 25.7174 88.9816 31.8634C88.9816 37.944 92.1199 42.1939 97.4813 42.1939Z"
|
||||
fill="#fff"
|
||||
/>
|
||||
<path
|
||||
d="M72.7289 48.6667C70.1136 48.6667 68.6752 46.9668 68.6752 44.0899V5.38342C68.6752 2.50658 70.1136 0.806641 72.7289 0.806641C75.3442 0.806641 76.7826 2.50658 76.7826 5.38342V44.0899C76.7826 46.9668 75.4096 48.6667 72.7289 48.6667Z"
|
||||
fill="#fff"
|
||||
/>
|
||||
<path
|
||||
d="M47.8314 49.2552C37.8932 49.2552 31.0281 42.0631 31.0281 31.9288C31.0281 21.6637 37.8279 14.4062 47.8314 14.4062C57.9003 14.4062 64.7001 21.6637 64.7001 31.9288C64.7001 42.0631 57.8349 49.2552 47.8314 49.2552ZM47.8314 42.1939C53.1928 42.1939 56.4619 37.944 56.4619 31.8634C56.4619 25.7174 53.1928 21.4676 47.8314 21.4676C42.47 21.4676 39.3317 25.7174 39.3317 31.8634C39.3317 37.944 42.47 42.1939 47.8314 42.1939Z"
|
||||
fill="#fff"
|
||||
/>
|
||||
<path
|
||||
d="M5.10235 48.6669C2.42166 48.6669 0.852478 46.967 0.852478 43.9594V7.21438C0.852478 4.20678 2.55243 2.50684 5.62541 2.50684H26.1555C28.967 2.50684 30.5362 3.87987 30.5362 6.23365C30.5362 8.58742 28.967 9.89507 26.1555 9.89507H9.35221V20.9447H24.7825C27.594 20.9447 29.1631 22.187 29.1631 24.5408C29.1631 26.9599 27.594 28.2022 24.7825 28.2022H9.35221V43.9594C9.35221 46.967 7.84842 48.6669 5.10235 48.6669Z"
|
||||
fill="#fff"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getImageBase64(image: string | null | undefined) {
|
||||
if (!image) {
|
||||
return null
|
||||
|
|
|
|||
|
|
@ -9,12 +9,14 @@ export default defineConfig({
|
|||
outDir: "dist/server",
|
||||
|
||||
clean: true,
|
||||
format: ["cjs"],
|
||||
format: ["esm"],
|
||||
external: ["lightningcss", "vite"],
|
||||
treeshake: true,
|
||||
|
||||
define: {
|
||||
__DEV__: JSON.stringify(process.env.NODE_ENV === "development"),
|
||||
},
|
||||
|
||||
hooks(hooks) {
|
||||
hooks.hook("build:done", async () => {
|
||||
if (process.env.VERCEL !== "1") return
|
||||
|
|
@ -24,10 +26,11 @@ export default defineConfig({
|
|||
|
||||
try {
|
||||
const insertCode = `try {
|
||||
require.resolve("@fontsource/sn-pro")
|
||||
require.resolve('kose-font')
|
||||
require.resolve('kose-font/fonts/KosefontP-JP.ttf')
|
||||
require.resolve('kose-font/fonts/Kosefont-JP.ttf')
|
||||
const noop = () => {}
|
||||
import("@fontsource/sn-pro").then(noop)
|
||||
import('kose-font').then(noop)
|
||||
import('kose-font/fonts/KosefontP-JP.ttf').then(noop)
|
||||
import('kose-font/fonts/Kosefont-JP.ttf').then(noop)
|
||||
${(() => {
|
||||
const require = createRequire(import.meta.url)
|
||||
const fontDepsPath = require.resolve("@fontsource/sn-pro")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { resolve } from "node:path"
|
||||
import { dirname, resolve } from "node:path"
|
||||
import { fileURLToPath } from "node:url"
|
||||
|
||||
import react from "@vitejs/plugin-react"
|
||||
import { codeInspectorPlugin } from "code-inspector-plugin"
|
||||
|
|
@ -13,6 +14,8 @@ const routeBuilderPluginV2 = await tsImport(
|
|||
import.meta.url,
|
||||
).then((m) => m.default)
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
export default defineConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import { LazyMotion, MotionConfig } from "motion/react"
|
||||
import { domMax, LazyMotion, MotionConfig } from "motion/react"
|
||||
|
||||
const loadFeatures = () => import("../framer-lazy-feature").then((res) => res.default)
|
||||
export const MotionProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
return (
|
||||
<LazyMotion features={loadFeatures} strict key="framer">
|
||||
<LazyMotion features={domMax} strict key="framer">
|
||||
<MotionConfig
|
||||
transition={{
|
||||
type: "tween",
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
export { domMax as default } from "motion/react"
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"name": "@follow/constants",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"sideEffects": false,
|
||||
"exports": {
|
||||
|
|
|
|||
Loading…
Reference in New Issue