Graphical PDS migrator for AT Protocol

fresh boilerplate

knotbin.com e39dfc18

+11
.gitignore
··· 1 + # dotenv environment variable files 2 + .env 3 + .env.development.local 4 + .env.test.local 5 + .env.production.local 6 + .env.local 7 + 8 + # Fresh build directory 9 + _fresh/ 10 + # npm dependencies 11 + node_modules/
+16
README.md
··· 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.
+12
components/Button.tsx
··· 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-white hover:bg-gray-200 transition-colors" 10 + /> 11 + ); 12 + }
+39
deno.json
··· 1 + { 2 + "lock": false, 3 + "tasks": { 4 + "check": "deno fmt --check && deno lint && deno check **/*.ts && deno check **/*.tsx", 5 + "cli": "echo \"import '\\$fresh/src/dev/cli.ts'\" | deno run --unstable -A -", 6 + "manifest": "deno task cli manifest $(pwd)", 7 + "start": "deno run -A --watch=static/,routes/ dev.ts", 8 + "build": "deno run -A dev.ts build", 9 + "preview": "deno run -A main.ts", 10 + "update": "deno run -A -r https://fresh.deno.dev/update ." 11 + }, 12 + "lint": { 13 + "rules": { 14 + "tags": [ 15 + "fresh", 16 + "recommended" 17 + ] 18 + } 19 + }, 20 + "exclude": [ 21 + "**/_fresh/*" 22 + ], 23 + "imports": { 24 + "$fresh/": "https://deno.land/x/fresh@1.7.3/", 25 + "preact": "https://esm.sh/preact@10.22.0", 26 + "preact/": "https://esm.sh/preact@10.22.0/", 27 + "@preact/signals": "https://esm.sh/*@preact/signals@1.2.2", 28 + "@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.5.1", 29 + "tailwindcss": "npm:tailwindcss@3.4.1", 30 + "tailwindcss/": "npm:/tailwindcss@3.4.1/", 31 + "tailwindcss/plugin": "npm:/tailwindcss@3.4.1/plugin.js", 32 + "$std/": "https://deno.land/std@0.216.0/" 33 + }, 34 + "compilerOptions": { 35 + "jsx": "react-jsx", 36 + "jsxImportSource": "preact" 37 + }, 38 + "nodeModulesDir": true 39 + }
+8
dev.ts
··· 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 + import "$std/dotenv/load.ts"; 7 + 8 + await dev(import.meta.url, "./main.ts", config);
+6
fresh.config.ts
··· 1 + import { defineConfig } from "$fresh/server.ts"; 2 + import tailwind from "$fresh/plugins/tailwind.ts"; 3 + 4 + export default defineConfig({ 5 + plugins: [tailwind()], 6 + });
+27
fresh.gen.ts
··· 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 $api_joke from "./routes/api/joke.ts"; 8 + import * as $greet_name_ from "./routes/greet/[name].tsx"; 9 + import * as $index from "./routes/index.tsx"; 10 + import * as $Counter from "./islands/Counter.tsx"; 11 + import type { Manifest } from "$fresh/server.ts"; 12 + 13 + const manifest = { 14 + routes: { 15 + "./routes/_404.tsx": $_404, 16 + "./routes/_app.tsx": $_app, 17 + "./routes/api/joke.ts": $api_joke, 18 + "./routes/greet/[name].tsx": $greet_name_, 19 + "./routes/index.tsx": $index, 20 + }, 21 + islands: { 22 + "./islands/Counter.tsx": $Counter, 23 + }, 24 + baseUrl: import.meta.url, 25 + } satisfies Manifest; 26 + 27 + export default manifest;
+16
islands/Counter.tsx
··· 1 + import type { Signal } from "@preact/signals"; 2 + import { Button } from "../components/Button.tsx"; 3 + 4 + interface CounterProps { 5 + count: Signal<number>; 6 + } 7 + 8 + export default function Counter(props: CounterProps) { 9 + return ( 10 + <div class="flex gap-8 py-6"> 11 + <Button onClick={() => props.count.value -= 1}>-1</Button> 12 + <p class="text-3xl tabular-nums">{props.count}</p> 13 + <Button onClick={() => props.count.value += 1}>+1</Button> 14 + </div> 15 + ); 16 + }
+13
main.ts
··· 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 + 7 + import "$std/dotenv/load.ts"; 8 + 9 + import { start } from "$fresh/server.ts"; 10 + import manifest from "./fresh.gen.ts"; 11 + import config from "./fresh.config.ts"; 12 + 13 + await start(manifest, config);
+27
routes/_404.tsx
··· 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 bg-[#86efac]"> 10 + <div class="max-w-screen-md mx-auto flex flex-col items-center justify-center"> 11 + <img 12 + class="my-6" 13 + src="/logo.svg" 14 + width="128" 15 + height="128" 16 + alt="the Fresh logo: a sliced lemon dripping with juice" 17 + /> 18 + <h1 class="text-4xl font-bold">404 - Page not found</h1> 19 + <p class="my-4">The page you were looking for doesn't exist.</p> 20 + <a href="/" class="underline"> 21 + Go back home 22 + </a> 23 + </div> 24 + </div> 25 + </> 26 + ); 27 + }
+16
routes/_app.tsx
··· 1 + import { type PageProps } from "$fresh/server.ts"; 2 + export default function App({ Component }: PageProps) { 3 + return ( 4 + <html> 5 + <head> 6 + <meta charset="utf-8" /> 7 + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 8 + <title>airport</title> 9 + <link rel="stylesheet" href="/styles.css" /> 10 + </head> 11 + <body> 12 + <Component /> 13 + </body> 14 + </html> 15 + ); 16 + }
+21
routes/api/joke.ts
··· 1 + import { FreshContext } from "$fresh/server.ts"; 2 + 3 + // Jokes courtesy of https://punsandoneliners.com/randomness/programmer-jokes/ 4 + const JOKES = [ 5 + "Why do Java developers often wear glasses? They can't C#.", 6 + "A SQL query walks into a bar, goes up to two tables and says “can I join you?”", 7 + "Wasn't hard to crack Forrest Gump's password. 1forrest1.", 8 + "I love pressing the F5 key. It's refreshing.", 9 + "Called IT support and a chap from Australia came to fix my network connection. I asked “Do you come from a LAN down under?”", 10 + "There are 10 types of people in the world. Those who understand binary and those who don't.", 11 + "Why are assembly programmers often wet? They work below C level.", 12 + "My favourite computer based band is the Black IPs.", 13 + "What programme do you use to predict the music tastes of former US presidential candidates? An Al Gore Rhythm.", 14 + "An SEO expert walked into a bar, pub, inn, tavern, hostelry, public house.", 15 + ]; 16 + 17 + export const handler = (_req: Request, _ctx: FreshContext): Response => { 18 + const randomIndex = Math.floor(Math.random() * JOKES.length); 19 + const body = JOKES[randomIndex]; 20 + return new Response(body); 21 + };
+5
routes/greet/[name].tsx
··· 1 + import { PageProps } from "$fresh/server.ts"; 2 + 3 + export default function Greet(props: PageProps) { 4 + return <div>Hello {props.params.name}</div>; 5 + }
+25
routes/index.tsx
··· 1 + import { useSignal } from "@preact/signals"; 2 + import Counter from "../islands/Counter.tsx"; 3 + 4 + export default function Home() { 5 + const count = useSignal(3); 6 + return ( 7 + <div class="px-4 py-8 mx-auto bg-[#86efac]"> 8 + <div class="max-w-screen-md mx-auto flex flex-col items-center justify-center"> 9 + <img 10 + class="my-6" 11 + src="/logo.svg" 12 + width="128" 13 + height="128" 14 + alt="the Fresh logo: a sliced lemon dripping with juice" 15 + /> 16 + <h1 class="text-4xl font-bold">Welcome to Fresh</h1> 17 + <p class="my-4"> 18 + Try updating this message in the 19 + <code class="mx-2">./routes/index.tsx</code> file, and refresh. 20 + </p> 21 + <Counter count={count} /> 22 + </div> 23 + </div> 24 + ); 25 + }
static/favicon.ico

This is a binary file and will not be displayed.

+6
static/logo.svg
··· 1 + <svg width="40" height="40" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 + <path d="M34.092 8.845C38.929 20.652 34.092 27 30 30.5c1 3.5-2.986 4.222-4.5 2.5-4.457 1.537-13.512 1.487-20-5C2 24.5 4.73 16.714 14 11.5c8-4.5 16-7 20.092-2.655Z" fill="#FFDB1E"/> 3 + <path d="M14 11.5c6.848-4.497 15.025-6.38 18.368-3.47C37.5 12.5 21.5 22.612 15.5 25c-6.5 2.587-3 8.5-6.5 8.5-3 0-2.5-4-5.183-7.75C2.232 23.535 6.16 16.648 14 11.5Z" fill="#fff" stroke="#FFDB1E"/> 4 + <path d="M28.535 8.772c4.645 1.25-.365 5.695-4.303 8.536-3.732 2.692-6.606 4.21-7.923 4.83-.366.173-1.617-2.252-1.617-1 0 .417-.7 2.238-.934 2.326-1.365.512-4.223 1.29-5.835 1.29-3.491 0-1.923-4.754 3.014-9.122.892-.789 1.478-.645 2.283-.645-.537-.773-.534-.917.403-1.546C17.79 10.64 23 8.77 25.212 8.42c.366.014.82.35.82.629.41-.14 2.095-.388 2.503-.278Z" fill="#FFE600"/> 5 + <path d="M14.297 16.49c.985-.747 1.644-1.01 2.099-2.526.566.121.841-.08 1.29-.701.324.466 1.657.608 2.453.701-.715.451-1.057.852-1.452 2.106-1.464-.611-3.167-.302-4.39.42Z" fill="#fff"/> 6 + </svg>
+3
static/styles.css
··· 1 + @tailwind base; 2 + @tailwind components; 3 + @tailwind utilities;
+7
tailwind.config.ts
··· 1 + import { type Config } from "tailwindcss"; 2 + 3 + export default { 4 + content: [ 5 + "{routes,islands,components}/**/*.{ts,tsx,js,jsx}", 6 + ], 7 + } satisfies Config;