Skip to content

Commit

Permalink
Merge branch 'main' of github.com:piterator-org/luogu-discussion-archive
Browse files Browse the repository at this point in the history
  • Loading branch information
wxh06 committed Jul 5, 2023
2 parents 0fb76db + 357f6f1 commit 00cd8ce
Show file tree
Hide file tree
Showing 6 changed files with 292 additions and 12 deletions.
107 changes: 107 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# 许可证

版权所有 © 2023 Piterator。

## 引言

「洛谷讨论存档」(Luogu Discussion Archive)是由 Piterator 开发的软件,该软件中包含的所有文本、图形图像和源代码的版权在没有额外条款明确指明的情况下均属于 Piterator。

Piterator 保留对「洛谷讨论存档」及其中包含的所有 Piterator 拥有的文本、图形图像和软件的所有权利。

「洛谷讨论存档」公开的源代码仅可作为参考与学习之用途。

## 贡献者许可协议(CLA)

贡献源代码即代表您同意将所撰写的相关源代码的著作权按本许可证不可撤销地授予 Piterator。

## 第三方资源

EXLG 徽标:由 [haraki](https://github.com/haraki-argon)<!-- @haraki-argon --> 设计,其著作权归 [EXLG 团队](https://github.com/extend-luogu) 所有。

## 第三方软件许可证

以下列举了部分该软件使用到的第三方软件的许可证。完整软件列表请参阅 [pnpm-lock.yaml](./pnpm-lock.yaml)

### [Bootstrap](https://github.com/twbs/bootstrap/blob/main/LICENSE)

```plaintext
The MIT License (MIT)
Copyright (c) 2011-2023 The Bootstrap Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
```

### [Next.js](https://github.com/vercel/next.js/blob/canary/license.md)

```plaintext
The MIT License (MIT)
Copyright (c) 2023 Vercel, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```

### [React](https://github.com/facebook/react/blob/main/LICENSE)

```plaintext
MIT License
Copyright (c) Meta Platforms, Inc. and affiliates.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```

### 洛谷 3

该软件引用了洛谷 3 用户名颜色的样式表。

合理使用,著作权归[上海洛谷网络科技有限公司](https://www.luogu.com.cn/)所有。
10 changes: 10 additions & 0 deletions packages/viewer/src/app/bootstrap.scss
Original file line number Diff line number Diff line change
Expand Up @@ -224,3 +224,13 @@ details[open] summary .open-hide {
details[open] summary .open-show-inline {
display: inline !important;
}

.reply-meta-bottom {
bottom: -1.5em;
}

@include media-breakpoint-up(md) {
.reply-meta-bottom {
bottom: -2.8em;
}
}
114 changes: 109 additions & 5 deletions packages/viewer/src/app/r/[rid]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,124 @@
import prisma from "@/lib/prisma";
import { notFound, redirect } from "next/navigation";
import { notFound } from "next/navigation";
import Link from "next/link";
import Image from "next/image";
import Content from "@/components/replies/Content";
import UserInfo from "@/components/UserInfo";
import serializeReply from "@/lib/serialize-reply";
import { getUserAvatarUrl, getUserUrl } from "@/lib/luogu";

export const metadata = { title: "金玉良言 - 洛谷帖子保存站" };

const REPLIES_PER_PAGE = parseInt(process.env.REPLIES_PER_PAGE ?? "10", 10);

export default async function Page({ params }: { params: { rid: string } }) {
const id = parseInt(params.rid, 10);
if (Number.isNaN(id)) notFound();
const { discussionId } =
const replyRaw =
(await prisma.reply.findUnique({
select: { discussionId: true },
select: {
id: true,
author: true,
time: true,
content: true,
discussion: {
select: {
id: true,
snapshots: {
select: { title: true, authorId: true },
orderBy: { time: "desc" },
take: 1,
},
},
},
},
where: { id },
})) ?? notFound();
const reply = {
...replyRaw,
...(await serializeReply(replyRaw.discussion.id, replyRaw)),
};
const pages = Math.ceil(
(await prisma.reply.count({
where: { id: { lte: id }, discussionId },
where: { id: { lte: id }, discussionId: reply.discussion.id },
})) / REPLIES_PER_PAGE
);
return redirect(`/${discussionId}/${pages}#${params.rid}`);
// return redirect(`/${discussionId}/${pages}#${params.rid}`);
return (
<div className="row px-2 px-md-0">
<div className="col-xl-9 col-lg-10 col-md-11 col-12 mt-3 mb-3x mx-auto">
<div className="pb-3 mb-4x position-relative">
<div className="bg-white rounded-4 shadow">
<div className="px-4 pt-2 pb-4 position-relative">
<Content
discussionAuthor={reply.discussion.snapshots[0].authorId}
content={reply.content}
usersMetioned={reply.usersMetioned}
/>
<span
className="text-end text-body-tertiary d-block d-md-none"
style={{ fontSize: ".8rem" }}
>
{reply.time}
</span>
</div>
</div>
<div
className="position-absolute"
style={{ bottom: "-1.6em", left: ".8em" }}
>
<a
href={getUserUrl(reply.author.id)}
target="_blank"
rel="noopener noreferrer"
>
<Image
src={getUserAvatarUrl(reply.author.id)}
className="rounded-circle shadow"
width={72}
height={72}
alt={reply.author.id.toString()}
/>
</a>
</div>
<div
className="ps-6 position-absolute reply-meta-bottom"
style={{ left: 0, right: 0 }}
>
<div>
<UserInfo user={reply.author} />
<span
className="float-end text-body-tertiary d-none d-md-inline"
style={{ marginRight: ".8em" }}
>
{reply.time}
</span>
</div>
<div className="fw-medium text-body-tertiary d-none d-md-block">
于帖子{" "}
<Link
className="text-decoration-none"
href={`/${reply.discussion.id}/${pages}#${params.rid}`}
>
{reply.discussion.snapshots[0].title}
<span className="fw-normal">(第 {pages} 页)</span>
</Link>
</div>
</div>
</div>
<div className="mt-5 bg-white rounded-4 shadow d-md-none px-4 py-3">
<div className="fw-medium text-body-tertiary">
于帖子{" "}
<Link
className="text-decoration-none"
href={`/${reply.discussion.id}/${pages}#${params.rid}`}
>
{reply.discussion.snapshots[0].title}
<span className="fw-normal">(第 {pages} 页)</span>
</Link>
</div>
</div>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,35 @@ export default function UserParticipated({
) : (
""
)}
<span className="float-end text-body-tertiary d-none d-md-inline">
{reply.time}
<span className="float-end text-body-tertiary">
<span className="d-none d-md-inline">
{reply.time}
</span>
{reply.id !== undefined ? (
<Link
href={`/r/${reply.id}`}
className="ms-2 link-secondary position-relative"
style={{ fontSize: ".8em", top: "-.2em" }}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
fill="currentColor"
className="bi bi-box-arrow-up-right"
viewBox="0 0 16 16"
>
<path
fillRule="evenodd"
d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"
/>
<path
fillRule="evenodd"
d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"
/>
</svg>
</Link>
) : undefined}
</span>
</div>
<div className="px-4 py-2 position-relative">
Expand Down
12 changes: 9 additions & 3 deletions packages/viewer/src/components/markdown.css
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@
.markdown ul > li::before {
content: "→";
position: absolute;
left: -1.2em;
left: -1.4em;
color: #dad9da;
transition: ease-in-out color 0.1s;
}

.markdown ul > li:hover:before {
.markdown ul > li:hover::before {
color: #6c757d;
}

Expand Down Expand Up @@ -226,7 +226,13 @@
}

.markdown code {
font-family: "Fira Code", Consolas, monospace;
font-family: "Fira Code", Menlo, Monaco, "Courier New", Consolas, monospace;
tab-size: 4;
border-radius: 0.9em;
}

/* .markdown p > img:only-child {
display: block;
margin-left: auto;
margin-right: auto;
} */
30 changes: 28 additions & 2 deletions packages/viewer/src/components/replies/Reply.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { User } from "@prisma/client";
import type { UserMetioned } from "@/lib/serialize-reply";
import UserAvatar from "@/components/UserAvatar";
import UserInfo from "@/components/UserInfo";
import Link from "next/link";
import Content from "./Content";
import ContextViewer from "./ContextViewer";

Expand Down Expand Up @@ -54,8 +55,33 @@ export default function Reply({
) : (
""
)}
<span className="float-end text-body-tertiary d-none d-md-inline">
{reply.time}
<span className="float-end text-body-tertiary">
<span className="d-none d-md-inline">{reply.time}</span>
{reply.id !== undefined ? (
<Link
href={`/r/${reply.id}`}
className="ms-2 link-secondary position-relative"
style={{ fontSize: ".8em", top: "-.2em" }}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
fill="currentColor"
className="bi bi-box-arrow-up-right"
viewBox="0 0 16 16"
>
<path
fillRule="evenodd"
d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"
/>
<path
fillRule="evenodd"
d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"
/>
</svg>
</Link>
) : undefined}
</span>
</div>
<div className="reply-content pe-4 py-2 position-relative">
Expand Down

0 comments on commit 00cd8ce

Please sign in to comment.