Skip to content

Commit

Permalink
feat: initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
iShibi committed Mar 7, 2024
0 parents commit 9f6f7ae
Show file tree
Hide file tree
Showing 24 changed files with 374 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto eol=lf
33 changes: 33 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Deploy
on:
push:
branches: [main]
pull_request:
branches: main

jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest

permissions:
id-token: write # Needed for auth with Deno Deploy
contents: read # Needed to clone the repository

steps:
- name: Clone repository
uses: actions/checkout@v4

- name: Install Deno
uses: denoland/setup-deno@v1
with:
deno-version: v1.x

- name: Build step
run: "deno task build" # 📝 Update the build command(s) if necessary

- name: Upload to Deno Deploy
uses: denoland/deployctl@v1
with:
project: "example-project" # 📝 Update the deploy project name if necessary
entrypoint: "./main.ts" # 📝 Update the entrypoint if necessary
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# Fresh build directory
_fresh/
# npm dependencies
node_modules/
6 changes: 6 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"recommendations": [
"denoland.vscode-deno",
"bradlc.vscode-tailwindcss"
]
}
21 changes: 21 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"deno.enable": true,
"deno.lint": true,
"editor.defaultFormatter": "denoland.vscode-deno",
"[typescriptreact]": {
"editor.defaultFormatter": "denoland.vscode-deno"
},
"[typescript]": {
"editor.defaultFormatter": "denoland.vscode-deno"
},
"[javascriptreact]": {
"editor.defaultFormatter": "denoland.vscode-deno"
},
"[javascript]": {
"editor.defaultFormatter": "denoland.vscode-deno"
},
"css.customData": [
".vscode/tailwind.json"
],
"deno.unstable": true,
}
55 changes: 55 additions & 0 deletions .vscode/tailwind.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"version": 1.1,
"atDirectives": [
{
"name": "@tailwind",
"description": "Use the `@tailwind` directive to insert Tailwind's `base`, `components`, `utilities` and `screens` styles into your CSS.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#tailwind"
}
]
},
{
"name": "@apply",
"description": "Use the `@apply` directive to inline any existing utility classes into your own custom CSS. This is useful when you find a common utility pattern in your HTML that you’d like to extract to a new component.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#apply"
}
]
},
{
"name": "@responsive",
"description": "You can generate responsive variants of your own classes by wrapping their definitions in the `@responsive` directive:\n```css\n@responsive {\n .alert {\n background-color: #E53E3E;\n }\n}\n```\n",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#responsive"
}
]
},
{
"name": "@screen",
"description": "The `@screen` directive allows you to create media queries that reference your breakpoints by **name** instead of duplicating their values in your own CSS:\n```css\n@screen sm {\n /* ... */\n}\n```\n…gets transformed into this:\n```css\n@media (min-width: 640px) {\n /* ... */\n}\n```\n",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#screen"
}
]
},
{
"name": "@variants",
"description": "Generate `hover`, `focus`, `active` and other **variants** of your own utilities by wrapping their definitions in the `@variants` directive:\n```css\n@variants hover, focus {\n .btn-brand {\n background-color: #3182CE;\n }\n}\n```\n",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#variants"
}
]
}
]
}
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# tdotin

> t.in/
39 changes: 39 additions & 0 deletions deno.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"lock": false,
"tasks": {
"check": "deno fmt --check && deno lint && deno check **/*.ts && deno check **/*.tsx",
"cli": "echo \"import '\\$fresh/src/dev/cli.ts'\" | deno run --unstable -A -",
"manifest": "deno task cli manifest $(pwd)",
"start": "deno run -A --unstable-kv --watch=static/,routes/ dev.ts",
"build": "deno run -A dev.ts build",
"preview": "deno run -A main.ts",
"update": "deno run -A -r https://fresh.deno.dev/update ."
},
"lint": {
"rules": {
"tags": [
"fresh",
"recommended"
]
}
},
"exclude": [
"**/_fresh/*"
],
"imports": {
"$fresh/": "https://deno.land/x/[email protected]/",
"preact": "https://esm.sh/[email protected]",
"preact/": "https://esm.sh/[email protected]/",
"@preact/signals": "https://esm.sh/*@preact/[email protected]",
"@preact/signals-core": "https://esm.sh/*@preact/[email protected]",
"tailwindcss": "npm:[email protected]",
"tailwindcss/": "npm:/[email protected]/",
"tailwindcss/plugin": "npm:/[email protected]/plugin.js",
"$std/": "https://deno.land/[email protected]/"
},
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "preact"
},
"nodeModulesDir": true
}
8 changes: 8 additions & 0 deletions dev.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env -S deno run -A --watch=static/,routes/

import dev from "$fresh/dev.ts";
import config from "./fresh.config.ts";

import "$std/dotenv/load.ts";

await dev(import.meta.url, "./main.ts", config);
6 changes: 6 additions & 0 deletions fresh.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { defineConfig } from "$fresh/server.ts";
import tailwind from "$fresh/plugins/tailwind.ts";

export default defineConfig({
plugins: [tailwind()],
});
27 changes: 27 additions & 0 deletions fresh.gen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// DO NOT EDIT. This file is generated by Fresh.
// This file SHOULD be checked into source version control.
// This file is automatically updated during development when running `dev.ts`.

