♻️ Use sanity
This commit is contained in:
17
app/console/[[...index]]/page.tsx
Normal file
17
app/console/[[...index]]/page.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
'use client'
|
||||
|
||||
/**
|
||||
* This route is responsible for the built-in authoring environment using Sanity Studio.
|
||||
* All routes under your studio path is handled by this file using Next.js' catch-all routes:
|
||||
* https://nextjs.org/docs/routing/dynamic-routes#catch-all-routes
|
||||
*
|
||||
* You can learn more about the next-sanity package here:
|
||||
* https://github.com/sanity-io/next-sanity
|
||||
*/
|
||||
|
||||
import { NextStudio } from 'next-sanity/studio'
|
||||
import config from '../../../sanity.config'
|
||||
|
||||
export default function StudioPage() {
|
||||
return <NextStudio config={config} />
|
||||
}
|
@ -12,10 +12,20 @@ export interface RelatedAccount {
|
||||
|
||||
export const SITE_NAME = "Goatshed";
|
||||
export const SITE_DESCRIPTION = "山羊寒舍,在这里最终智羊工作室的最新动态。";
|
||||
export const SITE_URL = "https://smartsheep.studio"
|
||||
export const SITE_URL = "https://smartsheep.studio";
|
||||
|
||||
export const RELATED_ACCOUNTS: RelatedAccount[] = [
|
||||
{ icon: <GitHubIcon />, platform: "GitHub", accountName: "@smartsheep-hq", link: "https://github.com/smartsheep-hq" },
|
||||
{ icon: <TwitterIcon />, platform: "Twitter", accountName: "@littlesheepovo", link: "https://twitter.com/littlesheepovo" },
|
||||
{ icon: <CoffeeIcon />, platform: "Ko-fi", accountName: "@littlesheep2code", link: "https://ko-fi.com/littlesheep2code" },
|
||||
];
|
||||
{
|
||||
icon: <TwitterIcon />,
|
||||
platform: "Twitter",
|
||||
accountName: "@littlesheepovo",
|
||||
link: "https://twitter.com/littlesheepovo",
|
||||
},
|
||||
{
|
||||
icon: <CoffeeIcon />,
|
||||
platform: "Ko-fi",
|
||||
accountName: "@littlesheep2code",
|
||||
link: "https://ko-fi.com/littlesheep2code",
|
||||
},
|
||||
];
|
||||
|
@ -8,7 +8,7 @@ export async function GET() {
|
||||
description: SITE_DESCRIPTION,
|
||||
site_url: SITE_URL,
|
||||
feed_url: `${SITE_URL}/feed`,
|
||||
language: "zh-CN"
|
||||
language: "zh-CN",
|
||||
});
|
||||
|
||||
getSortedPosts().forEach((item) => {
|
||||
@ -22,7 +22,7 @@ export async function GET() {
|
||||
|
||||
return new Response(feed.xml(), {
|
||||
headers: {
|
||||
"content-type": "application/xml"
|
||||
}
|
||||
"content-type": "application/xml",
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@tailwind utilities;
|
||||
|
@ -14,6 +14,7 @@ import "@fontsource/roboto/700.css";
|
||||
import "./globals.css";
|
||||
|
||||
import AppShell from "@/components/AppShell";
|
||||
import NextTopLoader from "nextjs-toploader";
|
||||
|
||||
export const runtime = "edge";
|
||||
|
||||
@ -33,6 +34,7 @@ export default function RootLayout({ children }: Readonly<{
|
||||
<body>
|
||||
<AppRouterCacheProvider>
|
||||
<CssBaseline />
|
||||
<NextTopLoader showAtBottom color="#4a5099" />
|
||||
<ThemeProvider theme={theme}>
|
||||
<AppShell>{children}</AppShell>
|
||||
</ThemeProvider>
|
||||
|
31
app/page.tsx
31
app/page.tsx
@ -2,14 +2,15 @@ import {
|
||||
Avatar,
|
||||
Box,
|
||||
Button,
|
||||
Card, colors,
|
||||
Card,
|
||||
colors,
|
||||
Container,
|
||||
Grid,
|
||||
List,
|
||||
ListItemAvatar,
|
||||
ListItemButton,
|
||||
ListItemText,
|
||||
Typography
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { RELATED_ACCOUNTS } from "@/app/consts";
|
||||
import Image from "next/image";
|
||||
@ -18,19 +19,18 @@ import Link from "next/link";
|
||||
export default function Home() {
|
||||
return (
|
||||
<Container sx={{ scrollBehavior: "smooth", px: 5 }}>
|
||||
<Grid
|
||||
container
|
||||
id="introduce"
|
||||
alignItems="center"
|
||||
sx={{ height: "calc(100vh - 64px)" }}
|
||||
>
|
||||
<Grid container id="introduce" alignItems="center" sx={{ height: "calc(100vh - 64px)" }}>
|
||||
<Grid item xs={12} sm={6} sx={{ textAlign: { xs: "center", sm: "initial" } }}>
|
||||
<Typography variant="h1" gutterBottom>你好呀 👋</Typography>
|
||||
<Typography variant="h1" gutterBottom>
|
||||
你好呀 👋
|
||||
</Typography>
|
||||
<Typography paragraph>
|
||||
欢迎来到 SmartSheep Studio 的官方网站!在这里了解,订阅,跟踪我们的最新消息。
|
||||
接触我们最大的官方社区,并且尝试最新产品,参与各种活动,提供反馈,让我们更好的服务您。
|
||||
</Typography>
|
||||
<Button variant="contained" href="#about-us" size="large">探索更多</Button>
|
||||
<Button variant="contained" href="#about-us" size="large">
|
||||
探索更多
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid
|
||||
item
|
||||
@ -44,12 +44,7 @@ export default function Home() {
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
container
|
||||
id="about-us"
|
||||
alignItems="center"
|
||||
sx={{ height: "calc(100vh - 64px)" }}
|
||||
>
|
||||
<Grid container id="about-us" alignItems="center" sx={{ height: "calc(100vh - 64px)" }}>
|
||||
<Grid item xs={12} sm={6} sx={{ display: "flex", justifyContent: { xs: "center", sm: "end" } }}>
|
||||
<Card sx={{ flexGrow: 1, mr: { xs: 0, sm: 4, md: 8 } }}>
|
||||
<List sx={{ width: "100%", bgcolor: "background.paper" }}>
|
||||
@ -67,7 +62,9 @@ export default function Home() {
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} sx={{ textAlign: { xs: "center", sm: "initial" } }}>
|
||||
<Typography variant="h1" gutterBottom>关于我们</Typography>
|
||||
<Typography variant="h1" gutterBottom>
|
||||
关于我们
|
||||
</Typography>
|
||||
<Typography paragraph>
|
||||
我们是一群充满活力、对开源充满热情的开发者。成立于 2019 年。自那年起我们一直在开发让人喜欢的开源软件。
|
||||
在我们这里,“取之于开源,用之于开源” 不仅是原则,更是我们信仰的座右铭。
|
||||
|
@ -1,20 +1,32 @@
|
||||
import { Box, Card, CardContent, CardMedia, Divider, Typography } from "@mui/material";
|
||||
import { getSinglePost } from "@/content/posts";
|
||||
import Image from "next/image";
|
||||
import { Box, Card, CardContent, CardMedia, Chip, Divider, Stack, Typography } from "@mui/material";
|
||||
import { client } from "@/sanity/lib/client";
|
||||
import PostContent from "@/components/posts/PostContent";
|
||||
import Image from "next/image";
|
||||
|
||||
export default function PostDetailPage({ params }: { params: { id: string } }) {
|
||||
const post = getSinglePost(params.id);
|
||||
export default async function PostDetailPage({ params }: { params: { id: string } }) {
|
||||
const post = await client.fetch<any>(`*[_type == "post" && slug.current == $slug][0] {
|
||||
title, description, slug, body, author, publishedAt,
|
||||
mainImage {
|
||||
asset -> {
|
||||
_id,
|
||||
url
|
||||
},
|
||||
alt
|
||||
},
|
||||
"categories": categories[]->title,
|
||||
"author_name": author->name,
|
||||
"author_image": author->image
|
||||
}`, { slug: params.id });
|
||||
|
||||
return (
|
||||
<Card>
|
||||
{
|
||||
post.thumbnail &&
|
||||
<CardMedia sx={{ height: 360, position: "relative" }} title={post.title}>
|
||||
post.mainImage &&
|
||||
<CardMedia sx={{ height: 360, position: "relative" }} title={post.mainImage.alt}>
|
||||
<Image
|
||||
fill
|
||||
src={post.thumbnail}
|
||||
alt={post.title}
|
||||
src={post.mainImage.asset.url}
|
||||
alt={post.mainImage.alt}
|
||||
style={{ objectFit: "cover" }}
|
||||
/>
|
||||
</CardMedia>
|
||||
@ -22,18 +34,22 @@ export default function PostDetailPage({ params }: { params: { id: string } }) {
|
||||
|
||||
<CardContent sx={{ paddingX: 5, paddingY: 3 }}>
|
||||
<Box>
|
||||
<Typography gutterBottom variant="h2">
|
||||
<Typography variant="h2">
|
||||
{post.title}
|
||||
</Typography>
|
||||
|
||||
<Stack direction="row" sx={{ mx: -0.5, mt: 1, mb: 1.2 }}>
|
||||
{post.categories.map((category: string, idx: number) => <Chip size="small" label={category} key={idx} />)}
|
||||
</Stack>
|
||||
<Typography color="text.secondary" variant="body2">
|
||||
{post.description ?? "No description yet."}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Divider sx={{ my: 5 }} />
|
||||
<Divider sx={{ my: 2.5, mx: -5 }} />
|
||||
<Box component="article" className="prose max-w-none" sx={{ minWidth: 0 }}>
|
||||
<PostContent content={post.content ?? ""} />
|
||||
<PostContent content={post.body} />
|
||||
</Box>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { Box, Container } from "@mui/material";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
export default function PostLayout({children}: Readonly<{
|
||||
export default function PostLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<Container sx={{ display: "flex", justifyContent: "center", gap: 4, py: 2 }}>
|
||||
<Box sx={{ flexGrow: 1, maxWidth: 720 }}>
|
||||
{children}
|
||||
</Box>
|
||||
<Box sx={{ flexGrow: 1, maxWidth: 720 }}>{children}</Box>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -1,36 +1,52 @@
|
||||
import { Button, Card, CardActions, CardContent, CardMedia, Typography } from "@mui/material";
|
||||
import { getSortedPosts } from "@/content/posts";
|
||||
import { Button, Card, CardActions, CardContent, CardMedia, Chip, Stack, Typography } from "@mui/material";
|
||||
import { client } from "@/sanity/lib/client";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function PostList() {
|
||||
const posts = getSortedPosts();
|
||||
export default async function PostList() {
|
||||
const posts = await client.fetch<any[]>(`*[_type == "post"] {
|
||||
title, description, slug, author, publishedAt,
|
||||
mainImage {
|
||||
asset -> {
|
||||
_id,
|
||||
url
|
||||
},
|
||||
alt
|
||||
},
|
||||
"categories": categories[]->title,
|
||||
"author_name": author->name,
|
||||
"author_image": author->image
|
||||
}`);
|
||||
|
||||
return (
|
||||
posts.map((post) => (
|
||||
<Card key={post.id} sx={{ width: "100%" }}>
|
||||
<Card key={post.slug.current} sx={{ width: "100%" }}>
|
||||
{
|
||||
post.thumbnail &&
|
||||
<CardMedia sx={{ height: 160, position: "relative" }} title={post.title}>
|
||||
post.mainImage &&
|
||||
<CardMedia sx={{ height: 160, position: "relative" }} title={post.mainImage.alt}>
|
||||
<Image
|
||||
fill
|
||||
src={post.thumbnail}
|
||||
alt={post.title}
|
||||
src={post.mainImage.asset.url}
|
||||
alt={post.mainImage.alt}
|
||||
style={{ objectFit: "cover" }}
|
||||
/>
|
||||
</CardMedia>
|
||||
}
|
||||
|
||||
<CardContent sx={{ paddingX: 5, paddingY: 3 }}>
|
||||
<Typography gutterBottom variant="h3">
|
||||
<Typography variant="h3">
|
||||
{post.title}
|
||||
</Typography>
|
||||
|
||||
<Stack direction="row" sx={{ mx: -0.5, mt: 1, mb: 1.2 }}>
|
||||
{post.categories.map((category: string, idx: number) => <Chip size="small" label={category} key={idx} />)}
|
||||
</Stack>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{post.description ?? "No description yet."}
|
||||
{post.description ? post.description : "No description yet."}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
<CardActions sx={{ paddingX: 4, paddingBottom: 2 }}>
|
||||
<Link href={`/p/${post.id}`} passHref>
|
||||
<Link href={`/p/${post.slug.current}`} passHref>
|
||||
<Button>Read more</Button>
|
||||
</Link>
|
||||
</CardActions>
|
||||
|
@ -10,20 +10,20 @@ export default function sitemap(): MetadataRoute.Sitemap {
|
||||
url: `${SITE_URL}/`,
|
||||
lastModified: new Date(),
|
||||
changeFrequency: "weekly",
|
||||
priority: 1
|
||||
priority: 1,
|
||||
},
|
||||
{
|
||||
url: `${SITE_URL}/posts`,
|
||||
lastModified: new Date(),
|
||||
changeFrequency: "daily",
|
||||
priority: 0.8
|
||||
priority: 0.8,
|
||||
},
|
||||
|
||||
...posts.map((item: Post) => ({
|
||||
url: `${SITE_URL}/posts/${item.id}`,
|
||||
lastModified: item.date,
|
||||
changeFrequency: "daily" as any,
|
||||
priority: 0.75
|
||||
}))
|
||||
priority: 0.75,
|
||||
})),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,11 @@ import { createTheme } from "@mui/material/styles";
|
||||
export const theme = createTheme({
|
||||
palette: {
|
||||
primary: {
|
||||
main: "#49509e"
|
||||
main: "#49509e",
|
||||
},
|
||||
secondary: {
|
||||
main: "#d43630"
|
||||
}
|
||||
main: "#d43630",
|
||||
},
|
||||
},
|
||||
typography: {
|
||||
h1: { fontSize: "2.5rem" },
|
||||
|
Reference in New Issue
Block a user