diff --git a/package.json b/package.json index 9c4a69b4..662b95de 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ }, "dependencies": { "@giscus/react": "^2.4.0", - "@prisma/client": "^5.6.0", + "@prisma/client": "^5.8.1", "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6", @@ -68,7 +68,7 @@ "postcss-nesting": "^12.0.2", "prettier": "^3.1.0", "prettier-plugin-tailwindcss": "^0.5.7", - "prisma": "^5.6.0", + "prisma": "^5.8.1", "tailwindcss": "^3.3.5", "typescript": "^5.1.6" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2f1d1aa1..bae4e6f0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ dependencies: specifier: ^2.4.0 version: 2.4.0(react-dom@18.2.0)(react@18.2.0) '@prisma/client': - specifier: ^5.6.0 - version: 5.7.1(prisma@5.7.1) + specifier: ^5.8.1 + version: 5.8.1(prisma@5.8.1) '@radix-ui/react-avatar': specifier: ^1.0.4 version: 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0) @@ -167,8 +167,8 @@ devDependencies: specifier: ^0.5.7 version: 0.5.10(prettier@3.1.1) prisma: - specifier: ^5.6.0 - version: 5.7.1 + specifier: ^5.8.1 + version: 5.8.1 tailwindcss: specifier: ^3.3.5 version: 3.4.0 @@ -459,8 +459,8 @@ packages: requiresBuild: true optional: true - /@prisma/client@5.7.1(prisma@5.7.1): - resolution: {integrity: sha512-TUSa4nUcC4nf/e7X3jyO1pEd6XcI/TLRCA0KjkA46RDIpxUaRsBYEOqITwXRW2c0bMFyKcCRXrH4f7h4q9oOlg==} + /@prisma/client@5.8.1(prisma@5.8.1): + resolution: {integrity: sha512-xQtMPfbIwLlbm0VVIVQY2yqQVOxPwRQhvIp7Z3m2900g1bu/zRHKhYZJQWELqmjl6d8YwBy0K2NvMqh47v1ubw==} engines: {node: '>=16.13'} requiresBuild: true peerDependencies: @@ -469,35 +469,35 @@ packages: prisma: optional: true dependencies: - prisma: 5.7.1 + prisma: 5.8.1 dev: false - /@prisma/debug@5.7.1: - resolution: {integrity: sha512-yrVSO/YZOxdeIxcBtZ5BaNqUfPrZkNsAKQIQg36cJKMxj/VYK3Vk5jMKkI+gQLl0KReo1YvX8GWKfV788SELjw==} + /@prisma/debug@5.8.1: + resolution: {integrity: sha512-tjuw7eA0Us3T42jx9AmAgL58rzwzpFGYc3R7Y4Ip75EBYrKMBA1YihuWMcBC92ILmjlQ/u3p8VxcIE0hr+fZfg==} - /@prisma/engines-version@5.7.1-1.0ca5ccbcfa6bdc81c003cf549abe4269f59c41e5: - resolution: {integrity: sha512-dIR5IQK/ZxEoWRBDOHF87r1Jy+m2ih3Joi4vzJRP+FOj5yxCwS2pS5SBR3TWoVnEK1zxtLI/3N7BjHyGF84fgw==} + /@prisma/engines-version@5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2: + resolution: {integrity: sha512-f5C3JM3l9yhGr3cr4FMqWloFaSCpNpMi58Om22rjD2DOz3owci2mFdFXMgnAGazFPKrCbbEhcxdsRfspEYRoFQ==} - /@prisma/engines@5.7.1: - resolution: {integrity: sha512-R+Pqbra8tpLP2cvyiUpx+SIKglav3nTCpA+rn6826CThviQ8yvbNG0s8jNpo51vS9FuZO3pOkARqG062vKX7uA==} + /@prisma/engines@5.8.1: + resolution: {integrity: sha512-TJgYLRrZr56uhqcXO4GmP5be+zjCIHtLDK20Cnfg+o9d905hsN065QOL+3Z0zQAy6YD31Ol4u2kzSfRmbJv/uA==} requiresBuild: true dependencies: - '@prisma/debug': 5.7.1 - '@prisma/engines-version': 5.7.1-1.0ca5ccbcfa6bdc81c003cf549abe4269f59c41e5 - '@prisma/fetch-engine': 5.7.1 - '@prisma/get-platform': 5.7.1 + '@prisma/debug': 5.8.1 + '@prisma/engines-version': 5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2 + '@prisma/fetch-engine': 5.8.1 + '@prisma/get-platform': 5.8.1 - /@prisma/fetch-engine@5.7.1: - resolution: {integrity: sha512-9ELauIEBkIaEUpMIYPRlh5QELfoC6pyHolHVQgbNxglaINikZ9w9X7r1TIePAcm05pCNp2XPY1ObQIJW5nYfBQ==} + /@prisma/fetch-engine@5.8.1: + resolution: {integrity: sha512-+bgjjoSFa6uYEbAPlklfoVSStOEfcpheOjoBoNsNNSQdSzcwE2nM4Q0prun0+P8/0sCHo18JZ9xqa8gObvgOUw==} dependencies: - '@prisma/debug': 5.7.1 - '@prisma/engines-version': 5.7.1-1.0ca5ccbcfa6bdc81c003cf549abe4269f59c41e5 - '@prisma/get-platform': 5.7.1 + '@prisma/debug': 5.8.1 + '@prisma/engines-version': 5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2 + '@prisma/get-platform': 5.8.1 - /@prisma/get-platform@5.7.1: - resolution: {integrity: sha512-eDlswr3a1m5z9D/55Iyt/nZqS5UpD+DZ9MooBB3hvrcPhDQrcf9m4Tl7buy4mvAtrubQ626ECtb8c6L/f7rGSQ==} + /@prisma/get-platform@5.8.1: + resolution: {integrity: sha512-wnA+6HTFcY+tkykMokix9GiAkaauPC5W/gg0O5JB0J8tCTNWrqpnQ7AsaGRfkYUbeOIioh6woDjQrGTTRf1Zag==} dependencies: - '@prisma/debug': 5.7.1 + '@prisma/debug': 5.8.1 /@radix-ui/number@1.0.1: resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==} @@ -3759,13 +3759,13 @@ packages: hasBin: true dev: true - /prisma@5.7.1: - resolution: {integrity: sha512-ekho7ziH0WEJvC4AxuJz+ewRTMskrebPcrKuBwcNzVDniYxx+dXOGcorNeIb9VEMO5vrKzwNYvhD271Ui2jnNw==} + /prisma@5.8.1: + resolution: {integrity: sha512-N6CpjzECnUHZ5beeYpDzkt2rYpEdAeqXX2dweu6BoQaeYkNZrC/WJHM+5MO/uidFHTak8QhkPKBWck1o/4MD4A==} engines: {node: '>=16.13'} hasBin: true requiresBuild: true dependencies: - '@prisma/engines': 5.7.1 + '@prisma/engines': 5.8.1 /prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} diff --git a/prisma/schema.prisma b/prisma/schema.prisma index f1bc5bd8..9d72815b 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -20,6 +20,8 @@ model Poem { contentPinYin String? introduce String? translation String? + // 注解 JSON 字符串 {文字: 解释} + annotation String? author Author @relation(fields: [authorId], references: [id]) authorId Int // 内容分类:叙事诗、抒情诗、送别诗、边塞诗、山水田园诗、咏史诗、咏物诗、悼亡诗、讽喻诗 diff --git a/src/app/(.)/poem/[id]/components/PinYinText/index.css b/src/app/(.)/poem/[id]/components/PinYinText/index.css index 3049a443..1cbe93f7 100644 --- a/src/app/(.)/poem/[id]/components/PinYinText/index.css +++ b/src/app/(.)/poem/[id]/components/PinYinText/index.css @@ -11,7 +11,7 @@ } .char_annotation { - @apply cursor-pointer text-blue-900; + @apply cursor-pointer text-blue-800 dark:text-blue-400; } &.pinyin_h1 { diff --git a/src/app/(.)/poem/[id]/components/PinYinText/index.tsx b/src/app/(.)/poem/[id]/components/PinYinText/index.tsx index 64a98736..2b65ea4d 100644 --- a/src/app/(.)/poem/[id]/components/PinYinText/index.tsx +++ b/src/app/(.)/poem/[id]/components/PinYinText/index.tsx @@ -20,7 +20,13 @@ interface Props { const _pinyinNoShowChar = ["."]; function _getText(text: string, annotation: string[]) { + const newAnnotation: string[] = []; + annotation.forEach((item) => { + if (text.includes(item)) { + newAnnotation.push(item); + } + text = text.replace(item, "$"); }); @@ -31,7 +37,7 @@ function _getText(text: string, annotation: string[]) { return result.map((item) => { if (item === "$") { i++; - return annotation[i - 1] || ""; + return newAnnotation[i - 1] || ""; } return item; @@ -124,7 +130,7 @@ const PinYinText = (props: Props) => { }; return ( - { )} - + ); }; diff --git a/src/app/(.)/poem/[id]/page.tsx b/src/app/(.)/poem/[id]/page.tsx index b97d99cb..e47f756e 100644 --- a/src/app/(.)/poem/[id]/page.tsx +++ b/src/app/(.)/poem/[id]/page.tsx @@ -64,6 +64,10 @@ export default async function Page({ params, searchParams }: Props) { const blockArray = poem.content.split("\n\n"); + const annotation = JSON.parse(poem.annotation ?? "{}") as { + [key in string]: string; + }; + return ( <> @@ -108,7 +112,7 @@ export default async function Page({ params, searchParams }: Props) { pinyin={showPinYin ? poem.titlePinYin ?? "" : ""} type="h1" /> -

+

{poem.author.dynasty && ( {poem.author.dynasty} · )} @@ -156,6 +160,7 @@ export default async function Page({ params, searchParams }: Props) { text={line} align={poem.genre === "词" ? "left" : "center"} pinyin={showPinYin ? blockPinYin?.split("\n")[index] : ""} + annotation={annotation} /> ))} diff --git a/src/app/create/layout.tsx b/src/app/create/layout.tsx index 538d7163..8175da73 100644 --- a/src/app/create/layout.tsx +++ b/src/app/create/layout.tsx @@ -29,7 +29,7 @@ export default function Layout({ children }: { children: React.ReactNode }) { ))} -
+
{children}
diff --git a/src/app/create/poem/page.tsx b/src/app/create/poem/page.tsx index 6ac54856..0880d770 100644 --- a/src/app/create/poem/page.tsx +++ b/src/app/create/poem/page.tsx @@ -42,6 +42,9 @@ export default function CreatePage() { const token = params.get("token") ?? ""; const router = useRouter(); const id = params.get("id") ?? ""; + const [annotations, setAnnotations] = useState< + { keyword: string; content: string }[] + >([]); const { data: poem } = api.poem.findById.useQuery(Number(id), { refetchOnWindowFocus: false, @@ -92,6 +95,7 @@ export default function CreatePage() { setContentPinYin(""); setIntroduce(""); setTranslation(""); + setAnnotations([]); } else { mutation.isSame.mutate({ title, @@ -129,6 +133,21 @@ export default function CreatePage() { setClassify(poem.classify ?? ""); setGenre(poem.genre ?? ""); setTranslation(poem?.translation ?? ""); + + const json = JSON.parse(poem.annotation ?? "{}") as { + [key in string]: string; + }; + + const arr: typeof annotations = []; + + for (const key in json) { + arr.push({ + keyword: key, + content: json[key] || "", + }); + } + + setAnnotations(arr); } }, [poem]); @@ -168,6 +187,7 @@ export default function CreatePage() { onClick={() => { setTitle(simplized(title)); setContent(simplized(content)); + setTranslation(simplized(translation)); }} > 繁转简 @@ -176,182 +196,257 @@ export default function CreatePage() {

Fill out the details htmlFor your new poem

-

-
- - setTitle(e.target.value)} - /> -
-
- - setTitlePinYin(e.target.value)} - /> + {/* 名字 */} +
+
+ + setTitle(e.target.value)} + /> +
+
+ + setTitlePinYin(e.target.value)} + /> +
-
- + {/* 作者 体裁 */} +
+
+ + {authors && ( + { + setAuthorId(framework.id); + }} + defaultValue={{ + ...authorItem, + value: authorItem?.name ?? "", + name: authorItem?.name ?? "", + id: authorItem?.id ?? -1, + }} + frameworks={authors.map((item) => ({ + value: item.name, + name: item.name, + id: item.id, + }))} + /> + )} +
- {authors && ( - { - setAuthorId(framework.id); - }} - defaultValue={{ - ...authorItem, - value: authorItem?.name ?? "", - name: authorItem?.name ?? "", - id: authorItem?.id ?? -1, - }} - frameworks={authors.map((item) => ({ - value: item.name, - name: item.name, - id: item.id, - }))} - /> - )} -
+
+ -
- -