ui
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { ActionIcon, createStyles, Group, Header, rem, TextInput } from "@mantine/core";
|
import { ActionIcon, createStyles, Group, Header, rem, Text, TextInput } from "@mantine/core";
|
||||||
import { useForm } from "@mantine/form";
|
import { useForm } from "@mantine/form";
|
||||||
import { IconSearch } from "@tabler/icons";
|
import { Icon123, IconHome, IconSearch } from "@tabler/icons";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
const useStyles = createStyles((theme) => ({
|
const useStyles = createStyles((theme) => ({
|
||||||
@@ -16,18 +16,6 @@ const useStyles = createStyles((theme) => ({
|
|||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
},
|
},
|
||||||
|
|
||||||
links: {
|
|
||||||
[theme.fn.smallerThan("md")]: {
|
|
||||||
display: "none",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
search: {
|
|
||||||
[theme.fn.smallerThan("xs")]: {
|
|
||||||
display: "none",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
link: {
|
link: {
|
||||||
display: "block",
|
display: "block",
|
||||||
lineHeight: 1,
|
lineHeight: 1,
|
||||||
@@ -42,13 +30,14 @@ const useStyles = createStyles((theme) => ({
|
|||||||
backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[6] : theme.colors.gray[0],
|
backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[6] : theme.colors.gray[0],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
linkText: {
|
||||||
|
[theme.fn.smallerThan("sm")]: {
|
||||||
|
display: "none",
|
||||||
|
},
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
interface HeaderSearchProps {
|
export function HeaderSearch() {
|
||||||
links: { link: string; label: string }[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function HeaderSearch({ links }: HeaderSearchProps) {
|
|
||||||
const { classes } = useStyles();
|
const { classes } = useStyles();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@@ -58,9 +47,23 @@ export function HeaderSearch({ links }: HeaderSearchProps) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const items = links.map((link) => (
|
const items = [
|
||||||
|
{
|
||||||
|
link: "/",
|
||||||
|
label: "Home",
|
||||||
|
icon: <IconHome />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
link: "/statistic",
|
||||||
|
label: "Statistic",
|
||||||
|
icon: <Icon123 />,
|
||||||
|
},
|
||||||
|
].map((link) => (
|
||||||
<a key={link.label} href={link.link} className={classes.link}>
|
<a key={link.label} href={link.link} className={classes.link}>
|
||||||
{link.label}
|
<Group>
|
||||||
|
{link.icon}
|
||||||
|
<Text className={classes.linkText}>{link.label}</Text>
|
||||||
|
</Group>
|
||||||
</a>
|
</a>
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -72,17 +75,12 @@ export function HeaderSearch({ links }: HeaderSearchProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Header height={56} className={classes.header} mb={120}>
|
<Header height={56} className={classes.header}>
|
||||||
<div className={classes.inner}>
|
<div className={classes.inner}>
|
||||||
<Group spacing={5}>{items}</Group>
|
<Group spacing={5}>{items}</Group>
|
||||||
<form onSubmit={form.onSubmit(submit)}>
|
<form onSubmit={form.onSubmit(submit)}>
|
||||||
<Group>
|
<Group>
|
||||||
<TextInput
|
<TextInput placeholder="Search" required {...form.getInputProps("search")} />
|
||||||
className={classes.search}
|
|
||||||
placeholder="Search"
|
|
||||||
required
|
|
||||||
{...form.getInputProps("search")}
|
|
||||||
/>
|
|
||||||
<ActionIcon type="submit">
|
<ActionIcon type="submit">
|
||||||
<IconSearch />
|
<IconSearch />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Button, Container, Grid, Group, Pagination, Title } from "@mantine/core";
|
import { Button, Container, Grid, Group, Pagination, ScrollArea, Title } from "@mantine/core";
|
||||||
import { useDocumentTitle } from "@mantine/hooks";
|
import { useDocumentTitle } from "@mantine/hooks";
|
||||||
import { Paragraph } from "@prisma/client";
|
import { Paragraph } from "@prisma/client";
|
||||||
import { IconArrowBack } from "@tabler/icons";
|
import { IconArrowBack } from "@tabler/icons";
|
||||||
@@ -39,33 +39,35 @@ export default function ParagraphGrid({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container my="8rem">
|
<ScrollArea h="calc( 100vh - 56px )">
|
||||||
<Title>
|
<Container my="2rem">
|
||||||
{title} Page {page}
|
<Title>
|
||||||
</Title>
|
{title} Page {page}
|
||||||
<Group position="apart" my="2rem">
|
</Title>
|
||||||
<Group>{titleAction}</Group>
|
<Group position="apart">
|
||||||
<Button variant="subtle" onClick={() => router.back()} rightIcon={<IconArrowBack />}>
|
<Group>{titleAction}</Group>
|
||||||
Back
|
<Button variant="subtle" onClick={() => router.back()} rightIcon={<IconArrowBack />}>
|
||||||
</Button>
|
Back
|
||||||
</Group>
|
</Button>
|
||||||
<Grid my="md">
|
</Group>
|
||||||
{paragraphs.map((paragraph) => {
|
<Grid my="md">
|
||||||
return (
|
{paragraphs.map((paragraph) => {
|
||||||
<Grid.Col xs={12} sm={4} lg={3} key={paragraph.id}>
|
return (
|
||||||
<ParagraphCard
|
<Grid.Col xs={12} sm={4} lg={3} key={paragraph.id}>
|
||||||
title={paragraph.title}
|
<ParagraphCard
|
||||||
id={paragraph.id}
|
title={paragraph.title}
|
||||||
author={paragraph.author}
|
id={paragraph.id}
|
||||||
time={paragraph.time}
|
author={paragraph.author}
|
||||||
/>
|
time={paragraph.time}
|
||||||
</Grid.Col>
|
/>
|
||||||
);
|
</Grid.Col>
|
||||||
})}
|
);
|
||||||
</Grid>
|
})}
|
||||||
<Group position="center">
|
</Grid>
|
||||||
<Pagination total={totalPage} value={page} onChange={toPage} withControls withEdges />
|
<Group position="center">
|
||||||
</Group>
|
<Pagination total={totalPage} value={page} onChange={toPage} withControls withEdges />
|
||||||
</Container>
|
</Group>
|
||||||
|
</Container>
|
||||||
|
</ScrollArea>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,18 +27,7 @@ export default function App(props: AppProps & { colorScheme: ColorScheme }) {
|
|||||||
|
|
||||||
<ColorSchemeProvider colorScheme={colorScheme} toggleColorScheme={toggleColorScheme}>
|
<ColorSchemeProvider colorScheme={colorScheme} toggleColorScheme={toggleColorScheme}>
|
||||||
<MantineProvider theme={{ colorScheme }} withGlobalStyles withNormalizeCSS>
|
<MantineProvider theme={{ colorScheme }} withGlobalStyles withNormalizeCSS>
|
||||||
<HeaderSearch
|
<HeaderSearch />
|
||||||
links={[
|
|
||||||
{
|
|
||||||
link: "/",
|
|
||||||
label: "Home",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
link: "/statistic",
|
|
||||||
label: "Statistic",
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<Component {...pageProps} />
|
<Component {...pageProps} />
|
||||||
<Notifications />
|
<Notifications />
|
||||||
</MantineProvider>
|
</MantineProvider>
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ export default function ParagraphPage({ paragraph }: { paragraph: Paragraph }) {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollArea h="100vh">
|
<ScrollArea h="calc( 100vh - 56px )">
|
||||||
<Container my="7rem">
|
<Container my="2rem">
|
||||||
<Title mb="xl">{paragraph.title}</Title>
|
<Title mb="xl">{paragraph.title}</Title>
|
||||||
<Group position="apart">
|
<Group position="apart">
|
||||||
<Group>
|
<Group>
|
||||||
|
|||||||
@@ -100,9 +100,9 @@ export default function StatisticPage({ data }: StatsGroupProps) {
|
|||||||
</div>
|
</div>
|
||||||
));
|
));
|
||||||
return (
|
return (
|
||||||
<Container my="7rem">
|
<Container my="2rem">
|
||||||
<Title>Statistic</Title>
|
<Title>Statistic</Title>
|
||||||
<Group position="apart" my="2rem">
|
<Group position="apart" mb="1rem">
|
||||||
<div></div>
|
<div></div>
|
||||||
<Button variant="subtle" onClick={() => router.back()} rightIcon={<IconArrowBack />}>
|
<Button variant="subtle" onClick={() => router.back()} rightIcon={<IconArrowBack />}>
|
||||||
Back
|
Back
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
import { Paragraph } from "@prisma/client";
|
|
||||||
import { GetServerSidePropsContext, GetServerSidePropsResult } from "next";
|
|
||||||
|
|
||||||
import ParagraphGrid from "../../components/ParagraphGrid/ParagraphGrid";
|
|
||||||
import { prismaClient } from "../../lib/db";
|
|
||||||
|
|
||||||
interface ListProps {
|
|
||||||
paragraphs: Omit<Paragraph, "content" | "markdown">[];
|
|
||||||
skip: number;
|
|
||||||
take: number;
|
|
||||||
total: number;
|
|
||||||
tag: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function TagPage(props: ListProps) {
|
|
||||||
return <ParagraphGrid title={`DS-Next | Tag ${props.tag}`} {...props} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getServerSideProps(
|
|
||||||
ctx: GetServerSidePropsContext
|
|
||||||
): Promise<GetServerSidePropsResult<ListProps>> {
|
|
||||||
const skip = Number(ctx.query.skip ?? 0);
|
|
||||||
const take = Number(ctx.query.take ?? 12);
|
|
||||||
const tag = ctx.params?.name;
|
|
||||||
|
|
||||||
if (!tag || typeof tag !== "string") {
|
|
||||||
return { notFound: true };
|
|
||||||
}
|
|
||||||
|
|
||||||
const condition = {
|
|
||||||
tags: {
|
|
||||||
contains: tag,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const [total, paragraphs] = await Promise.all([
|
|
||||||
prismaClient.paragraph.count({
|
|
||||||
where: condition,
|
|
||||||
}),
|
|
||||||
await prismaClient.paragraph.findMany({
|
|
||||||
where: condition,
|
|
||||||
skip: Number(skip),
|
|
||||||
take: Number(take),
|
|
||||||
orderBy: {
|
|
||||||
time: "desc",
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
title: true,
|
|
||||||
tags: true,
|
|
||||||
time: true,
|
|
||||||
author: true,
|
|
||||||
cover: true,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
paragraphs.forEach((paragraph) => {
|
|
||||||
paragraph.time = paragraph.time.getTime() as any;
|
|
||||||
});
|
|
||||||
return { props: { tag, paragraphs, skip, take, total } };
|
|
||||||
}
|
|
||||||
2
prisma/migrations/20230316150231_dev/migration.sql
Normal file
2
prisma/migrations/20230316150231_dev/migration.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE `Paragraph` MODIFY `time` DATETIME NOT NULL;
|
||||||
8
prisma/migrations/20230316151242_dev/migration.sql
Normal file
8
prisma/migrations/20230316151242_dev/migration.sql
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- You are about to alter the column `time` on the `Paragraph` table. The data in that column could be lost. The data in that column will be cast from `DateTime(0)` to `DateTime`.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE `Paragraph` MODIFY `time` DATETIME NOT NULL;
|
||||||
@@ -15,11 +15,11 @@ model Paragraph {
|
|||||||
cover String?
|
cover String?
|
||||||
markdown Boolean?
|
markdown Boolean?
|
||||||
tags String
|
tags String
|
||||||
time DateTime @db.Date
|
time DateTime @db.DateTime
|
||||||
title String
|
title String
|
||||||
|
|
||||||
@@index([author])
|
@@index([author])
|
||||||
@@index([time])
|
@@index([time(order: desc)])
|
||||||
@@index([title])
|
@@index([title])
|
||||||
@@fulltext([content, author, title, tags])
|
@@fulltext([content, author, title, tags])
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user