Skip to content

Commit 2b5a248

Browse files
committed
Initial commit
Signed-off-by: ackr-8 <[email protected]>
1 parent 5604b62 commit 2b5a248

31 files changed

+824
-2
lines changed

.gitignore

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# dotenv environment variable files
2+
.env
3+
.env.development.local
4+
.env.test.local
5+
.env.production.local
6+
.env.local
7+
8+
### Deno ###
9+
/.idea/
10+
/.vscode/
11+
12+
/node_modules
13+
14+
.env
15+
*.orig
16+
*.pyc
17+
*.swp
18+
19+
### Linux ###
20+
*~
21+
22+
# temporary files which can be created if a process still has a handle open of a deleted file
23+
.fuse_hidden*
24+
25+
# KDE directory preferences
26+
.directory
27+
28+
# Linux trash folder which might appear on any partition or disk
29+
.Trash-*
30+
31+
# .nfs files are created when an open file is removed but is still being accessed
32+
.nfs*
33+
34+
### macOS ###
35+
# General
36+
.DS_Store
37+
.AppleDouble
38+
.LSOverride
39+
40+
# Icon must end with two \r
41+
Icon
42+
43+
44+
# Thumbnails
45+
._*
46+
47+
# Files that might appear in the root of a volume
48+
.DocumentRevisions-V100
49+
.fseventsd
50+
.Spotlight-V100
51+
.TemporaryItems
52+
.Trashes
53+
.VolumeIcon.icns
54+
.com.apple.timemachine.donotpresent
55+
56+
# Directories potentially created on remote AFP share
57+
.AppleDB
58+
.AppleDesktop
59+
Network Trash Folder
60+
Temporary Items
61+
.apdisk
62+
63+
### macOS Patch ###
64+
# iCloud generated files
65+
*.icloud
66+
67+
### VisualStudioCode ###
68+
.vscode/*
69+
!.vscode/settings.json
70+
!.vscode/tasks.json
71+
!.vscode/launch.json
72+
!.vscode/extensions.json
73+
!.vscode/*.code-snippets
74+
75+
# Local History for Visual Studio Code
76+
.history/
77+
78+
# Built Visual Studio Code Extensions
79+
*.vsix
80+
81+
### VisualStudioCode Patch ###
82+
# Ignore all local history of files
83+
.history
84+
.ionide
85+
86+
### Windows ###
87+
# Windows thumbnail cache files
88+
Thumbs.db
89+
Thumbs.db:encryptable
90+
ehthumbs.db
91+
ehthumbs_vista.db
92+
93+
# Dump file
94+
*.stackdump
95+
96+
# Folder config file
97+
[Dd]esktop.ini
98+
99+
# Recycle Bin used on file shares
100+
$RECYCLE.BIN/
101+
102+
# Windows Installer files
103+
*.cab
104+
*.msi
105+
*.msix
106+
*.msm
107+
*.msp
108+
109+
# Windows shortcuts
110+
*.lnk

README.md

+16-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,16 @@
1-
# CRUD-NoSQL
2-
A basic demonstration for applying CRUD operations on a NoSQL database using TS.
1+
# Fresh project
2+
3+
Your new Fresh project is ready to go. You can follow the Fresh "Getting
4+
Started" guide here: https://fresh.deno.dev/docs/getting-started
5+
6+
### Usage
7+
8+
Make sure to install Deno: https://deno.land/manual/getting_started/installation
9+
10+
Then start the project:
11+
12+
```
13+
deno task start
14+
```
15+
16+
This will watch the project directory and restart as necessary.

components/Button.tsx

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { JSX } from "preact";
2+
import { IS_BROWSER } from "$fresh/runtime.ts";
3+
4+
export function Button(props: JSX.HTMLAttributes<HTMLButtonElement>) {
5+
return (
6+
<button
7+
{...props}
8+
disabled={!IS_BROWSER || props.disabled}
9+
class="px-2 py-1 border-gray-500 border-2 rounded bg-black hover:bg-sky-500 transition-colors"
10+
/>
11+
);
12+
}

components/Navbar.tsx

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import LemonIcon from "https://deno.land/x/[email protected]/tsx/lemon-2.tsx";
2+
3+
interface NavbarProps {
4+
sessionId?: string;
5+
}
6+
7+
export function Navbar({ sessionId }: NavbarProps) {
8+
return (
9+
<header class="text-white font-medium">
10+
<div class="mx-auto max-w-screen-xl px-4 sm:px-6 lg:px-8 ">
11+
<div class="flex h-16 items-center ">
12+
<div class="flex items-center flex-1">
13+
<a href="/" class="flex items-center">
14+
{/* <LemonIcon /> */}
15+
<div class="ml-1">
16+
<span class="font-extrabold text-sky-500">ST </span><span>URL Shortner</span>
17+
</div>
18+
</a>
19+
</div>
20+
21+
<div>
22+
<nav aria-label="Global">
23+
<ul class="flex items-center gap-6 text-sm">
24+
{ sessionId ?
25+
(
26+
<>
27+
<a
28+
class="font-bold transition hover:text-sky-500"
29+
href="/account/myshorts"
30+
>
31+
Shorts
32+
</a>
33+
<a
34+
class="transition hover:text-sky-500"
35+
href="/signout"
36+
>
37+
Sign Out
38+
</a>
39+
</>
40+
) : (
41+
<a
42+
class="transition hover:text-sky-500"
43+
href="/signin"
44+
>
45+
Sign In
46+
</a>
47+
)
48+
}
49+
50+
</ul>
51+
</nav>
52+
</div>
53+
</div>
54+
</div>
55+
</header>
56+
);
57+
}

