parent
7d0ac45e8a
commit
81deef7374
|
|
@ -1,3 +1,4 @@
|
||||||
APP_SITENAME=萝心花园
|
APP_SITENAME=萝心花园
|
||||||
APP_APIURL=https://paul.ren
|
APP_APIURL=https://paul.ren
|
||||||
|
APP_BACKEND_EXT_URL=https://ext.paul.ren
|
||||||
APP_FOOTER_EXTRA=
|
APP_FOOTER_EXTRA=
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,10 @@ import {
|
||||||
Feed,
|
Feed,
|
||||||
} from "~/components/ui/icons";
|
} from "~/components/ui/icons";
|
||||||
import { siteTitle } from "~/utils";
|
import { siteTitle } from "~/utils";
|
||||||
|
import { getImageThumbUrl } from "~/utils/media";
|
||||||
|
|
||||||
import type { Route } from "./+types/index";
|
import type { Route } from "./+types/index";
|
||||||
|
|
||||||
import styles from "./index.module.css";
|
import styles from "./index.module.css";
|
||||||
|
|
||||||
const year = new Date().getFullYear();
|
const year = new Date().getFullYear();
|
||||||
|
|
@ -36,15 +38,15 @@ export default function Index({ loaderData }: Route.ComponentProps) {
|
||||||
const { data } = loaderData;
|
const { data } = loaderData;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="px-2 py-24 max-w-3xl mx-auto">
|
<main className="px-2 py-24">
|
||||||
<section className="-mt-40 relative flex flex-col h-screen min-h-160 max-w-3xl mx-auto">
|
<section className="-mt-40 relative flex flex-col h-screen min-h-160 max-w-4xl mx-auto">
|
||||||
<div className="my-auto px-4 py-10 bg-white rounded-xl text-center">
|
<div className="my-auto text-center">
|
||||||
<div className="mx-auto w-40 mb-10 relative select-none">
|
<div className="mx-auto w-40 mb-12 relative select-none">
|
||||||
<div className="top-4 left-2 w-36 h-36 rounded-full absolute bg-pink-100"></div>
|
<div className="top-4 left-2 w-36 h-36 rounded-full absolute bg-pink-100"></div>
|
||||||
<img className={styles.avatar} src="/avatar.webp" alt="奇趣保罗" />
|
<img className={styles.avatar} src="/avatar.webp" alt="奇趣保罗" />
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-5xl mb-4">奇趣保罗</h1>
|
<h1 className="text-5xl md:text-7xl mb-4">奇趣保罗</h1>
|
||||||
<p className="opacity-60 mb-10">一只正在学习前后端技术的萌新</p>
|
<p className="opacity-60 mb-12">一只正在学习前后端技术的萌新</p>
|
||||||
<p className="flex justify-center gap-3">
|
<p className="flex justify-center gap-3">
|
||||||
<a href="https://paul.ren/join-group" target="_blank" rel="noreferrer" title="企鹅群">
|
<a href="https://paul.ren/join-group" target="_blank" rel="noreferrer" title="企鹅群">
|
||||||
<QQ className="w-6" />
|
<QQ className="w-6" />
|
||||||
|
|
@ -72,41 +74,57 @@ export default function Index({ loaderData }: Route.ComponentProps) {
|
||||||
<ArrowDown className="absolute left-0 right-0 bottom-20 mx-auto w-10 h-10 opacity-60 animate-bounce" />
|
<ArrowDown className="absolute left-0 right-0 bottom-20 mx-auto w-10 h-10 opacity-60 animate-bounce" />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="mb-16">
|
<section className="max-w-4xl mx-auto mb-24">
|
||||||
<h2 className="text-3xl mb-4">近期博文</h2>
|
<h2 className="text-5xl text-center mb-10">近期博文</h2>
|
||||||
<div className="bg-white rounded-xl p-5">
|
<div className="grid grid-cols-2 gap-5">
|
||||||
{data.data.blog.map((item) => (
|
{data.data.blog.map((item) => (
|
||||||
<p key={item.link} className="flex mb-3 last:mb-0">
|
<a
|
||||||
<a className="flex-1" href={item.link} target="_blank" rel="noreferrer">{item.title}</a>
|
key={item.link}
|
||||||
<span className="font-mono opacity-50">{item.date}</span>
|
href={item.link}
|
||||||
</p>
|
target="_blank"
|
||||||
|
className="flex flex-col bg-white rounded-xl p-5 border-4 border-transparent hover:border-pink-400 transition-colors border-b-cyan-200"
|
||||||
|
>
|
||||||
|
<h3 className="text-pink-400 text-xl font-semibold truncate mb-4">{item.title}</h3>
|
||||||
|
<p className="text-sm leading-relaxed flex-1 line-clamp-2 mb-4">{item.content}</p>
|
||||||
|
<span className="text-sm opacity-50">{item.date}</span>
|
||||||
|
</a>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="mb-16">
|
<section className="max-w-4xl mx-auto mb-24">
|
||||||
<h2 className="text-3xl mb-4">近期日记</h2>
|
<h2 className="text-5xl text-center mb-10">近期日记</h2>
|
||||||
<div className="bg-white rounded-xl p-5">
|
<div className="grid grid-cols-2 gap-5">
|
||||||
{data.data.note.map((item) => (
|
{data.data.note.map((item) => (
|
||||||
<p key={item.id} className="flex mb-3 last:mb-0">
|
<Link
|
||||||
<Link className="flex-1" to={`/note/${year}/${item.id}`}>{item.title}</Link>
|
key={item.id}
|
||||||
<span className="font-mono opacity-50">{item.date}</span>
|
to={`/note/${year}/${item.id}`}
|
||||||
</p>
|
className="flex flex-col bg-white rounded-xl p-5 border-4 border-transparent hover:border-pink-400 transition-colors border-b-cyan-200"
|
||||||
|
>
|
||||||
|
<h3 className="text-pink-400 text-xl font-semibold truncate mb-4">{item.title}</h3>
|
||||||
|
<p className="text-sm leading-relaxed flex-1 line-clamp-2 mb-4">{item.except}</p>
|
||||||
|
<span className="text-sm opacity-50">{item.date}</span>
|
||||||
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section className="max-w-screen-2xl mx-auto">
|
||||||
<h2 className="text-3xl mb-4">近期捕获</h2>
|
<h2 className="text-5xl text-center mb-10">近期捕获</h2>
|
||||||
<div className="bg-white rounded-xl p-5 grid grid-cols-2 gap-5">
|
<div className="grid grid-cols-2 lg:grid-cols-4 gap-5">
|
||||||
{data.data.media.map((item) => (
|
{data.data.media.map((item) => (
|
||||||
<div key={item.id}>
|
<div
|
||||||
<img className="mb-3 rounded-xl" src={item.thumb_url} alt={item.title} />
|
key={item.id}
|
||||||
<h3 className="text-lg mb-1">{item.title}</h3>
|
className="flex flex-col overflow-hidden bg-white rounded-xl border-4 border-transparent hover:border-pink-400 transition-colors border-b-cyan-200"
|
||||||
<p className="text-xs opacity-50">{item.take_time.substring(0, 10)}</p>
|
>
|
||||||
|
<img className="w-full aspect-4/3 object-cover" src={getImageThumbUrl(item.thumb_url, { height: 450, width: 900 })} alt={item.title} />
|
||||||
|
<div className="flex flex-col flex-1 p-5">
|
||||||
|
<h3 className="text-pink-400 text-xl font-semibold flex-1 truncate mb-4">{item.title}</h3>
|
||||||
|
<p className="text-sm opacity-50">{item.take_time.substring(0, 10)}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ export default function Note({ loaderData }: Route.ComponentProps) {
|
||||||
{item.starred && (
|
{item.starred && (
|
||||||
<StarFill className="absolute -top-5 -right-5 w-28 h-28 text-yellow-300 text-opacity-20 rotate-[-23deg]" />
|
<StarFill className="absolute -top-5 -right-5 w-28 h-28 text-yellow-300 text-opacity-20 rotate-[-23deg]" />
|
||||||
)}
|
)}
|
||||||
<h2 className={clsn(cover && "mt-48 sm:mt-0 md:mr-40", "text-pink-400 text-2xl font-bold mb-4")} style={{ viewTransitionName: `note-title-${item.id}` }}>
|
<h2 className={clsn(cover && "mt-48 sm:mt-0 sm:mr-40", "text-pink-400 text-2xl font-bold mb-4")} style={{ viewTransitionName: `note-title-${item.id}` }}>
|
||||||
{item.title}
|
{item.title}
|
||||||
</h2>
|
</h2>
|
||||||
<p className={clsn(cover && "sm:mr-40", "mb-8 relative")}>{item.except}</p>
|
<p className={clsn(cover && "sm:mr-40", "mb-8 relative")}>{item.except}</p>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
const { APP_BACKEND_EXT_URL } = import.meta.env;
|
||||||
|
|
||||||
|
// 获取图片缩略图
|
||||||
|
export const getImageThumbUrl = (
|
||||||
|
url: string,
|
||||||
|
{ width = 500, height = 500 }: { width?: number; height?: number } = {}
|
||||||
|
) => {
|
||||||
|
// 确保不会出错
|
||||||
|
if (!APP_BACKEND_EXT_URL) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
const extUrl = new URL(APP_BACKEND_EXT_URL);
|
||||||
|
extUrl.pathname = `/api/image-compress/${new URL(
|
||||||
|
url.replace(".mp4", ".jpg")
|
||||||
|
).pathname.replace("/upload/", "")}`;
|
||||||
|
extUrl.searchParams.set("w", String(width || 500));
|
||||||
|
extUrl.searchParams.set("h", String(height || 500));
|
||||||
|
|
||||||
|
return extUrl.toString();
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue