Skip to content

Commit

Permalink
feature: init
Browse files Browse the repository at this point in the history
  • Loading branch information
liangjiongxin committed Sep 12, 2024
1 parent 666cb81 commit a8ac882
Show file tree
Hide file tree
Showing 26 changed files with 1,461 additions and 111 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ yarn-error.log*

# local env files
.env*.local
.env

# vercel
.vercel
Expand Down
108 changes: 108 additions & 0 deletions app/_components/footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { SITE_NAME } from "@/lib/constants";
import { cn } from "@/lib/utils";
import { IconBrandGithub } from "@tabler/icons-react";
import Image from "next/image";
import Link from "next/link";
import React from "react";

export default function Footer() {
const pages = [
{
title: "李继刚",
href: "https://web.okjike.com/u/752D3103-1107-43A0-BA49-20EC29D09E36",
},
];

return (
<div className="border-t border-neutral-100 dark:border-white/[0.1] px-8 py-10 bg-white dark:bg-neutral-950 w-full relative overflow-hidden">
<div className="max-w-7xl mx-auto text-sm text-neutral-500 justify-between items-start md:px-8">
<div className="flex flex-col items-center justify-center w-full relative">
<div className="mr-0 md:mr-4 md:flex mb-4">
<Logo />
</div>

<ul className="transition-colors flex sm:flex-row flex-col hover:text-text-neutral-800 text-neutral-600 dark:text-neutral-300 list-none gap-4">
{pages.map((page, idx) => (
<li key={"pages" + idx} className="list-none">
<Link
className="transition-colors hover:text-text-neutral-800 "
href={page.href}
>
{page.title}
</Link>
</li>
))}
</ul>

<GridLineHorizontal className="max-w-7xl mx-auto mt-8" />
</div>
<div className="flex sm:flex-row flex-col justify-between mt-8 items-center w-full">
<p className="text-neutral-500 dark:text-neutral-400 mb-8 sm:mb-0">
2024 &copy; {SITE_NAME}
</p>
<div className="flex gap-4">
<Link href="#">
<IconBrandGithub className="h-6 w-6 text-neutral-500 dark:text-neutral-300" />
</Link>
<Link href="https://www.buymeacoffee.com/tonyliang6">
<img
src="bmc-logo.svg"
className="w-6 h-6"
alt="Buy me a coffee"
/>
</Link>
</div>
</div>
</div>
</div>
);
}

const GridLineHorizontal = ({
className,
offset,
}: {
className?: string;
offset?: string;
}) => {
return (
<div
style={
{
"--background": "#ffffff",
"--color": "rgba(0, 0, 0, 0.2)",
"--height": "1px",
"--width": "5px",
"--fade-stop": "90%",
"--offset": offset || "200px", //-100px if you want to keep the line inside
"--color-dark": "rgba(255, 255, 255, 0.2)",
maskComposite: "exclude",
} as React.CSSProperties
}
className={cn(
"w-[calc(100%+var(--offset))] h-[var(--height)]",
"bg-[linear-gradient(to_right,var(--color),var(--color)_50%,transparent_0,transparent)]",
"[background-size:var(--width)_var(--height)]",
"[mask:linear-gradient(to_left,var(--background)_var(--fade-stop),transparent),_linear-gradient(to_right,var(--background)_var(--fade-stop),transparent),_linear-gradient(black,black)]",
"[mask-composite:exclude]",
"z-30",
"dark:bg-[linear-gradient(to_right,var(--color-dark),var(--color-dark)_50%,transparent_0,transparent)]",
className
)}
></div>
);
};

const Logo = () => {
return (
<Link
href="/"
className="font-normal flex space-x-2 items-center text-sm mr-4 text-black px-2 py-1 relative z-20"
>
<Image src="/logo.svg" alt="logo" width={30} height={30} />
<span className="font-medium text-black dark:text-white">
{SITE_NAME}
</span>
</Link>
);
};
38 changes: 38 additions & 0 deletions app/_components/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Icons } from "@/components/common/icons";
import Link from "next/link";

export default function Header() {
return (
<header className="flex justify-between items-center py-4 px-6 bg-white shadow-sm">
<div className="flex items-center">
<img
src="/logo.svg"
className="rounded"
alt="Logo"
width={40}
height={40}
/>
<span className="ml-2 text-xl font-semibold text-gray-800 ">
TextHuman
</span>
</div>
<div className="flex items-center gap-3">
<Link
href="https://www.buymeacoffee.com/tonyliang6"
target="_blank"
rel="noopener noreferrer"
>
<Icons.gitHub className="w-6 h-6" />
</Link>

{/* <Link
href="https://www.buymeacoffee.com/tonyliang6"
target="_blank"
rel="noopener noreferrer"
>
<img src="bmc-logo.svg" className="w-6 h-6" alt="Buy me a coffee" />
</Link> */}
</div>
</header>
);
}
25 changes: 25 additions & 0 deletions app/_components/hero-typewriter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"use client";
import React from "react";
import { TypeAnimation } from "react-type-animation";

