Skip to content

✨added link shortner project #51

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions link-shortner/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# database
/prisma/db.sqlite
/prisma/db.sqlite-journal

# next.js
/.next/
/out/
next-env.d.ts

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# local env files
# 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
.env
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
28 changes: 28 additions & 0 deletions link-shortner/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Create T3 App

This is a [T3 Stack](https://create.t3.gg/) project bootstrapped with `create-t3-app`.

## What's next? How do I make an app with this?

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.

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.

- [Next.js](https://nextjs.org)
- [NextAuth.js](https://next-auth.js.org)
- [Prisma](https://prisma.io)
- [Tailwind CSS](https://tailwindcss.com)
- [tRPC](https://trpc.io)

## Learn More

To learn more about the [T3 Stack](https://create.t3.gg/), take a look at the following resources:

- [Documentation](https://create.t3.gg/)
- [Learn the T3 Stack](https://create.t3.gg/en/faq#what-learning-resources-are-currently-available) — Check out these awesome tutorials

You can check out the [create-t3-app GitHub repository](https://github.com/t3-oss/create-t3-app) — your feedback and contributions are welcome!

## How do I deploy this?

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.
Binary file added link-shortner/bun.lockb
Binary file not shown.
16 changes: 16 additions & 0 deletions link-shortner/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "src/styles/globals.css",
"baseColor": "slate",
"cssVariables": true
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils"
}
}
22 changes: 22 additions & 0 deletions link-shortner/next.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
* for Docker builds.
*/
await import("./src/env.mjs");

/** @type {import("next").NextConfig} */
const config = {
reactStrictMode: true,
// pageExtensions:['']
/**
* If you are using `appDir` then you must comment the below `i18n` config out.
*
* @see https://github.com/vercel/next.js/issues/41980
*/
i18n: {
locales: ["en"],
defaultLocale: "en",
},
};

export default config;
54 changes: 54 additions & 0 deletions link-shortner/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"name": "linkr",
"version": "0.1.0",
"private": true,
"scripts": {
"build": "next build",
"db:push": "prisma db push",
"dev": "next dev",
"postinstall": "prisma generate",
"lint": "next lint",
"start": "next start"
},
"dependencies": {
"@prisma/client": "^5.1.1",
"@radix-ui/react-slot": "^1.0.2",
"@t3-oss/env-nextjs": "^0.6.0",
"@tanstack/react-query": "^4.32.6",
"@trpc/client": "^10.37.1",
"@trpc/next": "^10.37.1",
"@trpc/react-query": "^10.37.1",
"@trpc/server": "^10.37.1",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"lucide-react": "^0.284.0",
"next": "^13.4.19",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hot-toast": "^2.4.1",
"superjson": "^1.13.1",
"tailwind-merge": "^1.14.0",
"tailwindcss-animate": "^1.0.7",
"zod": "^3.21.4"
},
"devDependencies": {
"@types/eslint": "^8.44.2",
"@types/node": "^18.16.0",
"@types/react": "^18.2.20",
"@types/react-dom": "^18.2.7",
"@typescript-eslint/eslint-plugin": "^6.3.0",
"@typescript-eslint/parser": "^6.3.0",
"autoprefixer": "^10.4.14",
"eslint": "^8.47.0",
"eslint-config-next": "^13.4.19",
"postcss": "^8.4.27",
"prettier": "^3.0.0",
"prettier-plugin-tailwindcss": "^0.5.1",
"prisma": "^5.1.1",
"tailwindcss": "^3.3.3",
"typescript": "^5.1.6"
},
"ct3aMetadata": {
"initVersion": "7.20.2"
}
}
8 changes: 8 additions & 0 deletions link-shortner/postcss.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const config = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};

module.exports = config;
6 changes: 6 additions & 0 deletions link-shortner/prettier.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/** @type {import('prettier').Config & import('prettier-plugin-tailwindcss').options} */
const config = {
plugins: ["prettier-plugin-tailwindcss"],
};

export default config;
21 changes: 21 additions & 0 deletions link-shortner/prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}

model Link {
id Int @id @default(autoincrement())
slug String @unique
url String @db.LongText
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

@@index([slug])
}
Binary file added link-shortner/public/favicon.ico
Binary file not shown.
56 changes: 56 additions & 0 deletions link-shortner/src/components/ui/button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";

import { cn } from "~/lib/utils";

const buttonVariants = cva(
"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",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline:
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
},
);

export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button";
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
);
},
);
Button.displayName = "Button";

export { Button, buttonVariants };
25 changes: 25 additions & 0 deletions link-shortner/src/components/ui/input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import * as React from "react";

import { cn } from "~/lib/utils";

export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {}

const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"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",
className,
)}
ref={ref}
{...props}
/>
);
},
);
Input.displayName = "Input";

export { Input };
45 changes: 45 additions & 0 deletions link-shortner/src/env.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";

export const env = createEnv({
/**
* Specify your server-side environment variables schema here. This way you can ensure the app
* isn't built with invalid env vars.
*/
server: {
DATABASE_URL: z
.string()
.url()
.refine(
(str) => !str.includes("YOUR_MYSQL_URL_HERE"),
"You forgot to change the default URL",
),
NODE_ENV: z
.enum(["development", "test", "production"])
.default("development"),
},

/**
* Specify your client-side environment variables schema here. This way you can ensure the app
* isn't built with invalid env vars. To expose them to the client, prefix them with
* `NEXT_PUBLIC_`.
*/
client: {
// NEXT_PUBLIC_CLIENTVAR: z.string().min(1),
},

/**
* You can't destruct `process.env` as a regular object in the Next.js edge runtimes (e.g.
* middlewares) or client-side so we need to destruct manually.
*/
runtimeEnv: {
DATABASE_URL: process.env.DATABASE_URL,
NODE_ENV: process.env.NODE_ENV,
// NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR,
},
/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially
* useful for Docker builds.
*/
skipValidation: !!process.env.SKIP_ENV_VALIDATION,
});
6 changes: 6 additions & 0 deletions link-shortner/src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
16 changes: 16 additions & 0 deletions link-shortner/src/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Link } from "@prisma/client";
import { NextResponse } from "next/server";
import { NextRequest } from "next/server";

// This function can be marked `async` if using `await` inside
export async function middleware(request: NextRequest) {
const slug = request.nextUrl.pathname.split("/").pop();
const link: Link = await (
await fetch(`${request.nextUrl.origin}/api/${slug}`)
).json();
return NextResponse.redirect(link.url);
}

export const config = {
matcher: ["/r/:slug*"],
};
3 changes: 3 additions & 0 deletions link-shortner/src/pages/404.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Custom404() {
return <h1>404 - Page Not Found</h1>;
}
18 changes: 18 additions & 0 deletions link-shortner/src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { type AppType } from "next/app";

import { api } from "~/utils/api";

import "~/styles/globals.css";

import { Toaster } from "react-hot-toast";

const MyApp: AppType = ({ Component, pageProps }) => {
return (
<>
<Component {...pageProps} />
<Toaster position="bottom-center" />
</>
);
};

export default api.withTRPC(MyApp);
16 changes: 16 additions & 0 deletions link-shortner/src/pages/api/[slug].ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { NextApiRequest, NextApiResponse } from "next";
import { db } from "~/server/db";

export default async function getSlug(
req: NextApiRequest,
res: NextApiResponse,
) {
const slug = req.query.slug;

const link = await db.link.findUnique({ where: { slug: slug as string } });
if (link == null) {
console.log("nonono");
res.status(404).send({ message: "not found" });
}
res.send(link);
}
Loading