Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gen card #122

Merged
merged 8 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ GA_ID="xxx"
# microsoft-clarity-id
MC_ID="xxx"

# UNSPLASH ACCESS KEY
UNSPLASH_ACCESS_KEY="

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
"tailwind-merge": "^2.2.0",
"tailwindcss-animate": "^1.0.7",
"tailwindcss-bg-patterns": "^0.3.0",
"uid": "^2.0.2",
"unsplash-js": "^7.0.19",
"zod": "^3.22.4"
},
"devDependencies": {
Expand Down
23 changes: 23 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ model Poem {
createdAt DateTime? @default(now())
updatedAt DateTime? @updatedAt
views Int @default(0)
cards Card[]
}

model Card {
id Int @id @default(autoincrement())
url String @unique
createdAt DateTime? @default(now())
updatedAt DateTime? @updatedAt
poem Poem @relation(fields: [poemId], references: [id])
poemId Int
}

model Author {
Expand Down
9 changes: 4 additions & 5 deletions src/app/[lang]/poem/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,11 @@ import { getPoemTitle } from "./utils";
import { Body } from "./components/body";
import { More } from "./components/more";
import { getDictionary, type Locale } from "~/dictionaries";
import { type Author, type Poem, type Tag } from "@prisma/client";
import "./index.css";

const GoFeedback = dynamic(() => import("./go-feedback"), { ssr: false });

const SaveShareButton = dynamic(() => import("./components/share"), {
const SaveShareButton = dynamic(() => import("~/components/share"), {
ssr: false,
});

Expand All @@ -35,12 +34,12 @@ const CopyButton = dynamic(() => import("./components/copy"), {
});

const DrawDefaultPreview = dynamic(
() => import("./components/share/draw/default"),
() => import("~/components/share/draw/default"),
{ ssr: false },
);

const DrawWuYanPreview = dynamic(
() => import("./components/share/draw/wu-yan"),
() => import("~/components/share/draw/wu-yan"),
{ ssr: false },
);

Expand All @@ -59,7 +58,7 @@ const getItem = cache(async ({ id, lang }: Props["params"]) => {
notFound();
}

return poem as Poem & { author: Author } & { tags: Tag[] };
return poem;
});

export const revalidate = 3600;
Expand Down
108 changes: 108 additions & 0 deletions src/app/create/gen-card/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
"use client";

import { toBlob } from "html-to-image";
import { useState } from "react";
import DrawDefaultPreview from "~/components/share/draw/default";
import { Button } from "~/components/ui/button";
import { api } from "~/trpc/react";
import { uid } from "uid";
import { useSearchParams } from "next/navigation";
import { type Author } from "@prisma/client";

interface Props {
poems: { id: number; author: Author; title: string; content: string }[];
urls: string[];
}

export default function GenCardPage() {
const [page, setPage] = useState(1);
const params = useSearchParams();
const token = params.get("token") ?? "";

const { data } = api.card.getGenerateCard.useQuery(
{ page, token },
{ refetchOnWindowFocus: false },
);

if (!data) return null;
const { data: poems, pageCount, urls } = data;
if (!urls) return null;

return (
<div>
<h1 className="prose-h1">生成卡片</h1>
<div className="mt-4">
<GenCard poems={poems} urls={urls} token={token} />

<div className="mt-2 space-x-2">
{new Array(pageCount).fill(0).map((_, index) => (
<Button
key={index}
variant={page === index + 1 ? "default" : "outline"}
onClick={() => setPage(index + 1)}
>
{index + 1}
</Button>
))}
</div>
</div>
<div className="mt-8 grid grid-cols-3 gap-2 gap-y-8">
{poems.map((item, i) => (
<DrawDefaultPreview
key={item.id}
data={item}
bgImage={urls[i]}
id={`draw-share-card-${item.id}`}
/>
))}
</div>
</div>
);
}

const GenCard = ({ poems, token }: Props & { token: string }) => {
const cardMutation = api.card.createCardItem.useMutation();

const download = async (id: number) => {
const card = document.getElementById(`draw-share-card-${id}`);
if (!card) return;

try {
const blob = await toBlob(card, {
width: card.clientWidth * 2,
height: card.clientHeight * 2,
cacheBust: true,
style: {
transform: "scale(2)",
transformOrigin: "top left",
},
});

if (!blob) return;

const name = `${id}-${uid()}`;

const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = `${name}.png`;
a.click();

await cardMutation.mutateAsync({
token,
url: name,
poemId: id,
});
} catch (e) {
console.error(e);
}
};

const gen = async () => {
for (const item of poems) {
await download(item.id);
}
};

return <Button onClick={gen}>一键生成 ({poems.length})</Button>;
};
3 changes: 2 additions & 1 deletion src/app/create/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ export default function Layout({ children }: { children: React.ReactNode }) {

const navs = [
{ title: "诗词", path: "/create/poem" },
{ title: "更新诗词英语", path: "/create/poem-en" },
{ title: "更新诗词-英语", path: "/create/poem-en" },
{ title: "作者", path: "/create/author" },
{ title: "标签", path: "/create/tag" },
{ title: "表格", path: "/create/table" },
{ title: "生成卡片", path: "/create/gen-card" },
];

return (
Expand Down
2 changes: 1 addition & 1 deletion src/app/create/poem-en/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default function CreatePage() {
const router = useRouter();
const id = params.get("id") ?? "";

const { data: poem } = api.poem.findById.useQuery(
const { data: poem } = api.poem.findByIdSelected.useQuery(
{
id: Number(id),
selected: ["translation_en"],
Expand Down
5 changes: 4 additions & 1 deletion src/app/create/poem/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
SelectValue,
} from "~/components/ui/select";
import { convertToHans, convertToHant } from "~/utils/convert";
import { type Author, type Poem, type Tag } from "@prisma/client";

export default function CreatePage() {
const utils = api.useUtils();
Expand All @@ -32,7 +33,7 @@ export default function CreatePage() {
pageSize: 9999,
});

const { data: poem } = api.poem.findById.useQuery(
const { data: poemT } = api.poem.findById.useQuery(
{
id: Number(id),
},
Expand All @@ -41,6 +42,8 @@ export default function CreatePage() {
},
);

const poem = poemT as Poem & { author: Author; tags: Tag[] };

const [keyword, setKeyword] = useState("");

// 作者
Expand Down
14 changes: 0 additions & 14 deletions src/app/demo/page.tsx

This file was deleted.

4 changes: 2 additions & 2 deletions src/app/demo/share-card/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import { api } from "~/trpc/react";
import { random } from "lodash-es";
import SaveShareButton from "~/app/[lang]/poem/[id]/components/share";
import DrawDefaultPreview from "~/app/[lang]/poem/[id]/components/share/draw/default";
import bgCardsImages from "~/utils/bg-card";
import SaveShareButton from "~/components/share";
import DrawDefaultPreview from "~/components/share/draw/default";

export default function Page() {
const { data } = api.poem.findById.useQuery(
Expand Down
Loading