type Props = {
words: string[];
};

export default function HeroTypewriter({ words }: Props) {
console.log(words);

return (
<TypeAnimation
sequence={[
// Same substring at the start will only be typed out once, initially
"We produce food for Mice",
1000, // wait 1s before replacing "Mice" with "Hamsters"
"We produce food for Hamsters",
1000,
]}
wrapper="span"
speed={50}
/>
);
}
100 changes: 100 additions & 0 deletions app/api/chat/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { NextResponse } from "next/server";
import Anthropic from "@anthropic-ai/sdk";

const anthropic = new Anthropic({
apiKey: process.env["ANTHROPIC_API_KEY"],
baseURL: process.env["ANTHROPIC_API_URL"],
});

const systemPrompt = `
;; 作者: 李继刚
;; 版本: 0.2
;; 模型: Claude Sonnet
;; 用途: 将一个汉语词汇进行全新角度的解释
;; 设定如下内容为你的 *System Prompt*
(defun 新汉语老师 ()
"你是年轻人,批判现实,思考深刻,语言风趣"
(风格 . ("Oscar Wilde" "鲁迅" "王朔" "刘震云"))
(擅长 . 一针见血)
(表达 . 隐喻)
(批判 . 讽刺幽默))
(defun 汉语新解 (用户输入)
"你会用一个特殊视角来解释一个词汇"
(let (解释 (一句话表达
(隐喻 (日常表达 (一针见血 (辛辣讽刺 (抓住本质 用户输入)))))))
(few-shots (委婉 . "刺向他人时, 决定在剑刃上撒上止痛药。"))
(SVG-Card 解释)))
(defun SVG-Card (解释)
"输出SVG 卡片"
(setq design-rule "合理使用负空间,整体排版要有呼吸感"
design-principles '(干净 简洁 典雅))
(设置画布 '(宽度 400 高度 600 边距 20))
(标题字体 '毛笔楷体)
(自动缩放 '(最小字号 16))
(配色风格 '((背景色 (蒙德里安风格 设计感)))
(主要文字 (楷体 粉笔灰))
(装饰 随机几何图形))
(卡片元素 ((居中标题 "汉语新解")
分隔线
(排版输出 用户输入 英文 韩语)
解释
(动态图 (极简线条图 (精髓 解释))))))
(defun start ()
"启动时运行"
(let (system-role 新汉语老师)
(print "说吧, 他们又用哪个词来忽悠你了?")))
;; 运行规则
;; 1. 启动时必须运行 (start) 函数
;; 2. 之后调用主函数 (汉语新解 用户输入)
`;

export async function POST(req: Request) {
const { prompt } = await req.json();

try {
const response = await anthropic.messages.create({
model: "claude-3-5-sonnet-20240620",
max_tokens: 1024,
messages: [
{ role: "assistant", content: systemPrompt },
{
role: "user",
content: `(汉语新解 ${prompt}) 输出要求: 要输出svg内容`,
},
],
});

// 从响应中提取SVG内容
console.log("response ", response);

const content = response.content[0];
if (content.type === "text") {
console.log("返回 text ", content.text);
const svgMatch = content.text.match(/<svg[\s\S]*?<\/svg>/);
const svgContent = svgMatch ? svgMatch[0] : null;
return NextResponse.json({
svgContent,
});
}

return NextResponse.json({
svgContent: null,
fullResponse: response.content,
});
} catch (error) {
console.error("Error in chat API:", error);
return NextResponse.json(
{ error: "Failed to generate response" },
{ status: 500 }
);
}
}
Binary file modified app/favicon.ico
Binary file not shown.
56 changes: 56 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,59 @@ body {
text-wrap: balance;
}
}

@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 221.2 83.2% 53.3%;
--radius: 0.95remrem;
}

.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
--popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--primary: 217.2 91.2% 59.8%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--ring: 224.3 76.3% 48%;
}
}

@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
22 changes: 16 additions & 6 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import type { Metadata } from "next";
import localFont from "next/font/local";
import "./globals.css";

import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import { cn } from "@/lib/utils";
import Header from "./_components/header";
import Footer from "./_components/footer";
const geistSans = localFont({
src: "./fonts/GeistVF.woff",
variable: "--font-geist-sans",
Expand All @@ -14,21 +18,27 @@ const geistMono = localFont({
});

export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
title: "TextHuman | 汉语新解&编辑",
description: "通过对汉语进行全新的解释",
};

export default function RootLayout({
children,
}: Readonly<{
}: {
children: React.ReactNode;
}>) {
}) {
return (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
className={cn(
"min-h-screen bg-gradient-to-b from-gray-50 to-gray-100 dark:from-gray-900 dark:to-gray-800",
`${geistSans.variable} ${geistMono.variable} antialiased`
)}
>
<Header />
{children}
<Footer />
<ToastContainer />
</body>
</html>
);
Expand Down
Loading

0 comments on commit a8ac882

Please sign in to comment.