Skip to content

Commit

Permalink
Merge pull request #83 from AElfProject/feature/next-export-optimize-…
Browse files Browse the repository at this point in the history
…images

feat: build time export of images
  • Loading branch information
AbigailDeng authored Aug 30, 2024
2 parents 33f2b9d + e23d7cd commit 97e519c
Show file tree
Hide file tree
Showing 14 changed files with 795 additions and 86 deletions.
16 changes: 14 additions & 2 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { cn, getConfigContent, getMenu } from "@/lib/utils";
import { Poppins as FontSans } from "next/font/google";
import { Footer } from "@/components/footer";
import Header from "@/components/Header";
import { Logo } from "@/components/logo";
import { Suspense } from "react";
import Loading from "./loading";
import { getNodeToken, NodesItem } from "../services/larkServices";
Expand Down Expand Up @@ -44,9 +45,20 @@ export default async function RootLayout({
disableTransitionOnChange
>
<AntdRegistry>
<Header menu={menu} baseConfig={configObj} />
<Header
menu={menu}
baseConfig={configObj}
logo={<Logo baseConfig={configObj} />}
drawerLogo={
<Logo baseConfig={configObj} className="w-[107px] max-w-fit" />
}
/>
<Suspense fallback={<Loading />}>{children}</Suspense>
<Footer baseConfig={configObj} footerData={footerData} />
<Footer
baseConfig={configObj}
footerData={footerData}
logo={<Logo baseConfig={configObj} />}
/>
</AntdRegistry>
</ThemeProvider>
</body>
Expand Down
35 changes: 9 additions & 26 deletions components/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import type { MenuProps } from "antd";
import { Drawer, Menu, theme as antdTheme, ConfigProvider } from "antd";
import { NodesData, NodesItem } from "../../services/larkServices";
import { useEffect, useState } from "react";
import { useEffect, useState, ReactNode } from "react";
import Link from "next/link";
import { useParams } from "next/navigation";
import {
Expand All @@ -26,16 +26,18 @@ import { Skeleton } from "../ui/skeleton";
interface Props {
menu: NodesData;
baseConfig: { [key: string]: any };
logo: ReactNode;
drawerLogo: ReactNode;
}
type MenuItem = Required<MenuProps>["items"][number];

export default function Header({ menu, baseConfig }: Props) {
export default function Header({ menu, baseConfig, logo, drawerLogo }: Props) {
const params = useParams();
const { lastItemId: id } = findPathByTitles(menu, params.id as string[]);
let temp: any = {};
temp.items = findTopLevelItems(menu, id as string) as NodesItem[];
const items = menu.items;
const menuItems: MenuItem[] = items.map(ele => {
const menuItems: MenuItem[] = items.map((ele) => {
const titles = findTitlesById(menu, ele.node_token);
const url = titles?.join("/");
let obj: any = {};
Expand All @@ -53,7 +55,7 @@ export default function Header({ menu, baseConfig }: Props) {
useEffect(() => {
setCurrent(temp.items && temp.items[0]?.node_token);
}, [id]);
const onClick: MenuProps["onClick"] = e => {
const onClick: MenuProps["onClick"] = (e) => {
setCurrent(e.key);
};
const [drawerOpen, setDrawerOpen] = useState(false);
Expand All @@ -75,7 +77,7 @@ export default function Header({ menu, baseConfig }: Props) {
);
const homeDrawerContent = (
<div className="home-drawer-content">
{menu.items.map(item => {
{menu.items.map((item) => {
const titles = findTitlesById(menu, item.node_token);
const url = titles?.join("/");
return (
Expand Down Expand Up @@ -133,17 +135,7 @@ export default function Header({ menu, baseConfig }: Props) {

<Drawer
className="header-drawer-container"
title={
<CustomImage
src={getThemeConfig(theme, [
baseConfig.logoLight,
baseConfig.logoDark,
])}
width={115}
height={32}
alt="logo"
></CustomImage>
}
title={drawerLogo}
closeIcon={false}
extra={
<span className="flex justify-between">
Expand All @@ -165,16 +157,7 @@ export default function Header({ menu, baseConfig }: Props) {
{showHome ? homeDrawerContent : drawerContent}
</Drawer>
<Link href="/" className="mr-8 flex">
<CustomImage
src={getThemeConfig(theme, [
baseConfig.logoLight,
baseConfig.logoDark,
])}
width={115}
height={32}
className="w-[107px] max-w-fit"
alt="logo"
></CustomImage>
{logo}
</Link>
<div className="hidden lg:flex w-full items-center">
<Menu
Expand Down
11 changes: 1 addition & 10 deletions components/blocks/image.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Item } from "./common";
import { fetcher } from "../../lib/api";
import CustomImage from "../customImage";
import { getLink } from "@/services/get-link";

export interface Image extends Item {
block_type: 27;
Expand All @@ -12,15 +12,6 @@ export interface Image extends Item {
};
}

export async function getLink(token: string) {
const { data } = await fetcher(
`https://open.larksuite.com/open-apis/drive/v1/medias/batch_get_tmp_download_url?file_tokens=${token}`,
{ tags: [token] }
);

return data.tmp_download_urls?.[0]?.tmp_download_url;
}

export async function Image(props: Image) {
const src = await getLink(props.image.token);

Expand Down
12 changes: 2 additions & 10 deletions components/customImage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"use client";
import Image from "next/image";
import Image from "next-export-optimize-images/remote-image";
import type { ImageLoader } from "next/image";

interface ImageProps {
Expand All @@ -20,12 +19,5 @@ interface ImageProps {
}

export default function CustomImage(props: ImageProps) {
return (
<Image
{...props}
src={`https://res.cloudinary.com/${
process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME
}/image/fetch/${encodeURIComponent(props.src)}`}
/>
);
return <Image {...props} />;
}
25 changes: 6 additions & 19 deletions components/footer.tsx → components/footer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
"use client";
import { key } from "@/lib/utils";
import Link from "next/link";
import CustomImage from "./customImage";
import Image from "next/image";
import { useTheme } from "next-themes";
import { getThemeConfig } from "../lib/theme";
import { useEffect, useState } from "react";
import { useEffect, useState, ReactNode } from "react";

interface CategoryItem {
Category: string;
Expand All @@ -18,10 +15,10 @@ interface CategoryItem {
interface Props {
baseConfig: { [key: string]: any };
footerData: { [key in string]: CategoryItem[] };
logo: ReactNode;
}
export function Footer({ baseConfig, footerData }: Props) {
export function Footer({ baseConfig, footerData, logo }: Props) {
const [mounted, setMounted] = useState(false);
const { theme } = useTheme();

// useEffect only runs on the client, so now we can safely show the UI
useEffect(() => {
Expand All @@ -36,22 +33,12 @@ export function Footer({ baseConfig, footerData }: Props) {
<footer className="bg-footer-background">
<div className="container p-8 ">
<div className="footer-links lg:grid grid-cols-5 gap-4">
<div className="hidden lg:block">
<CustomImage
src={getThemeConfig(theme, [
baseConfig?.logoLight,
baseConfig?.logoDark,
])}
width={115}
height={32}
alt="logo"
/>
</div>
{Object.keys(footerData).map(category => (
<div className="hidden lg:block">{logo}</div>
{Object.keys(footerData).map((category) => (
<div key={category} className="mb-4">
<h3 className="font-bold mb-4">{category}</h3>
<ul>
{footerData[category].map(item => (
{footerData[category].map((item) => (
<li key={key()} className="leading-[32px]">
<Link
className="hover:underline text-link"
Expand Down
36 changes: 36 additions & 0 deletions components/logo/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Dark, Light } from "./theme";
import CustomImage from "../customImage";

interface Props {
baseConfig: { [key: string]: any };
className?: string;
theme?: string;
}
export function Logo({ baseConfig, className }: Props) {
return (
<>
{baseConfig?.logoLight ? (
<Light>
<CustomImage
src={baseConfig.logoLight}
width={115}
height={32}
alt="logo"
className={className}
/>
</Light>
) : null}
{baseConfig?.logoDark ? (
<Dark>
<CustomImage
src={baseConfig.logoLight}
width={115}
height={32}
alt="logo"
className={className}
/>
</Dark>
) : null}
</>
);
}
17 changes: 17 additions & 0 deletions components/logo/ssr-logo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import CustomImage from "@/components/customImage";

interface Props {
src: string;
className?: string;
}
export function SsrLogo({ src, className }: Props) {
return (
<CustomImage
src={src}
width={115}
height={32}
alt="logo"
className={className}
/>
);
}
19 changes: 19 additions & 0 deletions components/logo/theme.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"use client";

import { useTheme } from "next-themes";

interface Props {
children: React.ReactNode;
}

export function Light({ children }: Props) {
const { resolvedTheme } = useTheme();

if (resolvedTheme === "light") return <>{children}</>;
}

export function Dark({ children }: Props) {
const { resolvedTheme } = useTheme();

if (resolvedTheme !== "light") return <>{children}</>;
}
24 changes: 24 additions & 0 deletions export-images.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* @type {import('next-export-optimize-images').Config}
*/
const config = {
filenameGenerator: ({ path, name, width, extension }) =>
`${name}.${width}.${extension}`,
sourceImageParser: ({ src, defaultParser }) => {
const regExpMatches = src.match(/^.*\?code=(.*)$/);
if (!regExpMatches) {
return defaultParser(src);
}

// if the src has fileId and extension in its route then it
// must be a non-standard image, so parse it differently for all intents
// and purposes
return {
pathWithoutName: "", // maybe there is no path, or you can supply an arbitrary one for filename processing
name: regExpMatches[1] || "",
extension: "png",
};
},
};

module.exports = config;
17 changes: 9 additions & 8 deletions next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import withExportImages from "next-export-optimize-images";

/** @type {import('next').NextConfig} */
const nextConfig = {
staticPageGenerationTimeout: 10000,
images: {
remotePatterns: [
{
protocol: "https",
hostname: "internal-api-drive-stream-sg.larksuite.com",
port: "",
pathname: "**",
},
// {
// protocol: "https",
// hostname: "internal-api-drive-stream-sg.larksuite.com",
// port: "",
// pathname: "**",
// },
{
protocol: "https",
hostname: "docs.aelf.dev",
port: "",
pathname: "**",
},
],
unoptimized: true,
},
experimental: {
workerThreads: false,
Expand All @@ -26,4 +27,4 @@ const nextConfig = {
trailingSlash: true,
};

export default nextConfig;
export default withExportImages(nextConfig);
Loading

0 comments on commit 97e519c

Please sign in to comment.