import * as $_alias_ from "./routes/[alias].tsx";
import * as $_404 from "./routes/_404.tsx";
import * as $_app from "./routes/_app.tsx";
import * as $api_url from "./routes/api/url.ts";
import * as $index from "./routes/index.tsx";
import * as $Form from "./islands/Form.tsx";
import { type Manifest } from "$fresh/server.ts";

const manifest = {
routes: {
"./routes/[alias].tsx": $_alias_,
"./routes/_404.tsx": $_404,
"./routes/_app.tsx": $_app,
"./routes/api/url.ts": $api_url,
"./routes/index.tsx": $index,
},
islands: {
"./islands/Form.tsx": $Form,
},
baseUrl: import.meta.url,
} satisfies Manifest;

export default manifest;
39 changes: 39 additions & 0 deletions islands/Form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useState } from "preact/hooks";

export default function Form() {
const [url, setUrl] = useState<string>("");
const [shortUrl, setShortUrl] = useState<string>("");

const store = async () => {
const res = await fetch(location.href + "api/url", {
method: "POST",
body: JSON.stringify({ url }),
});
const data = await res.json() as { alias: string; url: string };
setShortUrl(`${location.href}${data.alias}`);
};

return (
<div class="border-dotted border-black border-2 mx-auto w-3/5 rounded-md py-8 px-3 shadow-lg">
<form class="gap-5 flex flex-col items-center">
<input
type="url"
name="url"
id="url"
placeholder="Paste long url here..."
value={url}
onInput={(e) => setUrl((e.target as HTMLInputElement).value)}
class="rounded-md px-2 hover:outline-none focus:outline-none shadow-lg py-2 border-dotted border-black border-2 w-full"
/>
<button
type="button"
onClick={() => store()}
class="border-dotted border-black border-2 shadow-lg w-fit px-2 py-1 rounded-md hover:text-white hover:bg-blue-400"
>
Shorten URL
</button>
</form>
{shortUrl}
</div>
);
}
14 changes: 14 additions & 0 deletions main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/// <reference no-default-lib="true" />
/// <reference lib="dom" />
/// <reference lib="dom.iterable" />
/// <reference lib="dom.asynciterable" />
/// <reference lib="deno.ns" />
/// <reference lib="deno.unstable" />

import "$std/dotenv/load.ts";

import { start } from "$fresh/server.ts";
import manifest from "./fresh.gen.ts";
import config from "./fresh.config.ts";

await start(manifest, config);
12 changes: 12 additions & 0 deletions routes/[alias].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { defineRoute, PageProps } from "$fresh/server.ts";
import { kv } from "../util/database.ts";

export default defineRoute(async (req, ctx) => {
const url = (await kv.get([ctx.params.alias])).value as string;
const headers = new Headers();
headers.set("location", url);
return new Response(null, {
status: 303,
headers,
});
});
27 changes: 27 additions & 0 deletions routes/_404.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Head } from "$fresh/runtime.ts";

export default function Error404() {
return (
<>
<Head>
<title>404 - Page not found</title>
</Head>
<div class="px-4 py-8 mx-auto bg-[#86efac]">
<div class="max-w-screen-md mx-auto flex flex-col items-center justify-center">
<img
class="my-6"
src="/logo.svg"
width="128"
height="128"
alt="the Fresh logo: a sliced lemon dripping with juice"
/>
<h1 class="text-4xl font-bold">404 - Page not found</h1>
<p class="my-4">
The page you were looking for doesn't exist.
</p>
<a href="/" class="underline">Go back home</a>
</div>
</div>
</>
);
}
16 changes: 16 additions & 0 deletions routes/_app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { type PageProps } from "$fresh/server.ts";
export default function App({ Component }: PageProps) {
return (
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>tdotin</title>
<link rel="stylesheet" href="/styles.css" />
</head>
<body>
<Component />
</body>
</html>
);
}
20 changes: 20 additions & 0 deletions routes/api/url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { FreshContext } from "$fresh/server.ts";
import { kv } from "../../util/database.ts";
import { createAlias } from "../../util/index.ts";

export const handler = async (
req: Request,
_ctx: FreshContext,
): Promise<Response> => {
const alias = createAlias(5);
const { url } = await req.json() as NewUrl;
await kv.set([alias], [url]);
return new Response(JSON.stringify({
alias,
url,
}));
};

interface NewUrl {
url: string;
}
9 changes: 9 additions & 0 deletions routes/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Form from "../islands/Form.tsx";

export default function Home() {
return (
<div class="min-h-screen pt-4">
<Form />
</div>
);
}
Binary file added static/favicon.ico
Binary file not shown.
6 changes: 6 additions & 0 deletions static/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions static/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
7 changes: 7 additions & 0 deletions tailwind.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { type Config } from "tailwindcss";

export default {
content: [
"{routes,islands,components}/**/*.{ts,tsx}",
],
} satisfies Config;
1 change: 1 addition & 0 deletions util/database.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const kv = await Deno.openKv();
10 changes: 10 additions & 0 deletions util/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const CHARS = "abcdefghijklmnopqrstuvwxyz0123456789";

export function createAlias(len: number) {
let alias = "";
for (let i = 0; i < len; i++) {
const randomIndex = Math.floor(Math.random() * 36);
alias += CHARS.at(randomIndex);
}
return alias;
}

0 comments on commit 9f6f7ae

Please sign in to comment.