Compare commits

..

3 Commits

Author SHA1 Message Date
AderKonstantin
181595f195 changed Upstash Redis to local Redis-server 2025-05-15 22:18:01 +03:00
AderKonstantin
3c6b449280 Добавил русский в навигацию nav 2025-05-15 21:53:14 +03:00
AderKonstantin
139ac3356d Добавил русский и свое название 2025-05-15 21:51:53 +03:00
11 changed files with 9977 additions and 2325 deletions

3
.env Normal file
View File

@ -0,0 +1,3 @@
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD= # если используется

View File

@ -1,2 +0,0 @@
UPSTASH_REDIS_REST_URL=
UPSTASH_REDIS_REST_TOKEN=

View File

@ -32,13 +32,13 @@ export const Navigation: React.FC = () => {
href="/projects"
className="duration-200 text-zinc-400 hover:text-zinc-100"
>
Projects
Проекты
</Link>
<Link
href="/contact"
className="duration-200 text-zinc-400 hover:text-zinc-100"
>
Contact
Контакты
</Link>
</div>

View File

@ -3,8 +3,8 @@ import React from "react";
import Particles from "./components/particles";
const navigation = [
{ name: "Projects", href: "/projects" },
{ name: "Contact", href: "/contact" },
{ name: "Проекты", href: "/projects" },
{ name: "Контакты", href: "/contact" },
];
export default function Home() {
@ -29,7 +29,7 @@ export default function Home() {
quantity={100}
/>
<h1 className="py-3.5 px-0.5 z-10 text-4xl text-transparent duration-1000 bg-white cursor-default text-edge-outline animate-title font-display sm:text-6xl md:text-9xl whitespace-nowrap bg-clip-text ">
chronark
aderk.tech
</h1>
<div className="hidden w-screen h-px animate-glow md:block animate-fade-right bg-gradient-to-r from-zinc-300/0 via-zinc-300/50 to-zinc-300/0" />

View File

@ -4,7 +4,7 @@ import { Mdx } from "@/app/components/mdx";
import { Header } from "./header";
import "./mdx.css";
import { ReportView } from "./view";
import { Redis } from "@upstash/redis";
import Redis from "ioredis";
export const revalidate = 60;
@ -14,7 +14,12 @@ type Props = {
};
};
const redis = Redis.fromEnv();
// Настройка подключения к локальному Redis
const redis = new Redis({
host: process.env.REDIS_HOST || "localhost",
port: parseInt(process.env.REDIS_PORT || "6379"),
password: process.env.REDIS_PASSWORD,
});
export async function generateStaticParams(): Promise<Props["params"][]> {
return allProjects
@ -32,8 +37,11 @@ export default async function PostPage({ params }: Props) {
notFound();
}
const views =
(await redis.get<number>(["pageviews", "projects", slug].join(":"))) ?? 0;
// Получаем и преобразуем значение просмотров
const views = parseInt(
(await redis.get(`projects:${slug}:views`)) || "0",
10
);
return (
<div className="bg-zinc-50 min-h-screen">

View File

@ -4,19 +4,24 @@ import { allProjects } from "contentlayer/generated";
import { Navigation } from "../components/nav";
import { Card } from "../components/card";
import { Article } from "./article";
import { Redis } from "@upstash/redis";
import Redis from "ioredis"; // Заменяем @upstash/redis на ioredis
import { Eye } from "lucide-react";
const redis = Redis.fromEnv();
// Создаем подключение к локальному Redis
const redis = new Redis({
host: process.env.REDIS_HOST || "localhost",
port: parseInt(process.env.REDIS_PORT || "6379"),
password: process.env.REDIS_PASSWORD, // если есть пароль
});
export const revalidate = 60;
export default async function ProjectsPage() {
const views = (
await redis.mget<number[]>(
...allProjects.map((p) => ["pageviews", "projects", p.slug].join(":")),
)
).reduce((acc, v, i) => {
acc[allProjects[i].slug] = v ?? 0;
const viewsEntries = await redis.mget(
...allProjects.map((p) => `projects:${p.slug}:views`)
);
const views = allProjects.reduce((acc, project, index) => {
acc[project.slug] = parseInt(viewsEntries[index] as string) || 0;
return acc;
}, {} as Record<string, number>);

11
content/projects/bog.mdx Normal file
View File

@ -0,0 +1,11 @@
---
title: bitofgame.net
description: bitofgame.net is an open source API Key management solution. It allows you to create, manage and validate API Keys for your users.
date: "2025-07-01"
url: https://unkey.dev
published: true
repository: chronark/unkey
---
Unkey is an open source API Key management solution. It allows you to create, manage and validate API Keys for your users. Its built with security and speed in mind.

6976
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,7 @@
"@upstash/redis": "^1.23.3",
"contentlayer": "^0.3.4",
"framer-motion": "^10.16.4",
"ioredis": "^5.6.1",
"lucide-react": "^0.284.0",
"markdown-wasm": "^1.2.0",
"next": "^13.5.4",

View File

@ -1,9 +1,15 @@
import { Redis } from "@upstash/redis";
import Redis from "ioredis";
import { NextRequest, NextResponse } from "next/server";
const redis = Redis.fromEnv();
// Настройка подключения к локальному Redis
const redis = new Redis({
host: process.env.REDIS_HOST || "localhost",
port: parseInt(process.env.REDIS_PORT || "6379"),
password: process.env.REDIS_PASSWORD,
});
export const config = {
runtime: "edge",
runtime: "edge", // Возможно потребуется изменить на "nodejs" если возникнут проблемы
};
export default async function incr(req: NextRequest): Promise<NextResponse> {
@ -15,33 +21,33 @@ export default async function incr(req: NextRequest): Promise<NextResponse> {
}
const body = await req.json();
let slug: string | undefined = undefined;
if ("slug" in body) {
slug = body.slug;
}
const slug = body.slug;
if (!slug) {
return new NextResponse("Slug not found", { status: 400 });
}
const ip = req.ip;
if (ip) {
// Hash the IP in order to not store it directly in your db.
// Хеширование IP-адреса
const buf = await crypto.subtle.digest(
"SHA-256",
new TextEncoder().encode(ip),
new TextEncoder().encode(ip)
);
const hash = Array.from(new Uint8Array(buf))
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
// deduplicate the ip for each slug
const isNew = await redis.set(["deduplicate", hash, slug].join(":"), true, {
nx: true,
ex: 24 * 60 * 60,
});
// Проверка уникальности посещения
const key = `deduplicate:${hash}:${slug}`;
const isNew = await redis.set(key, "1", "EX", 86400, "NX");
if (!isNew) {
new NextResponse(null, { status: 202 });
return new NextResponse(null, { status: 202 });
}
}
await redis.incr(["pageviews", "projects", slug].join(":"));
// Увеличиваем счетчик просмотров
await redis.incr(`projects:${slug}:views`);
return new NextResponse(null, { status: 202 });
}

5220
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff