Skip to content

Commit c2f5349

Browse files
authored
Link shortner (#78)
* ✨added link shortner project * renamed the project folder * changed the foldername * ✨ renamed the project
1 parent a823bc3 commit c2f5349

29 files changed

+874
-0
lines changed

Link Shortner/.gitignore

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# database
12+
/prisma/db.sqlite
13+
/prisma/db.sqlite-journal
14+
15+
# next.js
16+
/.next/
17+
/out/
18+
next-env.d.ts
19+
20+
# production
21+
/build
22+
23+
# misc
24+
.DS_Store
25+
*.pem
26+
27+
# debug
28+
npm-debug.log*
29+
yarn-debug.log*
30+
yarn-error.log*
31+
.pnpm-debug.log*
32+
33+
# local env files
34+
# do not commit any .env files to git, except for the .env.example file. https://create.t3.gg/en/usage/env-variables#using-environment-variables
35+
.env
36+
.env*.local
37+
38+
# vercel
39+
.vercel
40+
41+
# typescript
42+
*.tsbuildinfo

Link Shortner/README.md

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Create T3 App
2+
3+
This is a [T3 Stack](https://create.t3.gg/) project bootstrapped with `create-t3-app`.
4+
5+
## What's next? How do I make an app with this?
6+
7+
We try to keep this project as simple as possible, so you can start with just the scaffolding we set up for you, and add additional things later when they become necessary.
8+
9+
If you are not familiar with the different technologies used in this project, please refer to the respective docs. If you still are in the wind, please join our [Discord](https://t3.gg/discord) and ask for help.
10+
11+
- [Next.js](https://nextjs.org)
12+
- [NextAuth.js](https://next-auth.js.org)
13+
- [Prisma](https://prisma.io)
14+
- [Tailwind CSS](https://tailwindcss.com)
15+
- [tRPC](https://trpc.io)
16+
17+
## Learn More
18+
19+
To learn more about the [T3 Stack](https://create.t3.gg/), take a look at the following resources:
20+
21+
- [Documentation](https://create.t3.gg/)
22+
- [Learn the T3 Stack](https://create.t3.gg/en/faq#what-learning-resources-are-currently-available) — Check out these awesome tutorials
23+
24+
You can check out the [create-t3-app GitHub repository](https://github.com/t3-oss/create-t3-app) — your feedback and contributions are welcome!
25+
26+
## How do I deploy this?
27+
28+
Follow our deployment guides for [Vercel](https://create.t3.gg/en/deployment/vercel), [Netlify](https://create.t3.gg/en/deployment/netlify) and [Docker](https://create.t3.gg/en/deployment/docker) for more information.

Link Shortner/bun.lockb

146 KB
Binary file not shown.

Link Shortner/components.json

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"$schema": "https://ui.shadcn.com/schema.json",
3+
"style": "default",
4+
"rsc": false,
5+
"tsx": true,
6+
"tailwind": {
7+
"config": "tailwind.config.js",
8+
"css": "src/styles/globals.css",
9+
"baseColor": "slate",
10+
"cssVariables": true
11+
},
12+
"aliases": {
13+
"components": "@/components",
14+
"utils": "@/lib/utils"
15+
}
16+
}

Link Shortner/next.config.mjs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
3+
* for Docker builds.
4+
*/
5+
await import("./src/env.mjs");
6+
7+
/** @type {import("next").NextConfig} */
8+
const config = {
9+
reactStrictMode: true,
10+
// pageExtensions:['']
11+
/**
12+
* If you are using `appDir` then you must comment the below `i18n` config out.
13+
*
14+
* @see https://github.com/vercel/next.js/issues/41980
15+
*/
16+
i18n: {
17+
locales: ["en"],
18+
defaultLocale: "en",
19+
},
20+
};
21+
22+
export default config;

Link Shortner/package.json

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
"name": "linkr",
3+
"version": "0.1.0",
4+
"private": true,
5+
"scripts": {
6+
"build": "next build",
7+
"db:push": "prisma db push",
8+
"dev": "next dev",
9+
"postinstall": "prisma generate",
10+
"lint": "next lint",
11+
"start": "next start"
12+
},
13+
"dependencies": {
14+
"@prisma/client": "^5.1.1",
15+
"@radix-ui/react-slot": "^1.0.2",
16+
"@t3-oss/env-nextjs": "^0.6.0",
17+
"@tanstack/react-query": "^4.32.6",
18+
"@trpc/client": "^10.37.1",
19+
"@trpc/next": "^10.37.1",
20+
"@trpc/react-query": "^10.37.1",
21+
"@trpc/server": "^10.37.1",
22+
"class-variance-authority": "^0.7.0",
23+
"clsx": "^2.0.0",
24+
"lucide-react": "^0.284.0",
25+
"next": "^13.4.19",
26+
"react": "18.2.0",
27+
"react-dom": "18.2.0",
28+
"react-hot-toast": "^2.4.1",
29+
"superjson": "^1.13.1",
30+
"tailwind-merge": "^1.14.0",
31+
"tailwindcss-animate": "^1.0.7",
32+
"zod": "^3.21.4"
33+
},
34+
"devDependencies": {
35+
"@types/eslint": "^8.44.2",
36+
"@types/node": "^18.16.0",
37+
"@types/react": "^18.2.20",
38+
"@types/react-dom": "^18.2.7",
39+
"@typescript-eslint/eslint-plugin": "^6.3.0",
40+
"@typescript-eslint/parser": "^6.3.0",
41+
"autoprefixer": "^10.4.14",
42+
"eslint": "^8.47.0",
43+
"eslint-config-next": "^13.4.19",
44+
"postcss": "^8.4.27",
45+
"prettier": "^3.0.0",
46+
"prettier-plugin-tailwindcss": "^0.5.1",
47+
"prisma": "^5.1.1",
48+
"tailwindcss": "^3.3.3",
49+
"typescript": "^5.1.6"
50+
},
51+
"ct3aMetadata": {
52+
"initVersion": "7.20.2"
53+
}
54+
}

Link Shortner/postcss.config.cjs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const config = {
2+
plugins: {
3+
tailwindcss: {},
4+
autoprefixer: {},
5+
},
6+
};
7+
8+
module.exports = config;

Link Shortner/prettier.config.mjs

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/** @type {import('prettier').Config & import('prettier-plugin-tailwindcss').options} */
2+
const config = {
3+
plugins: ["prettier-plugin-tailwindcss"],
4+
};
5+
6+
export default config;

Link Shortner/prisma/schema.prisma

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// This is your Prisma schema file,
2+
// learn more about it in the docs: https://pris.ly/d/prisma-schema
3+
4+
generator client {
5+
provider = "prisma-client-js"
6+
}
7+
8+
datasource db {
9+
provider = "mysql"
10+
url = env("DATABASE_URL")
11+
}
12+
13+
model Link {
14+
id Int @id @default(autoincrement())
15+
slug String @unique
16+
url String @db.LongText
17+
createdAt DateTime @default(now())
18+
updatedAt DateTime @updatedAt
19+
20+
@@index([slug])
21+
}

Link Shortner/public/favicon.ico

15 KB
Binary file not shown.
+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import * as React from "react";
2+
import { Slot } from "@radix-ui/react-slot";
3+
import { cva, type VariantProps } from "class-variance-authority";
4+
5+
import { cn } from "~/lib/utils";
6+
7+
const buttonVariants = cva(
8+
"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
9+
{
10+
variants: {
11+
variant: {
12+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
13+
destructive:
14+
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
15+
outline:
16+
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
17+
secondary:
18+
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
19+
ghost: "hover:bg-accent hover:text-accent-foreground",
20+
link: "text-primary underline-offset-4 hover:underline",
21+
},
22+
size: {
23+
default: "h-10 px-4 py-2",
24+
sm: "h-9 rounded-md px-3",
25+
lg: "h-11 rounded-md px-8",
26+
icon: "h-10 w-10",
27+
},
28+
},
29+
defaultVariants: {
30+
variant: "default",
31+
size: "default",
32+
},
33+
},
34+
);
35+
36+
export interface ButtonProps
37+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
38+
VariantProps<typeof buttonVariants> {
39+
asChild?: boolean;
40+
}
41+
42+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
43+
({ className, variant, size, asChild = false, ...props }, ref) => {
44+
const Comp = asChild ? Slot : "button";
45+
return (
46+
<Comp
47+
className={cn(buttonVariants({ variant, size, className }))}
48+
ref={ref}
49+
{...props}
50+
/>
51+
);
52+
},
53+
);
54+
Button.displayName = "Button";
55+
56+
export { Button, buttonVariants };
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import * as React from "react";
2+
3+
import { cn } from "~/lib/utils";
4+
5+
export interface InputProps
6+
extends React.InputHTMLAttributes<HTMLInputElement> {}
7+
8+
const Input = React.forwardRef<HTMLInputElement, InputProps>(
9+
({ className, type, ...props }, ref) => {
10+
return (
11+
<input
12+
type={type}
13+
className={cn(
14+
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
15+
className,
16+
)}
17+
ref={ref}
18+
{...props}
19+
/>
20+
);
21+
},
22+
);
23+
Input.displayName = "Input";
24+
25+
export { Input };

Link Shortner/src/env.mjs

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { createEnv } from "@t3-oss/env-nextjs";
2+
import { z } from "zod";
3+
4+
export const env = createEnv({
5+
/**
6+
* Specify your server-side environment variables schema here. This way you can ensure the app
7+
* isn't built with invalid env vars.
8+
*/
9+
server: {
10+
DATABASE_URL: z
11+
.string()
12+
.url()
13+
.refine(
14+
(str) => !str.includes("YOUR_MYSQL_URL_HERE"),
15+
"You forgot to change the default URL",
16+
),
17+
NODE_ENV: z
18+
.enum(["development", "test", "production"])
19+
.default("development"),
20+
},
21+
22+
/**
23+
* Specify your client-side environment variables schema here. This way you can ensure the app
24+
* isn't built with invalid env vars. To expose them to the client, prefix them with
25+
* `NEXT_PUBLIC_`.
26+
*/
27+
client: {
28+
// NEXT_PUBLIC_CLIENTVAR: z.string().min(1),
29+
},
30+
31+
/**
32+
* You can't destruct `process.env` as a regular object in the Next.js edge runtimes (e.g.
33+
* middlewares) or client-side so we need to destruct manually.
34+
*/
35+
runtimeEnv: {
36+
DATABASE_URL: process.env.DATABASE_URL,
37+
NODE_ENV: process.env.NODE_ENV,
38+
// NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR,
39+
},
40+
/**
41+
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially
42+
* useful for Docker builds.
43+
*/
44+
skipValidation: !!process.env.SKIP_ENV_VALIDATION,
45+
});

Link Shortner/src/lib/utils.ts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { type ClassValue, clsx } from "clsx";
2+
import { twMerge } from "tailwind-merge";
3+
4+
export function cn(...inputs: ClassValue[]) {
5+
return twMerge(clsx(inputs));
6+
}

Link Shortner/src/middleware.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Link } from "@prisma/client";
2+
import { NextResponse } from "next/server";
3+
import { NextRequest } from "next/server";
4+
5+
// This function can be marked `async` if using `await` inside
6+
export async function middleware(request: NextRequest) {
7+
const slug = request.nextUrl.pathname.split("/").pop();
8+
const link: Link = await (
9+
await fetch(`${request.nextUrl.origin}/api/${slug}`)
10+
).json();
11+
return NextResponse.redirect(link.url);
12+
}
13+
14+
export const config = {
15+
matcher: ["/r/:slug*"],
16+
};

Link Shortner/src/pages/404.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function Custom404() {
2+
return <h1>404 - Page Not Found</h1>;
3+
}

Link Shortner/src/pages/_app.tsx

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { type AppType } from "next/app";
2+
3+
import { api } from "~/utils/api";
4+
5+
import "~/styles/globals.css";
6+
7+
import { Toaster } from "react-hot-toast";
8+
9+
const MyApp: AppType = ({ Component, pageProps }) => {
10+
return (
11+
<>
12+
<Component {...pageProps} />
13+
<Toaster position="bottom-center" />
14+
</>
15+
);
16+
};
17+
18+
export default api.withTRPC(MyApp);

Link Shortner/src/pages/api/[slug].ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { NextApiRequest, NextApiResponse } from "next";
2+
import { db } from "~/server/db";
3+
4+
export default async function getSlug(
5+
req: NextApiRequest,
6+
res: NextApiResponse,
7+
) {
8+
const slug = req.query.slug;
9+
10+
const link = await db.link.findUnique({ where: { slug: slug as string } });
11+
if (link == null) {
12+
console.log("nonono");
13+
res.status(404).send({ message: "not found" });
14+
}
15+
res.send(link);
16+
}

0 commit comments

Comments
 (0)