deno.json

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"lock": false,
3+
"tasks": {
4+
"check": "deno fmt --check && deno lint && deno check **/*.ts && deno check **/*.tsx",
5+
"start": "deno run -A --watch=static/,routes/ --unstable-kv dev.ts",
6+
"db:dump": "deno run --allow-read --allow-env --unstable-kv tools/dump.ts",
7+
"db:reset": "deno run --allow-read --allow-env --unstable-kv tools/reset_kv.ts",
8+
"build": "deno run -A --unstable-kv dev.ts build",
9+
"preview": "deno run -A --unstable-kv main.ts",
10+
"update": "deno run -A -r https://fresh.deno.dev/update ."
11+
},
12+
"lint": { "rules": { "tags": ["fresh", "recommended"] } },
13+
"nodeModulesDir": true,
14+
"imports": {
15+
"$fresh/": "https://deno.land/x/[email protected]/",
16+
"preact": "https://esm.sh/[email protected]",
17+
"preact/": "https://esm.sh/[email protected]/",
18+
"preact-render-to-string": "https://esm.sh/*[email protected]",
19+
"@preact/signals": "https://esm.sh/*@preact/[email protected]",
20+
"@preact/signals-core": "https://esm.sh/*@preact/[email protected]",
21+
"$std/": "https://deno.land/[email protected]/",
22+
"kv_oauth": "https://deno.land/x/[email protected]/mod.ts",
23+
"tailwindcss": "npm:[email protected]",
24+
"tailwindcss/": "npm:/[email protected]/",
25+
"tailwindcss/plugin": "npm:/[email protected]/plugin.js"
26+
},
27+
"compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "preact" },
28+
"exclude": ["**/_fresh/*"]
29+
}

dev.ts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env -S deno run -A --watch=static/,routes/
2+
3+
import dev from "$fresh/dev.ts";
4+
import config from "./fresh.config.ts";
5+
6+
await dev(import.meta.url, "./main.ts", config);

fresh.config.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { defineConfig } from "$fresh/server.ts";
2+
import tailwind from "$fresh/plugins/tailwind.ts"
3+
export default defineConfig({
4+
plugins: [tailwind()]
5+
});

fresh.gen.ts

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// DO NOT EDIT. This file is generated by Fresh.
2+
// This file SHOULD be checked into source version control.
3+
// This file is automatically updated during development when running `dev.ts`.
4+
5+
import * as $_404 from "./routes/_404.tsx";
6+
import * as $_app from "./routes/_app.tsx";
7+
import * as $_layout from "./routes/_layout.tsx";
8+
import * as $_middleware from "./routes/_middleware.ts";
9+
import * as $account_middleware from "./routes/account/_middleware.ts";
10+
import * as $account_myshorts from "./routes/account/myshorts.tsx";
11+
import * as $callback from "./routes/callback.ts";
12+
import * as $index from "./routes/index.tsx";
13+
import * as $s_id_ from "./routes/s/[id].tsx";
14+
import * as $signin from "./routes/signin.ts";
15+
import * as $signout from "./routes/signout.ts";
16+
import * as $Short from "./islands/Short.tsx";
17+
import { type Manifest } from "$fresh/server.ts";
18+
19+
const manifest = {
20+
routes: {
21+
"./routes/_404.tsx": $_404,
22+
"./routes/_app.tsx": $_app,
23+
"./routes/_layout.tsx": $_layout,
24+
"./routes/_middleware.ts": $_middleware,
25+
"./routes/account/_middleware.ts": $account_middleware,
26+
"./routes/account/myshorts.tsx": $account_myshorts,
27+
"./routes/callback.ts": $callback,
28+
"./routes/index.tsx": $index,
29+
"./routes/s/[id].tsx": $s_id_,
30+
"./routes/signin.ts": $signin,
31+
"./routes/signout.ts": $signout,
32+
},
33+
islands: {
34+
"./islands/Short.tsx": $Short,
35+
},
36+
baseUrl: import.meta.url,
37+
} satisfies Manifest;
38+
39+
export default manifest;

islands/Short.tsx

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import IconCopy from "https://deno.land/x/[email protected]/tsx/copy.tsx";
2+
import { useState } from "preact/hooks";
3+
import { ShortEntity } from "../utils/db.ts";
4+
5+
interface ShortProps {
6+
short: ShortEntity,
7+
hostname: string,
8+
}
9+
10+
export default function Short({ short, hostname } : ShortProps) {
11+
const [isView, setView] = useState<boolean>(false);
12+
const onDelete = async () => {
13+
await fetch("/account/myshorts", { method: "DELETE", credentials: "same-origin", body: JSON.stringify(short) });
14+
window.location.reload();
15+
}
16+
return (
17+
<>
18+
<div class="flex items-center justify-between ">
19+
<div class="flex items-center space-x-4">
20+
<div>
21+
<p class="text-sky-600 font-semibold">Short URL</p>
22+
<p class="text-gray-600">{hostname}/s/{short.shortUrl}</p>
23+
</div>
24+
<button
25+
onClick={() => navigator.clipboard.writeText(`${hostname}/s/${short.shortUrl}`)}
26+
class="text-sky-600 hover:text-sky-800 focus:outline-none">
27+
<IconCopy class="w-6 h-6" />
28+
</button>
29+
</div>
30+
<div>
31+
<button onClick={() => setView(prevState => !prevState)} class="text-sky-600 hover:underline m-3">
32+
View Original
33+
</button>
34+
|
35+
<button onClick={() => onDelete()} class="text-sky-600 hover:underline m-3">
36+
Delete
37+
</button>
38+
</div>
39+
</div>
40+
41+
{isView ?
42+
(
43+
<div class="mt-4 bg-white text-black border border-gray-300 p-2 rounded-md whitespace-pre">
44+
{short.originalUrl}
45+
</div>
46+
) : (<span></span>)
47+
}
48+
49+
</>
50+
);
51+
}

main.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/// <reference no-default-lib="true" />
2+
/// <reference lib="dom" />
3+
/// <reference lib="dom.iterable" />
4+
/// <reference lib="dom.asynciterable" />
5+
/// <reference lib="deno.ns" />
6+
/// <reference lib="deno.unstable" />
7+
8+
import "$std/dotenv/load.ts";
9+
10+
import { start } from "$fresh/server.ts";
11+
import manifest from "./fresh.gen.ts";
12+
import config from "./fresh.config.ts";
13+
14+
await start(manifest, config);

routes/_404.tsx

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { Head } from "$fresh/runtime.ts";
2+
3+
export default function Error404() {
4+
return (
5+
<>
6+
<Head>
7+
<title>404 - Page not found</title>
8+
</Head>
9+
<div class="px-4 py-8 mx-auto">
10+
<div class="max-w-screen-md mx-auto flex flex-col items-center justify-center">
11+
<img
12+
class="my-6"
13+
src="/fav.png"
14+
width="128"
15+
height="128"
16+
alt="CK | ackr8.com"
17+
/>
18+
<h1 class="text-4xl font-bold">404 - Page not found</h1>
19+
<p class="my-4">
20+
The page you were looking for doesn't exist.
21+
</p>
22+
<a href="/" class="underline">Go back home</a>
23+
</div>
24+
</div>
25+
</>
26+
);
27+
}

routes/_app.tsx

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { AppProps } from "$fresh/server.ts";
2+
3+
export default function App({ Component }: AppProps) {
4+
return (
5+
<html>
6+
<head>
7+
<meta charSet="utf-8" />
8+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
9+
<title>ST - URL Shortner</title>
10+
<link rel="stylesheet" href="/styles.css" />
11+
</head>
12+
<body>
13+
<Component />
14+
</body>
15+
</html>
16+
);
17+
}

0 commit comments

Comments
 (0)