screw it, let's do this.

This commit is contained in:
mehbark 2023-04-28 19:48:34 -04:00
commit 346bf1fcf6
45 changed files with 1931 additions and 0 deletions

11
README.md Normal file
View file

@ -0,0 +1,11 @@
# fresh project
### Usage
Start the project:
```
deno task start
```
This will watch the project directory and restart as necessary.

149
common/db.ts Normal file
View file

@ -0,0 +1,149 @@
import { catcher, catcher_async, squish_option } from "utils";
import { Conversation, Database, Message, Preset } from "types";
import { Option } from "optionals";
import { URL } from "utils";
const DB_PATH = "./db.json";
export async function get_db_obj(): Promise<Option<Database>> {
const text = await catcher_async(() => Deno.readTextFile(DB_PATH));
const db = text.map(db_text =>
catcher(() => JSON.parse(db_text) as Database)
);
return squish_option(db);
}
export async function get_message(id: string): Promise<Option<Message>> {
return (await get_db_obj()).map(db => db.messages[id]);
}
export async function get_conversation(
id: string
): Promise<Option<Conversation>> {
return (await get_db_obj()).map(db => db.conversations[id]);
}
async function save_db(db: Database) {
await Deno.writeTextFile(DB_PATH, JSON.stringify(db));
}
export function new_conversation(
name: string,
description: string
): Promise<Option<string>> {
return catcher_async(async () => {
const db = (await get_db_obj()).unwrap();
const id = abc_number(db.conversation_id);
db.conversation_id++;
db.conversations[id] = { name, description, messages: [], presets: {} };
db.conversations[id].presets.default = { fg: "black" };
db.conversations[id].presets.page = { fg: "black", bg: "white" };
db.conversations[id].presets.box = { fg: "black", bg: "white" };
await save_db(db);
return id;
});
}
export function add_preset(
name: string,
{ fg, bg, font }: Preset,
conv_id: string
) {
return catcher_async(async () => {
const db = (await get_db_obj()).unwrap();
const conv = db.conversations[conv_id];
if (!conv.presets) {
conv.presets = {};
}
conv.presets[name] = { fg, bg, font };
await save_db(db);
return name;
});
}
export function orphan_message(message: Message): Promise<Option<string>> {
return catcher_async(async () => {
const db = (await get_db_obj()).unwrap();
const id = abc_number(db.message_id);
db.message_id++;
db.messages[id] = message;
await save_db(db);
return id;
});
}
export function message_under(
message: Message,
conv_id: string
): Promise<Option<string>> {
return catcher_async(async () => {
const new_msg_id = (await orphan_message(message)).unwrap();
const db = (await get_db_obj()).unwrap();
if (!db.conversations[conv_id]) {
throw {};
}
db.conversations[conv_id].messages.push(new_msg_id);
await save_db(db);
return new_msg_id;
});
}
function abc_number(n: number): string {
let x = n.toString(26);
for (let i = 25; i >= 0; i--) {
const from = i.toString(26);
const to = (i + 10).toString(36);
x = x.replaceAll(from, to);
}
return x;
}
export async function fetch_db(): Promise<Option<Database>> {
const db_response = await catcher_async(
async () => await fetch(`${URL}/api/db`).then(r => r.json())
);
return db_response.map(db => db.val);
}
// export type Preset = {
// fg: string;
// bg: string;
// font?: string;
// };
//TODO: AS TEMPTING AS IT MIGHT BE, DO NOT JUST HAVE A save_db FUNCTION THAT STORES A SERIALIZED OBJECT
//TODO: THAT IS JUST *BEGGING* FOR CONCURRENCY ERRORS
//TODO: INSTEAD HAVE A SMALL SET OF FUNCTIONS THAT DO SPECIFIC THINGS
//TODO: it might actually be easier to use an actual db
// toy-network on  main [✘!?] via  v17.4.0 took 1m10s
// curl --request PUT localhost:8000/api/conv -d '{"name": "test", "description": "curl test", "fg": "red", "bg": "blue"}'
// "a"⏎
// toy-network on  main [✘!?] via  v17.4.0
// curl --request PUT localhost:8000/api/conv/a -d '{"content": "hello", "font": "Comic Sans MS"}'
// {}⏎
// toy-network on  main [✘!?] via  v17.4.0
// curl --request PUT localhost:8000/api/conv/a -d '{"content": "hello", "font": "Comic Sans MS"}'
// {"val":"c"}⏎
// toy-network on  main [✘!?] via  v17.4.0
// curl --request PUT localhost:8000/api/conv/a -d '{"content": "hello", "font": "Comic Sans MS"}'
// {"val":"c"}⏎
// toy-network on  main [✘!?] via  v17.4.0
// curl --request PUT localhost:8000/api/conv/a -d '{"content": "yay", "font": "cursive", "fg": "rebeccapurple"}'
// {"val":"d"}⏎
// toy-network on  main [✘!?] via  v17.4.0
// curl --request PUT localhost:8000/api/conv/a -d '{"content": "serif", "font": "serif", "fg": "rebeccapurple"}'
// {"val":"e"}⏎
// toy-network on  main [✘!?] via  v17.4.0
// curl --request PUT localhost:8000/api/conv/a -d '{"content": "\\"normal\\"", "fg": "rebeccapurple"}'
// {"val":"f"}⏎
// toy-network on  main [✘!?] via  v17.4.0
// curl --request PUT localhost:8000/api/conv/a -d '{"content": "contrast", "bg": "black", "fg": "white"}'
// {"val":"g"}⏎

77
common/style.ts Normal file
View file

@ -0,0 +1,77 @@
// JSXInternal.CSSProperties
import { Conversation, Database, Message } from "types";
import { remove_undefined_keys } from "utils";
export const DEFAULT_FONT = '"courier-std", courier, monospace';
// gonna use special presets, page for page, default for default
// did that lol: default, page, box
export const DEFAULT_STYLE: preact.JSX.CSSProperties = {
color: "#000000",
fontFamily: DEFAULT_FONT,
fontWeight: "bold",
};
export function msg_style(
msg: Message,
db: Database,
conv?: Conversation
): preact.JSX.CSSProperties {
const preset_style_ = msg.preset ? preset_style(msg.preset, db, conv) : {};
const conv_default_style = conv?.presets?.default ?? {};
return {
...DEFAULT_STYLE,
...conv_default_style,
...preset_style_,
...convert_fg_bg_font(msg),
};
}
// conversation presets override global oness
function preset_style(
preset: string,
db: Database,
conv?: Conversation
): preact.JSX.CSSProperties {
if (conv && conv.presets && conv.presets[preset]) {
const preset_ = (conv.presets ?? {})[preset] ?? {};
const box_bg = conv?.presets.box?.bg;
if (!preset_.bg && box_bg) {
preset_.bg = box_bg;
}
return convert_fg_bg_font(preset_);
} else {
const preset_ = db.presets[preset] ?? {};
return convert_fg_bg_font(preset_);
}
}
export function convert_fg_bg_font(thing: {
fg?: string;
bg?: string;
font?: string;
}): preact.JSX.CSSProperties {
return remove_undefined_keys({
color: thing.fg,
backgroundColor: thing.bg,
fontFamily: thing.font,
});
}
export function conv_style(conv: Conversation) {
return {
...DEFAULT_STYLE,
...convert_fg_bg_font(conv.presets?.box ?? conv),
};
}
export function page_style(conv: Conversation) {
return {
color: "black",
backgroundColor: "white",
fontFamily: DEFAULT_FONT,
...remove_undefined_keys(convert_fg_bg_font(conv.presets?.page)),
};
}

31
common/types.ts Normal file
View file

@ -0,0 +1,31 @@
export { Option } from "optionals";
export type Message = {
content: string;
preset?: string;
fg?: string;
bg?: string;
font?: string;
sender?: string;
};
export type Conversation = {
name: string;
description: string;
messages: string[];
presets: Record<string, Preset>;
};
export type Preset = {
fg: string;
bg?: string;
font?: string;
};
export type Database = {
messages: Record<string, Message>;
conversations: Record<string, Conversation>;
presets: Record<string, Preset>;
message_id: number;
conversation_id: number;
};

53
common/utils.ts Normal file
View file

@ -0,0 +1,53 @@
import { Option, Some, None, none } from "optionals";
export function catcher<T>(f: () => T): Option<T> {
try {
return Some(f());
} catch {
// There is no need to define what is already undefined.
return None();
}
}
export async function catcher_async<T>(
f: () => Promise<T>
): Promise<Option<T>> {
try {
return Some(await f());
} catch {
return None();
}
}
export function squish_option<T>(opt: Option<Option<T>>): Option<T> {
return opt.unwrapOr(None());
}
export function json_response(obj: any, options?: ResponseInit): Response {
return new Response(JSON.stringify(obj), {
...options,
headers: { "Content-Type": "application/json" },
});
}
export function fetch_json(
input: RequestInfo | URL,
init?: RequestInit
): Promise<Option<any>> {
return catcher_async(() => fetch(input, init).then(j => j.json()));
}
export function class_list(...classes: Array<string | undefined>): string {
return classes.filter(Boolean).join(" ");
}
export function remove_undefined_keys(obj: any): any {
return Object.keys(obj).reduce((acc, key) => {
if (obj[key] !== undefined && obj[key] !== "") {
acc[key] = obj[key];
}
return acc;
}, {});
}
export const URL = "http://fl.pyrope.net";

58
components/AddMsg.tsx Normal file
View file

@ -0,0 +1,58 @@
//TODO: maybe in a seperate path (e.g. /i/[id]) so that static is still there
//TODO: ^ going with this
//TODO: basically a fg, bg, font picker (text-entry? link to typical builtin fonts?)
//TODO: also making/editing presets
//TODO: might be easiest to refresh on submit
import { useState } from "preact/hooks";
import { Preset, Message, Database, Conversation } from "types";
import InputMsg from "components/InputMsg.tsx";
//TODO: oh also creating convos
//TODO: oh also updating convos' metadata
//TODO: a sort of commit like thing? reactive config, then you have to actually submit
//TODO: much harder than just refreshing but much nicer
//TODO: probably in the main index (much minimalism waow)
export default function AddMsg({
// preset_list,
preset,
onsubmit,
conv,
db,
}: {
// preset_list: string[];
// ehhh the order should stay consistent enough
preset: string;
onsubmit: (_: Message) => void;
conv: Conversation;
db: Database;
}) {
const [content, setContent] = useState("");
console.log(content);
const msg = {
content,
preset,
};
return (
<InputMsg
msg={msg}
db={db}
onSubmit={() => {
onsubmit(msg);
setContent("");
}}
conversation={conv}
onInput={e => setContent(e.target.value)}
/>
);
}
// type Message = {
// content: string;
// preset?: string | undefined;
// fg?: string | undefined;
// bg?: string | undefined;
// font?: string | undefined;
// sender?: string | undefined;
// }

12
components/Button.tsx Normal file
View file

@ -0,0 +1,12 @@
import { JSX } from "preact";
import { IS_BROWSER } from "$fresh/runtime.ts";
export function Button(props: JSX.HTMLAttributes<HTMLButtonElement>) {
return (
<button
{...props}
disabled={!IS_BROWSER || props.disabled}
class="px-2 py-1 border(gray-100 2) hover:bg-gray-200"
/>
);
}

60
components/Conv.tsx Normal file
View file

@ -0,0 +1,60 @@
import { Database } from "types";
import Msg from "components/Msg.tsx";
import { conv_style, msg_style, page_style } from "style";
import { Head } from "$fresh/runtime.ts";
import WithStyleSheet from "components/WithStyleSheet.tsx";
export default function Conv({
conv,
db,
children,
}: {
conv: string;
db: Database;
children?: any;
}) {
const conv_ = db.conversations[conv];
return (
<>
<WithStyleSheet href="/Conv.css" />
<Head>
<title>{conv_.name}</title>
</Head>
<div style={page_style(conv_)} className="convo-body">
<a href="/">
<h1
className="name"
// style={msg_style(
// { content: "", preset: "name" },
// db,
// conv_
// )}
>
{conv_.name}
</h1>
<p
className="description"
// style={{
// ...msg_style(
// { content: "", preset: "description" },
// db,
// conv_
// ),
// fontWeight: "normal",
// }}
>
{conv_.description}
</p>
</a>
<div className="chat-container" style={conv_style(conv_)}>
<div className="chat">
{conv_.messages.map(msg => (
<Msg message={msg} db={db} conversation={conv_} />
))}
</div>
</div>
{children}
</div>
</>
);
}

View file

@ -0,0 +1,48 @@
import { Database, Message } from "types";
import WithStyleSheet from "components/WithStyleSheet.tsx";
import { page_style } from "style";
import RenderMsg from "components/RenderMsg.tsx";
export default function ConversationLink({
conv,
db,
interactive,
}: {
conv: string;
db: Database;
interactive: boolean;
}) {
const conv_ = db.conversations[conv];
if (!conv_) return <></>;
const name: Message = {
content: conv_.name,
preset: "page",
};
const description: Message = {
content: conv_.description,
preset: "page",
};
return (
<>
<WithStyleSheet href="/ConversationLink.css" />
<div className="conversation-link" style={page_style(conv_)}>
<a href={`/${conv}${interactive ? "/i" : ""}`}>
<RenderMsg
conversation={conv_}
db={db}
msg={name}
additional_style={{ fontWeight: "bold" }}
/>
<RenderMsg
additional_style={{ fontWeight: "normal" }}
conversation={conv_}
db={db}
msg={description}
/>
</a>
</div>
</>
);
}

31
components/InputMsg.tsx Normal file
View file

@ -0,0 +1,31 @@
import { useEffect, useRef, useState } from "preact/hooks";
import { msg_style } from "style";
import { Conversation, Database, Message } from "types";
export default function InputMsg({
msg,
db,
conversation,
onInput,
onSubmit,
...props
}: {
msg: Message;
db: Database;
conversation?: Conversation;
onInput: (e: any) => void;
onSubmit: () => void;
}) {
return (
<input
// className={class_list("message", `preset-${msg.preset}`)}
value={msg.content}
style={msg_style(msg, db, conversation)}
className="add-msg"
onInput={onInput}
onKeyPress={e => e.key == "Enter" && onSubmit()}
type="text"
{...props}
></input>
);
}

19
components/Msg.tsx Normal file
View file

@ -0,0 +1,19 @@
import { Conversation, Database } from "types";
import { msg_style } from "style";
import RenderMsg from "components/RenderMsg.tsx";
export default function Msg({
message,
db,
conversation,
...props
}: {
message: string;
db: Database;
conversation?: Conversation;
}) {
const msg = db.messages[message];
return (
<RenderMsg msg={msg} db={db} conversation={conversation} {...props} />
);
}

View file

@ -0,0 +1,91 @@
import { useState } from "preact/hooks";
import { URL } from "utils";
export default function PresetCreator({
conv,
name,
setName,
fg,
setFg,
bg,
setBg,
font,
setFont,
onsubmit,
}: {
conv: string;
name: string;
setName: (_: string) => void;
fg: string;
setFg: (_: string) => void;
bg: string;
setBg: (_: string) => void;
font: string;
setFont: (_: string) => void;
onsubmit?: () => void;
}) {
async function submit() {
await fetch(`${URL}/api/conv/${conv}`, {
method: "PUT",
body: JSON.stringify({ register_preset: name, fg, bg, font }),
});
}
return (
<div
className="preset-creator"
style={{
color: fg,
backgroundColor: bg == "" ? "white" : bg,
fontFamily: font,
}}
>
<div className="pc-name">
Name:{" "}
<input
value={name}
onInput={(e: any) => setName(e.target.value)}
className="pc-input"
></input>
</div>
<div className="pc-fg">
FG:{" "}
<input
value={fg}
onInput={(e: any) => setFg(e.target.value)}
className="pc-input"
></input>
</div>
<div className="pc-bg">
BG:{" "}
<input
value={bg}
onInput={(e: any) => setBg(e.target.value)}
className="pc-input"
></input>
</div>
<div className="pc-font">
Font:{" "}
<input
value={font}
onInput={(e: any) => setFont(e.target.value)}
className="pc-input"
></input>
</div>
<button
className="pc-submit"
onClick={async () => {
await submit();
onsubmit && onsubmit();
}}
>
submit
</button>
</div>
);
}

View file

@ -0,0 +1,59 @@
import { Conversation, Database, Message, Preset } from "types";
import RenderMsg from "components/RenderMsg.tsx";
//TODO: this might be the place to allow editing of presets,,,
//TODO: easier to just not allow editing presets lol
export default function PresetSelector({
selected,
setPreset,
conv,
db,
}: {
selected: string;
setPreset: (_: string) => void;
conv: Conversation;
db: Database;
}) {
//TODO: maybe return DB presets? not really necessary
const presets = Object.keys({ ...conv.presets });
return (
<div className="preset-selector">
{presets.map(p => (
<PresetOption
name={p}
selected={selected == p}
onSelect={setPreset}
conv={conv}
db={db}
/>
))}
</div>
);
}
function PresetOption({
name,
selected,
onSelect,
conv,
db,
}: {
name: string;
selected: boolean;
onSelect: (_: string) => void;
conv: Conversation;
db: Database;
}) {
const msg: Message = {
content: name == "" ? "default" : name,
preset: name,
};
return (
<div
onClick={() => onSelect(name)}
className={`preset-option ${selected ? "selected" : ""}`}
>
<RenderMsg msg={msg} db={db} conversation={conv} />
</div>
);
}

26
components/RenderMsg.tsx Normal file
View file

@ -0,0 +1,26 @@
import { msg_style } from "style";
import { Conversation, Database, Message } from "types";
export default function RenderMsg({
msg,
db,
conversation,
additional_style = {},
...props
}: {
msg: Message;
db: Database;
additional_style?: preact.JSX.CSSProperties;
conversation?: Conversation;
}) {
return (
<div
// className={class_list("message", `preset-${msg.preset}`)}
style={{ ...msg_style(msg, db, conversation), ...additional_style }}
className={msg.preset}
{...props}
>
{msg.content}
</div>
);
}

View file

@ -0,0 +1,15 @@
import { Head } from "$fresh/runtime.ts";
export default function WithStyleSheet({
children = [],
href,
}: {
children?: any;
href: string;
}) {
return (
<Head>
<link rel="stylesheet" href={href}></link>
</Head>
);
}

1
db.json Normal file

File diff suppressed because one or more lines are too long

10
deno.json Normal file
View file

@ -0,0 +1,10 @@
{
"tasks": {
"start": "deno run -A --watch=static/,routes/ dev.ts"
},
"importMap": "./import_map.json",
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "preact"
}
}

389
deno.lock Normal file
View file

@ -0,0 +1,389 @@
{
"version": "2",
"remote": {
"https://deno.land/std@0.140.0/_util/assert.ts": "e94f2eb37cebd7f199952e242c77654e43333c1ac4c5c700e929ea3aa5489f74",
"https://deno.land/std@0.140.0/_util/os.ts": "3b4c6e27febd119d36a416d7a97bd3b0251b77c88942c8f16ee5953ea13e2e49",
"https://deno.land/std@0.140.0/fs/_util.ts": "0fb24eb4bfebc2c194fb1afdb42b9c3dda12e368f43e8f2321f84fc77d42cb0f",
"https://deno.land/std@0.140.0/fs/ensure_dir.ts": "9dc109c27df4098b9fc12d949612ae5c9c7169507660dcf9ad90631833209d9d",
"https://deno.land/std@0.140.0/fs/expand_glob.ts": "0c10130d67c9b02164b03df8e43c6d6defbf8e395cb69d09e84a8586e6d72ac3",
"https://deno.land/std@0.140.0/fs/walk.ts": "117403ccd21fd322febe56ba06053b1ad5064c802170f19b1ea43214088fe95f",
"https://deno.land/std@0.140.0/path/_constants.ts": "df1db3ffa6dd6d1252cc9617e5d72165cd2483df90e93833e13580687b6083c3",
"https://deno.land/std@0.140.0/path/_interface.ts": "ee3b431a336b80cf445441109d089b70d87d5e248f4f90ff906820889ecf8d09",
"https://deno.land/std@0.140.0/path/_util.ts": "c1e9686d0164e29f7d880b2158971d805b6e0efc3110d0b3e24e4b8af2190d2b",
"https://deno.land/std@0.140.0/path/common.ts": "bee563630abd2d97f99d83c96c2fa0cca7cee103e8cb4e7699ec4d5db7bd2633",
"https://deno.land/std@0.140.0/path/glob.ts": "cb5255638de1048973c3e69e420c77dc04f75755524cb3b2e160fe9277d939ee",
"https://deno.land/std@0.140.0/path/mod.ts": "d3e68d0abb393fb0bf94a6d07c46ec31dc755b544b13144dee931d8d5f06a52d",
"https://deno.land/std@0.140.0/path/posix.ts": "293cdaec3ecccec0a9cc2b534302dfe308adb6f10861fa183275d6695faace44",
"https://deno.land/std@0.140.0/path/separator.ts": "fe1816cb765a8068afb3e8f13ad272351c85cbc739af56dacfc7d93d710fe0f9",
"https://deno.land/std@0.140.0/path/win32.ts": "31811536855e19ba37a999cd8d1b62078235548d67902ece4aa6b814596dd757",
"https://deno.land/std@0.173.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462",
"https://deno.land/std@0.173.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3",
"https://deno.land/std@0.173.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0",
"https://deno.land/std@0.173.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b",
"https://deno.land/std@0.173.0/path/_util.ts": "86c2375a996c1931b2f2ac71fefd5ddf0cf0e579fa4ab12d3e4c552d4223b8d8",
"https://deno.land/std@0.173.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000",
"https://deno.land/std@0.173.0/path/glob.ts": "d479e0a695621c94d3fd7fe7abd4f9499caf32a8de13f25073451c6ef420a4e1",
"https://deno.land/std@0.173.0/path/mod.ts": "4b83694ac500d7d31b0cdafc927080a53dc0c3027eb2895790fb155082b0d232",
"https://deno.land/std@0.173.0/path/posix.ts": "0874b341c2c6968ca38d323338b8b295ea1dae10fa872a768d812e2e7d634789",
"https://deno.land/std@0.173.0/path/separator.ts": "0fb679739d0d1d7bf45b68dacfb4ec7563597a902edbaf3c59b50d5bcadd93b1",
"https://deno.land/std@0.173.0/path/win32.ts": "672942919dd66ce1b8c224e77d3447e2ad8254eaff13fe6946420a9f78fa141e",
"https://deno.land/std@0.177.0/async/abortable.ts": "73acfb3ed7261ce0d930dbe89e43db8d34e017b063cf0eaa7d215477bf53442e",
"https://deno.land/std@0.177.0/async/deadline.ts": "c5facb0b404eede83e38bd2717ea8ab34faa2ffb20ef87fd261fcba32ba307aa",
"https://deno.land/std@0.177.0/async/debounce.ts": "adab11d04ca38d699444ac8a9d9856b4155e8dda2afd07ce78276c01ea5a4332",
"https://deno.land/std@0.177.0/async/deferred.ts": "42790112f36a75a57db4a96d33974a936deb7b04d25c6084a9fa8a49f135def8",
"https://deno.land/std@0.177.0/async/delay.ts": "73aa04cec034c84fc748c7be49bb15cac3dd43a57174bfdb7a4aec22c248f0dd",
"https://deno.land/std@0.177.0/async/mod.ts": "f04344fa21738e5ad6bea37a6bfffd57c617c2d372bb9f9dcfd118a1b622e576",
"https://deno.land/std@0.177.0/async/mux_async_iterator.ts": "70c7f2ee4e9466161350473ad61cac0b9f115cff4c552eaa7ef9d50c4cbb4cc9",
"https://deno.land/std@0.177.0/async/pool.ts": "fd082bd4aaf26445909889435a5c74334c017847842ec035739b4ae637ae8260",
"https://deno.land/std@0.177.0/async/retry.ts": "5efa3ba450ac0c07a40a82e2df296287b5013755d232049efd7ea2244f15b20f",
"https://deno.land/std@0.177.0/async/tee.ts": "47e42d35f622650b02234d43803d0383a89eb4387e1b83b5a40106d18ae36757",
"https://deno.land/std@0.177.0/http/server.ts": "cbb17b594651215ba95c01a395700684e569c165a567e4e04bba327f41197433",
"https://deno.land/std@0.178.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462",
"https://deno.land/std@0.178.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3",
"https://deno.land/std@0.178.0/async/abortable.ts": "73acfb3ed7261ce0d930dbe89e43db8d34e017b063cf0eaa7d215477bf53442e",
"https://deno.land/std@0.178.0/async/deadline.ts": "c5facb0b404eede83e38bd2717ea8ab34faa2ffb20ef87fd261fcba32ba307aa",
"https://deno.land/std@0.178.0/async/debounce.ts": "adab11d04ca38d699444ac8a9d9856b4155e8dda2afd07ce78276c01ea5a4332",
"https://deno.land/std@0.178.0/async/deferred.ts": "42790112f36a75a57db4a96d33974a936deb7b04d25c6084a9fa8a49f135def8",
"https://deno.land/std@0.178.0/async/delay.ts": "73aa04cec034c84fc748c7be49bb15cac3dd43a57174bfdb7a4aec22c248f0dd",
"https://deno.land/std@0.178.0/async/mod.ts": "f04344fa21738e5ad6bea37a6bfffd57c617c2d372bb9f9dcfd118a1b622e576",
"https://deno.land/std@0.178.0/async/mux_async_iterator.ts": "70c7f2ee4e9466161350473ad61cac0b9f115cff4c552eaa7ef9d50c4cbb4cc9",
"https://deno.land/std@0.178.0/async/pool.ts": "fd082bd4aaf26445909889435a5c74334c017847842ec035739b4ae637ae8260",
"https://deno.land/std@0.178.0/async/retry.ts": "5efa3ba450ac0c07a40a82e2df296287b5013755d232049efd7ea2244f15b20f",
"https://deno.land/std@0.178.0/async/tee.ts": "47e42d35f622650b02234d43803d0383a89eb4387e1b83b5a40106d18ae36757",
"https://deno.land/std@0.178.0/flags/mod.ts": "d1cdefa18472ef69858a17df5cf7c98445ed27ac10e1460183081303b0ebc270",
"https://deno.land/std@0.178.0/fs/_util.ts": "65381f341af1ff7f40198cee15c20f59951ac26e51ddc651c5293e24f9ce6f32",
"https://deno.land/std@0.178.0/fs/walk.ts": "ea95ffa6500c1eda6b365be488c056edc7c883a1db41ef46ec3bf057b1c0fe32",
"https://deno.land/std@0.178.0/http/http_status.ts": "8a7bcfe3ac025199ad804075385e57f63d055b2aed539d943ccc277616d6f932",
"https://deno.land/std@0.178.0/http/server.ts": "cbb17b594651215ba95c01a395700684e569c165a567e4e04bba327f41197433",
"https://deno.land/std@0.178.0/media_types/_db.ts": "7606d83e31f23ce1a7968cbaee852810c2cf477903a095696cdc62eaab7ce570",
"https://deno.land/std@0.178.0/media_types/_util.ts": "916efbd30b6148a716f110e67a4db29d6949bf4048997b754415dd7e42c52378",
"https://deno.land/std@0.178.0/media_types/content_type.ts": "c682589a0aeb016bfed355cc1ed6fbb3ead2ea48fc0000ac5de6a5730613ad1c",
"https://deno.land/std@0.178.0/media_types/extension.ts": "7a4ef2813d7182f724a941f38161525996e4a67abc3cf6a0f9bc2168d73a0f0e",
"https://deno.land/std@0.178.0/media_types/extensions_by_type.ts": "4358023feac696e6e9d49c0f1e76a859f03ca254df57812f31f8536890c3a443",
"https://deno.land/std@0.178.0/media_types/format_media_type.ts": "1e35e16562e5c417401ffc388a9f8f421f97f0ee06259cbe990c51bae4e6c7a8",
"https://deno.land/std@0.178.0/media_types/get_charset.ts": "8be15a1fd31a545736b91ace56d0e4c66ea0d7b3fdc5c90760e8202e7b4b1fad",
"https://deno.land/std@0.178.0/media_types/mod.ts": "d3f0b99f85053bc0b98ecc24eaa3546dfa09b856dc0bbaf60d8956d2cdd710c8",
"https://deno.land/std@0.178.0/media_types/parse_media_type.ts": "bed260d868ea271445ae41d748e7afed9b5a7f407d2777ead08cecf73e9278de",
"https://deno.land/std@0.178.0/media_types/type_by_extension.ts": "6076a7fc63181d70f92ec582fdea2c927eb2cfc7f9c9bee9d6add2aca86f2355",
"https://deno.land/std@0.178.0/media_types/vendor/mime-db.v1.52.0.ts": "6925bbcae81ca37241e3f55908d0505724358cda3384eaea707773b2c7e99586",
"https://deno.land/std@0.178.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0",
"https://deno.land/std@0.178.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b",
"https://deno.land/std@0.178.0/path/_util.ts": "d7abb1e0dea065f427b89156e28cdeb32b045870acdf865833ba808a73b576d0",
"https://deno.land/std@0.178.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000",
"https://deno.land/std@0.178.0/path/glob.ts": "d479e0a695621c94d3fd7fe7abd4f9499caf32a8de13f25073451c6ef420a4e1",
"https://deno.land/std@0.178.0/path/mod.ts": "4b83694ac500d7d31b0cdafc927080a53dc0c3027eb2895790fb155082b0d232",
"https://deno.land/std@0.178.0/path/posix.ts": "8b7c67ac338714b30c816079303d0285dd24af6b284f7ad63da5b27372a2c94d",
"https://deno.land/std@0.178.0/path/separator.ts": "0fb679739d0d1d7bf45b68dacfb4ec7563597a902edbaf3c59b50d5bcadd93b1",
"https://deno.land/std@0.178.0/path/win32.ts": "d186344e5583bcbf8b18af416d13d82b35a317116e6460a5a3953508c3de5bba",
"https://deno.land/std@0.178.0/semver/mod.ts": "409a2691f5a411c34e917c1e6d445a6d1d53f3fadf660e44a99dd0bf9b2ef412",
"https://deno.land/x/code_block_writer@11.0.3/mod.ts": "2c3448060e47c9d08604c8f40dee34343f553f33edcdfebbf648442be33205e5",
"https://deno.land/x/code_block_writer@11.0.3/utils/string_utils.ts": "60cb4ec8bd335bf241ef785ccec51e809d576ff8e8d29da43d2273b69ce2a6ff",
"https://deno.land/x/denoflate@1.2.1/mod.ts": "f5628e44b80b3d80ed525afa2ba0f12408e3849db817d47a883b801f9ce69dd6",
"https://deno.land/x/denoflate@1.2.1/pkg/denoflate.js": "b9f9ad9457d3f12f28b1fb35c555f57443427f74decb403113d67364e4f2caf4",
"https://deno.land/x/denoflate@1.2.1/pkg/denoflate_bg.wasm.js": "d581956245407a2115a3d7e8d85a9641c032940a8e810acbd59ca86afd34d44d",
"https://deno.land/x/esbuild@v0.17.11/mod.d.ts": "dc279a3a46f084484453e617c0cabcd5b8bd1920c0e562e4ea02dfc828c8f968",
"https://deno.land/x/esbuild@v0.17.11/mod.js": "4f4e61964a551d9c0baf5bb19e973cf631cf8c66ddaf01e70070f8a100fc938c",
"https://deno.land/x/esbuild@v0.17.11/wasm.d.ts": "dc279a3a46f084484453e617c0cabcd5b8bd1920c0e562e4ea02dfc828c8f968",
"https://deno.land/x/esbuild@v0.17.11/wasm.js": "4030e7b50941ec6e06704c6b5f1f6416cc0f7f35f63daf63f184b728bea79a30",
"https://deno.land/x/fresh@1.1.5/dev.ts": "a66c7d64be35bcd6a8e12eec9c27ae335044c70363a241f2e36ee776db468622",
"https://deno.land/x/fresh@1.1.5/plugins/twind.ts": "c0570d6010e29ba24ee5f43b9d3f1fe735f7fac76d9a3e680c9896373d669876",
"https://deno.land/x/fresh@1.1.5/plugins/twind/shared.ts": "023e0ffcd66668753b5049edab0de46e6d66194fb6026c679034b9bbf04ad6f3",
"https://deno.land/x/fresh@1.1.5/runtime.ts": "b02ec1e2e32cf73a33d262b7c9dcab9468ce16cd89fd424196c71003698a4ab0",
"https://deno.land/x/fresh@1.1.5/server.ts": "f379c9aad24471a71e58fb887fa57e5cc27ad9df035987eb260541c78df38e84",
"https://deno.land/x/fresh@1.1.5/src/dev/deps.ts": "aef312af6de1315fa95fc0c32e87c56301b64efeb304193d0dce0da0634144d3",
"https://deno.land/x/fresh@1.1.5/src/dev/error.ts": "21a38d240c00279662e6adde41367f1da0ae7e2836d993f818ea94aabab53e7b",
"https://deno.land/x/fresh@1.1.5/src/dev/mod.ts": "14baa66a064961afcbad74748eeb2b99ce4bb246223ed69d8cc35b073e49b039",
"https://deno.land/x/fresh@1.1.5/src/runtime/csp.ts": "9ee900e9b0b786057b1009da5976298c202d1b86d1f1e4d2510bde5f06530ac9",
"https://deno.land/x/fresh@1.1.5/src/runtime/head.ts": "0f9932874497ab6e57ed1ba01d549e843523df4a5d36ef97460e7a43e3132fdc",
"https://deno.land/x/fresh@1.1.5/src/runtime/utils.ts": "8320a874a44bdd5905c7d4b87a0e7a14a6c50a2ed133800e72ae57341e4d4faa",
"https://deno.land/x/fresh@1.1.5/src/server/bundle.ts": "2febeb5071d0647993560807ca5b2f4cd60181d370ee8612e5db728cb10db9f1",
"https://deno.land/x/fresh@1.1.5/src/server/constants.ts": "ad10dda1bc20c25c2926f6a8cfd79ef4368d70b4b03a645f65c04b3fa7d93a8c",
"https://deno.land/x/fresh@1.1.5/src/server/context.ts": "896ca59b58d0713d8429c4ec8aea4cedb0e4c09a804a2e6ec0c81379f5f83b15",
"https://deno.land/x/fresh@1.1.5/src/server/default_error_page.ts": "9a1a595a1a2b31c9b724b04db82b8af256285536db272658d831ac9ef1d3d448",
"https://deno.land/x/fresh@1.1.5/src/server/deps.ts": "e205002c298ee6bf40af1365ced243b8cd86cf39e922ec2db2c91ef022eb72ad",
"https://deno.land/x/fresh@1.1.5/src/server/htmlescape.ts": "834ac7d0caa9fc38dffd9b8613fb47aeecd4f22d5d70c51d4b20a310c085835c",
"https://deno.land/x/fresh@1.1.5/src/server/mod.ts": "72d213444334dd2e94c757a0eee0fc486c0919399ea9184d07ad042f34edd00d",
"https://deno.land/x/fresh@1.1.5/src/server/render.ts": "6f50707bd1f6e33ed84bb71ae3b0996d202b953cefc4285f5356524c7b21f01f",
"https://deno.land/x/fresh@1.1.5/src/server/types.ts": "6579aac850ea4af5cdfee8f9552fbadebb7b50841d180b75bd90466416feee86",
"https://deno.land/x/importmap@0.2.1/_util.ts": "ada9a9618b537e6c0316c048a898352396c882b9f2de38aba18fd3f2950ede89",
"https://deno.land/x/importmap@0.2.1/mod.ts": "ae3d1cd7eabd18c01a4960d57db471126b020f23b37ef14e1359bbb949227ade",
"https://deno.land/x/lodash_es@v0.0.2/src/_DataView.js": "0c4811491cd0c415553118f42f9b31112ed58bdb3941358a99deec9347e7a829",
"https://deno.land/x/lodash_es@v0.0.2/src/_Hash.js": "7221393e8931adc88430d3badefee1568ffccf91a6efcd9dda2be498f4a09551",
"https://deno.land/x/lodash_es@v0.0.2/src/_ListCache.js": "a8c13a041707d9c96eff21d95a78326b6e2af12b067527bcba22108ce15b600c",
"https://deno.land/x/lodash_es@v0.0.2/src/_Map.js": "014aa839395eedfb215d1a994754db6716ba8c65ff3945b986270a4743b269bb",
"https://deno.land/x/lodash_es@v0.0.2/src/_MapCache.js": "fd27ffa20196943af9cbb4694555582d3045fff54b6f808269e4d3a645c3d886",
"https://deno.land/x/lodash_es@v0.0.2/src/_Promise.js": "55c26a3a24e9f2e6158d36fdeec3b34d59d9f9be08e415a7f50936429595c656",
"https://deno.land/x/lodash_es@v0.0.2/src/_Set.js": "84d53490631612489f33e3a4a9199f22c853e58b337aa1e10408e63d5129e216",
"https://deno.land/x/lodash_es@v0.0.2/src/_SetCache.js": "0dd677f901228955ec136fb35bb20c4a8dbc4c1ef63649298a29b7b0958b9b07",
"https://deno.land/x/lodash_es@v0.0.2/src/_Stack.js": "391b608ace36e0845f917ab7a5bbaab07930f9ad8b570849857ed564a0ec3a76",
"https://deno.land/x/lodash_es@v0.0.2/src/_Symbol.js": "631160c3c0cbd05ec8a3d1934ded4a312504a29f04a00be2b29372d00dd6bc6d",
"https://deno.land/x/lodash_es@v0.0.2/src/_Uint8Array.js": "0181e8a163773e63ca1c366a134df3306c5fec28f487beb326b6bb92113d619d",
"https://deno.land/x/lodash_es@v0.0.2/src/_WeakMap.js": "1248b893bd82f38179e2ac6df0ff2fa8daf5e5becd11b55d8b2073a5eaab3f47",
"https://deno.land/x/lodash_es@v0.0.2/src/_arrayFilter.js": "46a23fd1969903486b620f5de048c9347f24863f13416db0a632de56cc78b479",
"https://deno.land/x/lodash_es@v0.0.2/src/_arrayLikeKeys.js": "c441c2b158f992a5dd14bae0b35d20c3ec25a8a5b6cd439e1be0b1764e831612",
"https://deno.land/x/lodash_es@v0.0.2/src/_arrayPush.js": "ef2cb71a84885b726882f9664e3c2078279012ba7b220935b7e7390d85d89288",
"https://deno.land/x/lodash_es@v0.0.2/src/_arraySome.js": "0b50b5e018eabcb2a0b041bc02b5ae0c8d1f16914f94f376ecaf7f887cbd3aa3",
"https://deno.land/x/lodash_es@v0.0.2/src/_assocIndexOf.js": "b34ff3bbc5cf630e9ea1103eacd7bfcc208347a6b616398e515c7aee821bf8a4",
"https://deno.land/x/lodash_es@v0.0.2/src/_baseGetAllKeys.js": "45f92029359aaddc01b6aaf58370ba554430f141d1ff8879f6ef829c03ed4e44",
"https://deno.land/x/lodash_es@v0.0.2/src/_baseGetTag.js": "3a9eebe37ba231eff0380b5f76ac5b5fcee4590665642fd052d77aa51c7d063f",
"https://deno.land/x/lodash_es@v0.0.2/src/_baseIsArguments.js": "8cc4e523affa6237c8177cd7cb038ede5e6778deaf3fa9c052f3e416840e0334",
"https://deno.land/x/lodash_es@v0.0.2/src/_baseIsEqual.js": "332f33381628ed8c9849cb3e218d0e7122d47a736fea46f7abe76c1ef6904469",
"https://deno.land/x/lodash_es@v0.0.2/src/_baseIsEqualDeep.js": "64174049ab03796b0cf775075cadbf74ddbc7d5bb80c10835117417375c16528",
"https://deno.land/x/lodash_es@v0.0.2/src/_baseIsNative.js": "1557c70dbb11eba112c6f5454e3cbaf7a714656da0db17e0dfe83441a70e31b1",
"https://deno.land/x/lodash_es@v0.0.2/src/_baseIsTypedArray.js": "eb8a844c83bf159a41222acde165ab3f4a9983be77297496550164d10633b076",
"https://deno.land/x/lodash_es@v0.0.2/src/_baseKeys.js": "5ad980ce937752fa85ce2e48e981eed26ad9b0ee83a0b34491b4c032ab393aee",
"https://deno.land/x/lodash_es@v0.0.2/src/_baseTimes.js": "0d71867db092ef76aed4436956c0cf26d0990eb5d19c88f74edbe8c7ae2dfc93",
"https://deno.land/x/lodash_es@v0.0.2/src/_baseTrim.js": "8cce4af7b95677ab2c74cc39cac7abb359eaab9515427191974f5edd69ad5a71",
"https://deno.land/x/lodash_es@v0.0.2/src/_baseUnary.js": "25d6f22dcecef2d761e3059330425d1c585dfa81d50ba1dcd82d5524bfa78b53",
"https://deno.land/x/lodash_es@v0.0.2/src/_cacheHas.js": "142cd8ff86e5e823b1262c6ae0e7843b28c3b0e806c502f7d11daddf941cbc14",
"https://deno.land/x/lodash_es@v0.0.2/src/_coreJsData.js": "020778ed390efefeb8ea3cf88873e9e2818784b3e26fa001ec51fa81c71d0392",
"https://deno.land/x/lodash_es@v0.0.2/src/_equalArrays.js": "ef1ec1ba10240336affff703995642b5f44f9b9278fa81559e4f7ca231877413",
"https://deno.land/x/lodash_es@v0.0.2/src/_equalByTag.js": "72a492144060bc60415836aa1f8dc60949a75923f26d47c6007f16da092ef8b0",
"https://deno.land/x/lodash_es@v0.0.2/src/_equalObjects.js": "c386d0f1a6cb4d2a8b2803ef06cd69199b2e00c7d3062a6ea8ab9b0308bac243",
"https://deno.land/x/lodash_es@v0.0.2/src/_freeGlobal.js": "0b65c37b3c1ce6d1800cb59a330dde73f1009f0d10eeaf8fd45f7607b87db4c5",
"https://deno.land/x/lodash_es@v0.0.2/src/_getAllKeys.js": "01e917e05dd9a3dce40c4b68fe47fe57b6b5a349074e00a4a60768b95fada6e5",
"https://deno.land/x/lodash_es@v0.0.2/src/_getMapData.js": "4ab0307467b45546bd3d8146d67f0e123f2049e6934722653803fe90b3484374",
"https://deno.land/x/lodash_es@v0.0.2/src/_getNative.js": "b93d64fd14cab48b0ad9b0f1b896ee8dcd74d8d5a20ca9cae6f34aa4a68ae9ef",
"https://deno.land/x/lodash_es@v0.0.2/src/_getRawTag.js": "0023dec54160317b70d52df1d7918638bc16a2869b1bf355f0a4f3e755aa6faf",
"https://deno.land/x/lodash_es@v0.0.2/src/_getSymbols.js": "34d1bb981fb74a7c1193363e21f8d2634aca05436151bc2297bd9bbf0cd8080c",
"https://deno.land/x/lodash_es@v0.0.2/src/_getTag.js": "86877c73f440b311c85b96f32a5e05995f0e247ef86091bc3d5f4e585439f8c6",
"https://deno.land/x/lodash_es@v0.0.2/src/_getValue.js": "afff70502a4a536f971f961811013811c177e6f885d1e7e4e41c48c08ea6d6c7",
"https://deno.land/x/lodash_es@v0.0.2/src/_hashClear.js": "54d4b21fbc05b32b246c4449e27a30628f9d8b6749c08ae965ff8c81af6dad67",
"https://deno.land/x/lodash_es@v0.0.2/src/_hashDelete.js": "eaf93621141b5c23d99a299c6f8620192faf0fcc71f4f00c01ce5de8f98bc92a",
"https://deno.land/x/lodash_es@v0.0.2/src/_hashGet.js": "5aa4530201b81f25dc5609240b855f11a8bdd85d92c6bfb8cb2566758bfeaac7",
"https://deno.land/x/lodash_es@v0.0.2/src/_hashHas.js": "92a91d1122b450660d889520e13f185829e296334b1cc708a7b0009a2c568b71",
"https://deno.land/x/lodash_es@v0.0.2/src/_hashSet.js": "6535755fba2510b74079e573dc12f8c4f750131793d658ace64cf128fd1e0db2",
"https://deno.land/x/lodash_es@v0.0.2/src/_isIndex.js": "33b5bf1805dd076edfc1199e114995a62170f8d6c835e0035ec05099ae29fa97",
"https://deno.land/x/lodash_es@v0.0.2/src/_isKeyable.js": "207b697e802fc7f957d1275f7da727f59c6673e58ee2078fbc1af56f5f08c0de",
"https://deno.land/x/lodash_es@v0.0.2/src/_isMasked.js": "cc641b21108046e4ebe15220dae4f7ad463760596800ebf31d5e53df1b98f152",
"https://deno.land/x/lodash_es@v0.0.2/src/_isPrototype.js": "df65c802abe765ca4473d3dd632c0b3d13e9f2397dedd7cf9742f0157b2396ed",
"https://deno.land/x/lodash_es@v0.0.2/src/_listCacheClear.js": "e0e283b9176131c84766c243101a75d90566b4577e5c70cc6a38ad6266d805f6",
"https://deno.land/x/lodash_es@v0.0.2/src/_listCacheDelete.js": "4f60c332ff1ea93b47e744cfbeccb8cc65eed33e7bb302d6bad1fb596f70b186",
"https://deno.land/x/lodash_es@v0.0.2/src/_listCacheGet.js": "25d578131e42d496bf92590cc2daa636203fc0512eeab29e2add3ac569921e03",
"https://deno.land/x/lodash_es@v0.0.2/src/_listCacheHas.js": "c091833394e006cf700731a117a75310786726246843f225de698e94f1d1e798",
"https://deno.land/x/lodash_es@v0.0.2/src/_listCacheSet.js": "0696b9f99b4ed89c08725c8acc805b7cc493078ea0fb8d9153bfb920878fa029",
"https://deno.land/x/lodash_es@v0.0.2/src/_mapCacheClear.js": "0be01bc64f84e1252f501dbe68d2166eb97ac321bf6638415478ff24a26ac388",
"https://deno.land/x/lodash_es@v0.0.2/src/_mapCacheDelete.js": "a52b87a49edecdb1b47793b5bb26d41e4bf379c369a420949302e1b1562b5af7",
"https://deno.land/x/lodash_es@v0.0.2/src/_mapCacheGet.js": "bb71dbbe31d7fbd56016b622ea28b4c1ec570a8c910030dc927465737b458a4e",
"https://deno.land/x/lodash_es@v0.0.2/src/_mapCacheHas.js": "5b9c230d5e00aba2d482404cc8dbe327b23ad29325d13a0e49e93cfd0b1bf54d",
"https://deno.land/x/lodash_es@v0.0.2/src/_mapCacheSet.js": "43318a641896356f4b187bee7aad9be1147b766722108a7e7425d7e1ea322bfa",
"https://deno.land/x/lodash_es@v0.0.2/src/_mapToArray.js": "fd24c54b48cbdcb659a15dc013554a473fa7524b7c5fa2a7f8dc2229c7ad2bcc",
"https://deno.land/x/lodash_es@v0.0.2/src/_nativeCreate.js": "59c4a564c25a021902259cb237cfa331daf056423d359258ac968c60f51aa324",
"https://deno.land/x/lodash_es@v0.0.2/src/_nativeKeys.js": "df95037fd30b575dc9a1173fea65d68bd8cdb07ba10186b7cc43c4d7c69a92f9",
"https://deno.land/x/lodash_es@v0.0.2/src/_nodeUtil.js": "f81d8e969afead3562231a1c368fcf884b51339ee04aff07a2b67f8ba794f03b",
"https://deno.land/x/lodash_es@v0.0.2/src/_objectToString.js": "8f1bb6043dc27219e71dfae28900a7f214a0856118a628efeb120169fe46fe8c",
"https://deno.land/x/lodash_es@v0.0.2/src/_overArg.js": "599268d0a0a7da23b421ca0cfefbea1f295e44c33bab99fb87df38f4ef97bb9c",
"https://deno.land/x/lodash_es@v0.0.2/src/_root.js": "df58ff96c454ca91ace20d20e6af49b354c70dfba7e737adc00cd23e8ff77168",
"https://deno.land/x/lodash_es@v0.0.2/src/_setCacheAdd.js": "401386f4cc34e3675ee768b340e521df8b021abb3b9e8fba9b2a49614d54a189",
"https://deno.land/x/lodash_es@v0.0.2/src/_setCacheHas.js": "fc24b8606ffad00aab53dd47f42225ca4a97272b7b90df1db7f75a57cb49761e",
"https://deno.land/x/lodash_es@v0.0.2/src/_setToArray.js": "316f948fca04c5b007fe78c6edc199a69496beef8d395f44bdc0dbfd7a46a1ed",
"https://deno.land/x/lodash_es@v0.0.2/src/_stackClear.js": "2f18f696265ae6318deb51419e121ab543b4fd9ff240892e8e054d944db8020a",
"https://deno.land/x/lodash_es@v0.0.2/src/_stackDelete.js": "ae947fc8f29882a437db228bcdac90cd048f94bdd758e508b53987be2e28cdfe",
"https://deno.land/x/lodash_es@v0.0.2/src/_stackGet.js": "ae5633328aae57109e1ce84e70a587c2ba90503294f758ab8086d032ebb40897",
"https://deno.land/x/lodash_es@v0.0.2/src/_stackHas.js": "06066c99b9909bdc25bb702b579ca29a69ab478d9819506af29aa7e6476eddba",
"https://deno.land/x/lodash_es@v0.0.2/src/_stackSet.js": "4f96a1dfb190aae58f59bc26cd1a27fae1d10abc338e1f57a67e69d47b832cbe",
"https://deno.land/x/lodash_es@v0.0.2/src/_toSource.js": "a2333d6455d5a8802b8e8d64f0de422f04a4603cf477429d2baabb8021ec9032",
"https://deno.land/x/lodash_es@v0.0.2/src/_trimmedEndIndex.js": "1ff25e476022aa45aa96dbea87228e3ff709c1f3b8b82561b7f040279575a2ef",
"https://deno.land/x/lodash_es@v0.0.2/src/debounce.js": "d5f2c62200af44e14130d0018a27a47b0d6256220ea41b35b8d8fd0807805030",
"https://deno.land/x/lodash_es@v0.0.2/src/eq.js": "3a51729bde3af1d9bacf9b67e966d8c154e22b02f5e1cecc13f53f7f00889c13",
"https://deno.land/x/lodash_es@v0.0.2/src/isArguments.js": "08791025dc5d7ec5183e290aa2aa6a9c4af78703f0d42d1b9421b607c3199fcc",
"https://deno.land/x/lodash_es@v0.0.2/src/isArray.js": "0d9bcdfdf53955d9253076ddd68e0b992b2c91fb8364baa2ca971e57cbb74e4b",
"https://deno.land/x/lodash_es@v0.0.2/src/isArrayLike.js": "46956ba526a01c3371fe26a492bf2a247b20d995e6891f2ac99a17b1ab64b49f",
"https://deno.land/x/lodash_es@v0.0.2/src/isBuffer.js": "683ac01368bb0b51e7571332797cdec13cf5fa26a79ad20764045f01b1d249d2",
"https://deno.land/x/lodash_es@v0.0.2/src/isEqual.js": "60c66b9d8e67d807bb91d2487f05a5400c14031b4c59aee9920646529d494d17",
"https://deno.land/x/lodash_es@v0.0.2/src/isFunction.js": "4cf0f598213e142e5d9ad09f17d3611723a9e2e3def000a39edbf38b493b3b08",
"https://deno.land/x/lodash_es@v0.0.2/src/isLength.js": "ef8193123dc3fbd12be9893aa39aea7df0a779074e604d853c56da1c09d24e11",
"https://deno.land/x/lodash_es@v0.0.2/src/isObject.js": "fc44c8f265db1492ea04f777d9e2d8598b44d481f5eb38360cb58c1e45b8cbd9",
"https://deno.land/x/lodash_es@v0.0.2/src/isObjectLike.js": "e45d69136695e8568c6fb3c7327f96ac1a8ff7284b1b22f26fb4654255fd0c6c",
"https://deno.land/x/lodash_es@v0.0.2/src/isSymbol.js": "f0dc1666c3cec2306cd4fd0f63a9a7ab1f25ed21d2db6664b1edc81bd3641a41",
"https://deno.land/x/lodash_es@v0.0.2/src/isTypedArray.js": "ea3531a60d17525b79f484377cd4053f32fec478822dd2b51ca63ade12520737",
"https://deno.land/x/lodash_es@v0.0.2/src/keys.js": "cdcc1e10b113af10125daaae5cde3135d581e7f53a22d1190fa12bee62c3315e",
"https://deno.land/x/lodash_es@v0.0.2/src/now.js": "1304c9968c6c069d6529465225da0dbccf18055c0e340eda213ce6c47565a58f",
"https://deno.land/x/lodash_es@v0.0.2/src/stubArray.js": "fbb65461e7df8d72ba98065d2db95b3b781a66c58e396e2c76f8264d427b705e",
"https://deno.land/x/lodash_es@v0.0.2/src/stubFalse.js": "fd1d278ab0f9329d2b39c180bb97fcbfb609ec117f89443fc2ed898b633493ea",
"https://deno.land/x/lodash_es@v0.0.2/src/throttle.js": "d236ef311beb5042f68688ddc473e473edfe9be3b1ec5806431ad97828f4ac16",
"https://deno.land/x/lodash_es@v0.0.2/src/toNumber.js": "05f8ad055069ca69ac0c91112a70906367e167a088bd4d6b84f15cb0b100a2e0",
"https://deno.land/x/optionals@v3.0.0/mod.ts": "8e12b21e534e7f7304560bb07b46b628d5c953e5342f092a82a1300a60546bf2",
"https://deno.land/x/optionals@v3.0.0/src/option.ts": "5e0e6e7e4e5d95479b36a0da0e1bb1a02741deb1b0b6541adafd241e06022005",
"https://deno.land/x/optionals@v3.0.0/src/result.ts": "18a98e70e53f921995d38ffd3f2914b3b490a28c9b7e95fb283fcbfb4a484a53",
"https://deno.land/x/preact_ahooks@v0.0.6/createUpdateEffect/index.ts": "2f31a3347838dca97d2849c58b8434cb13b3effdbaed700b7f31bebc71cc719f",
"https://deno.land/x/preact_ahooks@v0.0.6/createUseStorageState/index.ts": "d52fab51e9da3abc6db66a6d98a4233e67f2ea428450a15c7c149fd367a6c6ec",
"https://deno.land/x/preact_ahooks@v0.0.6/deps.ts": "ee612845914cf4d7cf434879c4d897044ff552feaa0b65656076f9d55bed78eb",
"https://deno.land/x/preact_ahooks@v0.0.6/mod.ts": "64f38650d940cd15cf90c16a6bd707cd485982de0129b5b99ac7c102c283c939",
"https://deno.land/x/preact_ahooks@v0.0.6/types/debounce.d.ts": "3d787bcf72347381145b2b1c1a343d83a11c053c2f8dd27790dcbc00852fa38b",
"https://deno.land/x/preact_ahooks@v0.0.6/types/throttle.d.ts": "59251b9847dc87ddb772195b7f7b043a08d675469bfbe1cd21cc8373bd951436",
"https://deno.land/x/preact_ahooks@v0.0.6/useAntdTable/index.tsx": "33e7ae578986047b1088c709ae1a6a0c6acd8ac4800b304568e8bd8e954bb695",
"https://deno.land/x/preact_ahooks@v0.0.6/useAntdTable/types.ts": "8bc561719d2bfb23e63284d7d5e1df382b7b0f6deaa4d44f1920d844dd531e31",
"https://deno.land/x/preact_ahooks@v0.0.6/useAsyncEffect/index.ts": "13e4d1f3514425793048a9c9a9dca94b141fe9d01a77589e941ad4de71d648b5",
"https://deno.land/x/preact_ahooks@v0.0.6/useBoolean/index.ts": "493692aaf87a28e488a2ce7c6942890334ec67edc44845f423d5ab843cfa62b6",
"https://deno.land/x/preact_ahooks@v0.0.6/useClickAway/index.ts": "f47ae8fc7b531161c8bcac74359c83871d3b1f295a54a0942727e6624a502d1c",
"https://deno.land/x/preact_ahooks@v0.0.6/useControllableValue/index.ts": "9e6cc552b1a9877d875d109bb6616eeb8b50cddeb3a27131839599ec74cc8f3a",
"https://deno.land/x/preact_ahooks@v0.0.6/useCookieState/index.ts": "610e95eb5504b453d5322ba9e5edaa1a87d404a4a6476c80ed27f7cf87cbe6bd",
"https://deno.land/x/preact_ahooks@v0.0.6/useCountDown/index.ts": "0a074f3cb1fbc3ef1e35588d8e1914ce41ade29a450e94f5f1316422a141626e",
"https://deno.land/x/preact_ahooks@v0.0.6/useCounter/index.ts": "75dae5f99dbc3ad6f9ef7ee3a0d267ec0c325cc6641b28763ac3da00bf030c25",
"https://deno.land/x/preact_ahooks@v0.0.6/useCreation/index.ts": "608c480a88ff8d02fbe958570c0715338730164d389cc79acb6dddbc2792a0d1",
"https://deno.land/x/preact_ahooks@v0.0.6/useDebounce/debounceOptions.ts": "f49d5cce359ddd40bfe264a6c91f349d9ced4b9b71e427e3b361b3bd38e172a7",
"https://deno.land/x/preact_ahooks@v0.0.6/useDebounce/index.ts": "51d8640bfbaaf07e153895bd35e23feedd392b2f0415d5f3a02ee517c78a24ec",
"https://deno.land/x/preact_ahooks@v0.0.6/useDebounceEffect/index.ts": "b6988d77357016df0e5b1a7dabe5a72887b10aaebb59e253717559618cf59910",
"https://deno.land/x/preact_ahooks@v0.0.6/useDebounceFn/index.ts": "ab958596dfaa723d63154a980b154e387f3250db038ff37bf5fb9593779a1340",
"https://deno.land/x/preact_ahooks@v0.0.6/useDeepCompareEffect/index.tsx": "4f91f026ac500ac388155b7ac6f4714d3303a836f6bf354144147b99b1dceb4d",
"https://deno.land/x/preact_ahooks@v0.0.6/useDocumentVisibility/index.ts": "d8b1402cb69ede32b4e9c283d0605fbbc3e8b4891259578554d2e4b8054f08fc",
"https://deno.land/x/preact_ahooks@v0.0.6/useDrag/index.ts": "fa077a17015248b44a2e005e1635ba2cfd50184a9c82a39058b54ec458c601e2",
"https://deno.land/x/preact_ahooks@v0.0.6/useDrop/index.ts": "cad2118bc88dca3214ac3f4a91ceb8b4944bbaade7a0b921fe7d6617bca3a11b",
"https://deno.land/x/preact_ahooks@v0.0.6/useDynamicList/index.ts": "e66872685e6d0d5e5be209edff0024dea2a6b5e30707f1af85b96711de5a05a5",
"https://deno.land/x/preact_ahooks@v0.0.6/useEventEmitter/index.ts": "fc8445436c1539b783712b8062380bcc2e8d7882c6cd7bcc35efb3403b29dd3e",
"https://deno.land/x/preact_ahooks@v0.0.6/useEventListener/index.ts": "5fc347037695a33f8c9a25da73a63ee24bfb78b58a9f1379e58e1b7462b95553",
"https://deno.land/x/preact_ahooks@v0.0.6/useEventTarget/index.ts": "1f81a12822142f57cd631bc601d01145e1cf3c0c2bf26fd3bc85b982ee2a5fd4",
"https://deno.land/x/preact_ahooks@v0.0.6/useExternal/index.ts": "c8d5b4839b77727d1755d6ab6f8b03d58cfeb39ca49b0afa3ec02bd414418601",
"https://deno.land/x/preact_ahooks@v0.0.6/useFavicon/index.ts": "a9f291e25bce4d2c56dfb3052f640e5d6a7b2d1c814f033ab81560e895eb2005",
"https://deno.land/x/preact_ahooks@v0.0.6/useFocusWithin/index.tsx": "ce2e3256dcc6c9a55ba4ad2d7dea6f32ad38835ec8ec5cb55d5ae70072b0087e",
"https://deno.land/x/preact_ahooks@v0.0.6/useFullscreen/index.ts": "c6396a19bff971eb8c23263499699aa3c3e563235408cde1dbeee0520142c616",
"https://deno.land/x/preact_ahooks@v0.0.6/useFusionTable/fusionAdapter.ts": "3befdd4ec156b5c7121de7f9c392671a59e601a255594e7084e19aae07858d86",
"https://deno.land/x/preact_ahooks@v0.0.6/useFusionTable/index.tsx": "db6f9be0aa56eb15ad493e7dd6fb8458b7ed32cccddb61e37cc60ce5c95a4e55",
"https://deno.land/x/preact_ahooks@v0.0.6/useFusionTable/types.ts": "c4f2739a09e5c37f5e6a9a912f7784dd16d2381ee7e19f121521495bf84e3fbf",
"https://deno.land/x/preact_ahooks@v0.0.6/useGetState/index.ts": "cc2a9608205cbdbc0962add581cf26c4f895534b4a04b1d02e0bc7f7d8cd4821",
"https://deno.land/x/preact_ahooks@v0.0.6/useHistoryTravel/index.ts": "956f7b88e7c62208d134893963deb03489e5ca6d5eaba18dab593141ac961219",
"https://deno.land/x/preact_ahooks@v0.0.6/useHover/index.ts": "327a82f664f2feab1cbc118d265fd7780cf150624090fab40530bbe4d2289391",
"https://deno.land/x/preact_ahooks@v0.0.6/useInViewport/index.ts": "1e7c1856931fe8a3947f3682411d181beeccbd67f736ebbc85e2c8f7c7ca4f42",
"https://deno.land/x/preact_ahooks@v0.0.6/useInfiniteScroll/index.tsx": "5659894850e9416a27424a3de99992e64e41d8da5237779294785d1f6d2925fb",
"https://deno.land/x/preact_ahooks@v0.0.6/useInfiniteScroll/types.ts": "6ae4978938f11932419975d2f20d68eed4f5c9632de54102cd9995a29498267a",
"https://deno.land/x/preact_ahooks@v0.0.6/useInterval/index.ts": "b05624932614efdd877ea0d0e50f3749913c42215bdb9527da841d777d7efd1f",
"https://deno.land/x/preact_ahooks@v0.0.6/useIsomorphicLayoutEffect/index.ts": "c8b6d8fc5ed0301f781dcd8eda7beb30f8c756a4a7f7d134483104463b2bb328",
"https://deno.land/x/preact_ahooks@v0.0.6/useKeyPress/index.ts": "ce41adfaef882f5d45ed9df06f3541576f4b073ca4bef655b8a16bdfc0c26cb6",
"https://deno.land/x/preact_ahooks@v0.0.6/useLatest/index.ts": "d491fb08721e98cd0526240d1571e788d39dafa4a33a4c2a649b5436cb3cfbf1",
"https://deno.land/x/preact_ahooks@v0.0.6/useLocalStorageState/index.ts": "42652f576001dbf786e2018019cb141f03dbfb29c6d5b670e5ec6fc37924dae8",
"https://deno.land/x/preact_ahooks@v0.0.6/useLockFn/index.ts": "66c7e29e2fb02a48fc4344c8276daab578f8b8a1e276a2b60c63c61f9406fc9d",
"https://deno.land/x/preact_ahooks@v0.0.6/useLongPress/index.ts": "5342c0902bfe1b72aab59a528f3ede6f318b43e7de901e718fd53810f2aa42ce",
"https://deno.land/x/preact_ahooks@v0.0.6/useMap/index.ts": "171e76bb406d9228988126b0c9b450d18eb93a045e701d782659367c4cc04b14",
"https://deno.land/x/preact_ahooks@v0.0.6/useMedia/index.ts": "c617cfdba66bbc90820626b32f3bace7292715b1a8859439f2cf97a231a4387c",
"https://deno.land/x/preact_ahooks@v0.0.6/useMemoizedFn/index.ts": "d1b65979a97d46db7d6967fdb7d658b7e75379a9949705d6a118a1d8f1aed417",
"https://deno.land/x/preact_ahooks@v0.0.6/useMount/index.ts": "f822ace9cc8ca041e08fd0b4751aa44a7357a0f1de43284814bca42b9b570ecf",
"https://deno.land/x/preact_ahooks@v0.0.6/useMouse/index.ts": "74fe397575cd3679cd95d1b4486b7a06f422ada1fee713a28e32e2e88e41c16d",
"https://deno.land/x/preact_ahooks@v0.0.6/useNetwork/index.ts": "4b57b5dc353ef36d74fbb12e0fe2dde33b52abc46167d7a8ffc999579ced3169",
"https://deno.land/x/preact_ahooks@v0.0.6/usePagination/index.ts": "5fc35474528ce67d90ac7934f49a58070283018fd4895ce489f9c888bc464ec4",
"https://deno.land/x/preact_ahooks@v0.0.6/usePagination/types.ts": "f00de569a83a2d377408cbc6835901a569fc2d3137c66e24620fa958acced1f7",
"https://deno.land/x/preact_ahooks@v0.0.6/usePrevious/index.ts": "e8bee72e6a99585c701c5d1f689b7f8c1964480aafe74b1d03db356269b4cde4",
"https://deno.land/x/preact_ahooks@v0.0.6/useRafState/index.ts": "ddd3ac5508b7de759b8b1883404883e0042b4f90bd80bd3244f88c9d0649549e",
"https://deno.land/x/preact_ahooks@v0.0.6/useReactive/index.ts": "6858a1eaf119ec4f32115ae488e56ee064aa6987f3528243f571785c42f6ceab",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/index.ts": "a73e509fffdeaa2c3ebd8c6e957d5990cc60f89d8b79b454a3dd3a4af21704f8",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/Fetch.ts": "bd77288cd083083707e9953343d579be1f105ab6b485f9ee82df4bd30069fa9b",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/plugins/useAutoRunPlugin.ts": "7510240af6725b143793407a187d6337cb15953f8ff77d418f3e1b8ca80f45c6",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/plugins/useCachePlugin.ts": "4620ceb24d2b5fcabf1ed01a89882bda84145b4a78fcd61ba1831cdbab5ff9d6",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/plugins/useDebouncePlugin.ts": "0d26f7bfd7b160b3aa8e82efedb3c875a25e45214daa932cd662685df0db7e47",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/plugins/useLoadingDelayPlugin.ts": "499a6153ba72ad3aac5c9c331257b3880c3aed01defb81b16a2732f53ac8bc3a",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/plugins/usePollingPlugin.ts": "c1c2dc212baf45a221b2b70be47546ce05fe5e3dd8704c962815fdcdc6f7b079",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/plugins/useRefreshOnWindowFocusPlugin.ts": "dda6d00833c7347909fc733a7b8a1807b2e407c07786d6a58c00f1b402fec672",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/plugins/useRetryPlugin.ts": "44a32d95e20ae7fcfd3308009e6d677231f2543d7b25755ca04ff752f0f94dad",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/plugins/useThrottlePlugin.ts": "c7a8f748463a72336af38e4a215919b76436e172cd932e9ff163325f5a06a97e",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/types.ts": "b3334edff9a0fd5ccde5862aef974f2a37e7758ff4ec0768cfd54180a0a472dc",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/useRequest.ts": "c26b4f4f29fa1b16401905942da58a11371bccc2d87c33a366e0c9fa2e74cd08",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/useRequestImplement.ts": "fc38a7bcfe9de33ab8b7bcc6ba71bea5a466e8e33983dbdc5a470d6adf65dbd5",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/utils/cache.ts": "5108e78324c19fde80b1bd2621516cbd47aaed434854f23a918ab6eef2b58fc6",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/utils/cachePromise.ts": "78c97b56e03cf60f44f293819843385b6a05af9b143b17ee2cdbcccd665a4942",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/utils/cacheSubscribe.ts": "4b695c64f6e862403ce3496a7679d0b2c7896cf79d4a5af2a88110e0193a292f",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/utils/isDocumentVisible.ts": "9194a5a4f85e1cde176bcbde14ee7cf107af29c50542841038353905b7fd714f",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/utils/isOnline.ts": "03c5fdb00ba0f24615cdc7deb2e51e47bd22f6c3a1e54efdef79fb72328d5eaa",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/utils/limit.ts": "1ad26e28207dcdfbebefc0eca8147b0bddc7d8eec1b6eb45a4aa395790fb8e43",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/utils/subscribeFocus.ts": "55c12f72c9400f1e33d7c48b18063d3d05832780227734faf01961d60fd84752",
"https://deno.land/x/preact_ahooks@v0.0.6/useRequest/src/utils/subscribeReVisible.ts": "111077edcad0386aeb9ab8249398c8067f1a8f235c660911d6a30458cf1fbf8a",
"https://deno.land/x/preact_ahooks@v0.0.6/useResponsive/index.ts": "d3187c697699cf96a6fa7b4c3edfdc22eba292fb86d6788b69a95c444a5c549f",
"https://deno.land/x/preact_ahooks@v0.0.6/useSafeState/index.ts": "97e2e50522ac9da7a954ebb414586fd21847c6524df96408f861fbf759552f1b",
"https://deno.land/x/preact_ahooks@v0.0.6/useScroll/index.ts": "984ab220d7dc9d76e3ee617fc368ed7b8bf7fca84c6d3dd000315adbf19714fa",
"https://deno.land/x/preact_ahooks@v0.0.6/useSelections/index.ts": "786f462a062c90b0c3fc5886acb625d9db2d63e733ce457b7ec4352370898d94",
"https://deno.land/x/preact_ahooks@v0.0.6/useSessionStorageState/index.ts": "21bb7c398300dfabf647707e03df3b46735e64c60b07228afe1180216fcb1b1e",
"https://deno.land/x/preact_ahooks@v0.0.6/useSet/index.ts": "3d1d28559528d1f6860a44449f440de33fb36a0836984e399d91971ba341d28d",
"https://deno.land/x/preact_ahooks@v0.0.6/useSetState/index.ts": "e623d05863d45df5777eb831a2d0ac84a3a0e1f4464b6e63262a9b8d99e4b8c2",
"https://deno.land/x/preact_ahooks@v0.0.6/useSize/index.ts": "ef7f2aecaccbf3a80276df192ec190b9c0d483b9dbfa555fadf4c4aa8bb67287",
"https://deno.land/x/preact_ahooks@v0.0.6/useTextSelection/index.ts": "31df55138e33f30afa5078c3a9b65045981d04460f93d15d7e7d78a757066301",
"https://deno.land/x/preact_ahooks@v0.0.6/useThrottle/index.ts": "23eb3d976d6fd83f92346920a35226555ed5c1b9f3e25cca58323a5586621880",
"https://deno.land/x/preact_ahooks@v0.0.6/useThrottle/throttleOptions.ts": "54da3380f46f57db25efcb8e2319d32cb03c9c5b6bab7b8b6830a249a840a8ec",
"https://deno.land/x/preact_ahooks@v0.0.6/useThrottleEffect/index.ts": "43d6b3c2eda5b0c601d2f00421d14866611e72966c511cfe8bdc7c235aab947d",
"https://deno.land/x/preact_ahooks@v0.0.6/useThrottleFn/index.ts": "1470e5e15703d970c99cdf841f03a1529acbed42f7cc61ab4ef4158dff9d9a1d",
"https://deno.land/x/preact_ahooks@v0.0.6/useTimeout/index.ts": "045b2f2aa4d5de5d3a604e4b737f66ca6fc02192ea2245ae173b7eef6d4a5f08",
"https://deno.land/x/preact_ahooks@v0.0.6/useTitle/index.ts": "7b4251d89b3af74b608e535bcfac7c0d77f2e703a65ec26bf0d03a2cfae5ecdb",
"https://deno.land/x/preact_ahooks@v0.0.6/useToggle/index.ts": "a5a711eb7061cf779c262c1200ba6a8795dd120cd9706fef4a05eaaf89f2a3f1",
"https://deno.land/x/preact_ahooks@v0.0.6/useTrackedEffect/index.ts": "624f468a160ae8123d5d73ac0a23959140493fc9d459792d6dfc27ff0ac91559",
"https://deno.land/x/preact_ahooks@v0.0.6/useUnmount/index.ts": "bd23db9424b169f9f50afd2b36e3758be834c5d0a013ec313db473a9b3ca9fdb",
"https://deno.land/x/preact_ahooks@v0.0.6/useUnmountedRef/index.ts": "12ecac1165671062182175809493ff226704b0a00593aa281ca37b7ba5debba3",
"https://deno.land/x/preact_ahooks@v0.0.6/useUpdate/index.ts": "5190207396b5fcb767a3c9b369320f5819ebf9faf3f03e75143b4a2270fae514",
"https://deno.land/x/preact_ahooks@v0.0.6/useUpdateEffect/index.ts": "6498c7936116415e7642d6a56f0c197a7b00e7ce869d307c26e2cf3f4fad262b",
"https://deno.land/x/preact_ahooks@v0.0.6/useUpdateLayoutEffect/index.ts": "ef3a53ae561991e04712e0c3ebee8ccbb1a1efd9820f32ab30724d9fbd130c9a",
"https://deno.land/x/preact_ahooks@v0.0.6/useVirtualList/index.ts": "869c8be12341dfcb92c7e29cb22edd00c41040a3b2138ba654d96d29269cdd1f",
"https://deno.land/x/preact_ahooks@v0.0.6/useWebSocket/index.ts": "af1f71e5563ff9743ef33bab19ce27dbfa2ef4b834a39bff3d67baa2a5e7d233",
"https://deno.land/x/preact_ahooks@v0.0.6/useWhyDidYouUpdate/index.ts": "e721d0d4c4beab35241be401b567f822ec0b7126d90161b9fd8835c02de999c0",
"https://deno.land/x/preact_ahooks@v0.0.6/utils/canUseDom.ts": "9b0590d0f3ae763c438cab36185a8930fc4caadd02cca05b751b5f0a77902a42",
"https://deno.land/x/preact_ahooks@v0.0.6/utils/createEffectWithTarget.ts": "3f54149b5aa5751ed8ebc6912ec0ff6246ae2690fe1224c400c6d2f3afa44597",
"https://deno.land/x/preact_ahooks@v0.0.6/utils/depsAreSame.ts": "1d5ee6d18439c83c3ed3f505800dde07fd5fc4b813b4f3f65bf366a6a71a8abd",
"https://deno.land/x/preact_ahooks@v0.0.6/utils/domTarget.ts": "bcac5b997c2de50afbac8bc24731775c26d4231e99388922ab5ab2f375235123",
"https://deno.land/x/preact_ahooks@v0.0.6/utils/index.ts": "614f757dc9b8df35c39e8be6e3fdfd99702c261b90c758904afbc3cd7d7c1107",
"https://deno.land/x/preact_ahooks@v0.0.6/utils/isBrowser.ts": "5e8791e58b2b1152d918802ad8f1bd62dd8352fc9c8f663950466ddebbdd29bf",
"https://deno.land/x/preact_ahooks@v0.0.6/utils/rect.ts": "764483e5408aa0e784f3b65881e190b46ce2fe544383adfb476d0929c7cd6a2d",
"https://deno.land/x/preact_ahooks@v0.0.6/utils/useDeepCompareWithTarget.ts": "bffb1a5a70fc2ee1951d309f3ddfa9f8acc9a096cffc815184246642c5dfc2f4",
"https://deno.land/x/preact_ahooks@v0.0.6/utils/useEffectWithTarget.ts": "605ab52be6db2e3480d575385b57d75f5c013e06f4e2d46744132eaeab0f3c58",
"https://deno.land/x/preact_ahooks@v0.0.6/utils/useIsomorphicLayoutEffectWithTarget.ts": "7cce9767c926fac08296c200d449929d93e86ca7165029baa9db2ebb8cb5956f",
"https://deno.land/x/preact_ahooks@v0.0.6/utils/useLayoutEffectWithTarget.ts": "a1978c2e80d50bef6d64037940347f1bc44c421812af90ffeb7634fe753c95eb",
"https://deno.land/x/rutt@0.1.0/mod.ts": "4662ad4f687740ac612b779ed4c62eecebd718b56d24a07f719ec3b24464c139",
"https://deno.land/x/ts_morph@17.0.1/common/DenoRuntime.ts": "537800e840d0994f9055164e11bf33eadf96419246af0d3c453793c3ae67bdb3",
"https://deno.land/x/ts_morph@17.0.1/common/mod.ts": "01985d2ee7da8d1caee318a9d07664774fbee4e31602bc2bb6bb62c3489555ed",
"https://deno.land/x/ts_morph@17.0.1/common/ts_morph_common.d.ts": "ee7767b0c68b23c65bb607c94b6cb3512e8237fbcb7d1d8383a33235cde2c068",
"https://deno.land/x/ts_morph@17.0.1/common/ts_morph_common.js": "49a79124b941ba2b35d81ac9eb90fc33c957b2640cdb97569c1941bac5a3bbdb",
"https://deno.land/x/ts_morph@17.0.1/common/typescript.d.ts": "57e52a0882af4e835473dda27e4316cc31149866970210f9f79b940e916b7838",
"https://deno.land/x/ts_morph@17.0.1/common/typescript.js": "5dd669eb199ee2a539924c63a92e23d95df43dfe2fbe3a9d68c871648be1ad5e",
"https://deno.land/x/ts_morph@17.0.1/mod.ts": "adba9b82f24865d15d2c78ef6074b9a7457011719056c9928c800f130a617c93",
"https://deno.land/x/ts_morph@17.0.1/ts_morph.d.ts": "a54b0c51b06d84defedf5fdd59c773d803808ae7c9678f7165f7a1a6dfa7f6a3",
"https://deno.land/x/ts_morph@17.0.1/ts_morph.js": "1bb80284b9e31a4c5c2078cd533fe9b12b4b2d710267055cb655225aa88fb2df",
"https://esm.sh/*preact-render-to-string@5.2.6": "6d6471448406a5b757245eea4354286be62fe899134def7c9a7d34f12206eb06",
"https://esm.sh/dayjs@1.11.0": "c37c9ec8712a8bbec2f7d8b19886d986b4b1026824d6c8bea779e5d7025a9713",
"https://esm.sh/js-cookie@2.2.1": "ef633cfccf41e4a8f5d286d817fb12b0d435d5fe09e7032aed01c128659c6b34",
"https://esm.sh/preact@10.13.1": "ae382301328ab874e2c42bee76e261bb8d094673fe76ca7eb71917636d43d8ad",
"https://esm.sh/preact@10.13.1/hooks": "1813f80c6d648f8137a62569e35972b0716f92539f192d6db66d45b7aafea43a",
"https://esm.sh/preact@10.13.1/jsx-runtime": "0caf2b2eade93af59e89abc31816b6cb2829a9b8a82b958c0ebc1d8bec241e2a",
"https://esm.sh/preact@10.13.2": "5ebf0838bbc3c32fc6e78a4cd9dd672f2c36386d0595815d721a6b0941278488",
"https://esm.sh/preact@10.13.2/hooks": "884334b1560448cf16b4f14841fffdb8707615373a3c76c676a6f9e5c77e43b2",
"https://esm.sh/resize-observer@1.0.4": "04d2b4ede61d5fee44c861dec36894318c3ef6a5296d95fc7321f89e2b9e32b3",
"https://esm.sh/screenfull@5.2.0": "43ca168155f57b936da56e0407a9d6658959a0b082a0a643daadd38138cd6152",
"https://esm.sh/stable/preact@10.13.1/deno/hooks.js": "602f2fb6fdc51480875a095516fa2099f91c87ae6fc8ef544fcf48c854cf21a5",
"https://esm.sh/stable/preact@10.13.1/deno/hooks/src.js": "2dcb1a6d1c47a92d3e60baf6b5dc5ddb0fee7667e7a1c4535578e4647fc939c9",
"https://esm.sh/stable/preact@10.13.1/deno/jsx-runtime.js": "7c8e1b8f272996846cbac0837dcb71f6f8cfc82611b3f7819501d07c37383dc0",
"https://esm.sh/stable/preact@10.13.1/deno/preact.mjs": "9b73545225d0ed274c89f39aee524a2857c81a73060e80c2c4bdc2a6de7bec26",
"https://esm.sh/stable/preact@10.13.2/deno/hooks.js": "c248af581ea3e6f62bf518eb51f4ec04b3b46bc4c1a5d57f986bde63335e37b4",
"https://esm.sh/stable/preact@10.13.2/deno/preact.mjs": "365fab897381f4f403f859c5d12939084560545567108cc90dae901bbe892578",
"https://esm.sh/twind@0.16.19": "bfeee9816ad50c5a4a370c755ae1c7ac56f74b6ae0185ab3785f187a81f43d7e",
"https://esm.sh/twind@0.16.19/sheets": "670388ece940798a9928e2ee6120759599d6a5f316980a9e189b1c20b3fdacc1",
"https://esm.sh/v117/@types/js-cookie@2.2.7/index.d.ts": "b3338366fe1f2c5f978e2ec200f57d35c5bd2c4c90c2191f1e638cfa5621c1f6",
"https://esm.sh/v117/csstype@3.1.2/index.d.ts": "4c68749a564a6facdf675416d75789ee5a557afda8960e0803cf6711fa569288",
"https://esm.sh/v117/dayjs@1.11.0/deno/dayjs.mjs": "5355a125d58fa4498085cb7d919af713266badff879261b410c1d68329d23769",
"https://esm.sh/v117/dayjs@1.11.0/index.d.ts": "f42ab414377fc6607cca4ec18a6b75c7804db1dbef20fd096b567882da4af5cc",
"https://esm.sh/v117/dayjs@1.11.0/locale/index.d.ts": "76e3ebe7213b50c3398ae48315a440bb89fbfc3e09d7735b558b957941b29ba4",
"https://esm.sh/v117/dayjs@1.11.0/locale/types.d.ts": "73a0ee6395819b063df4b148211985f2e1442945c1a057204cf4cf6281760dc3",
"https://esm.sh/v117/js-cookie@2.2.1/deno/js-cookie.mjs": "651a618fb16e5e3fb883bffa2b0d7413a5b50d09c1646ab71c46ddb799796b4c",
"https://esm.sh/v117/preact-render-to-string@5.2.6/X-ZS8q/deno/preact-render-to-string.mjs": "672116885c5e5072207c527a0ec663f5bc52774a0868ec487985109520382a55",
"https://esm.sh/v117/preact-render-to-string@5.2.6/X-ZS8q/src/index.d.ts": "b1d73703252c8570fdf2952475805f5808ba3511fefbd93a3e7bd8406de7dcd0",
"https://esm.sh/v117/preact@10.13.1/hooks/src/index.d.ts": "5c29febb624fc25d71cb0e125848c9b711e233337a08f7eacfade38fd4c14cc3",
"https://esm.sh/v117/preact@10.13.1/hooks/src/index.js": "12359bedd157951586586f777c9cbef49983b93b97d5c1fdd2eb1c748764414b",
"https://esm.sh/v117/preact@10.13.1/jsx-runtime/src/index.d.ts": "e153460ed2b3fe2ad8b93696ecd48fbf73cd628b0b0ea6692b71804a3af69dfd",
"https://esm.sh/v117/preact@10.13.1/src/index.d.ts": "65398710de6aa0a07412da79784e05e6e96763f51c7c91b77344d2d0af06385c",
"https://esm.sh/v117/preact@10.13.1/src/jsx.d.ts": "fde41cfb4944bcc5005e653c989ef8f85deb1cbb5364a1726654993937cd08d0",
"https://esm.sh/v117/preact@10.13.2/hooks/src/index.d.ts": "5c29febb624fc25d71cb0e125848c9b711e233337a08f7eacfade38fd4c14cc3",
"https://esm.sh/v117/preact@10.13.2/src/index.d.ts": "65398710de6aa0a07412da79784e05e6e96763f51c7c91b77344d2d0af06385c",
"https://esm.sh/v117/preact@10.13.2/src/jsx.d.ts": "9ac9b82c199fa7b04748807d750eba1a106c0be52041b8617416f88d6fc0a257",
"https://esm.sh/v117/resize-observer@1.0.4/deno/resize-observer.mjs": "1ea6305f887ea34cb5114783b3195d0a7fc3ed606a2789fcdfe2bea2ed2e6504",
"https://esm.sh/v117/resize-observer@1.0.4/lib/ContentRect.d.ts": "6739f7eb143d076c258140ac92c4f29d454b9ddb7a883586456b6b3f57a1a261",
"https://esm.sh/v117/resize-observer@1.0.4/lib/ResizeObserver.d.ts": "5c67a75ef51b3900171c6ec031810034b7a79b58a51ba7e95af81d1d38a873dd",
"https://esm.sh/v117/resize-observer@1.0.4/lib/ResizeObserverCallback.d.ts": "9269c2476880d751d9c112b79cffbcaef2e1183b46e73ffc1724e98feebee7a2",
"https://esm.sh/v117/resize-observer@1.0.4/lib/ResizeObserverEntry.d.ts": "9e4d8ffeaa854ee78491457009cebff908a3feca8416a7d33645f4670f8c20e8",
"https://esm.sh/v117/screenfull@5.2.0/deno/screenfull.mjs": "f908eb8f7ac66c8b0c4dc10c15976494ef1a3d72d62b49bdc551deb264cf2714",
"https://esm.sh/v117/screenfull@5.2.0/dist/screenfull.d.ts": "74cb24dfec2f11b10e1ac66b0b47c28badc79f261fdf607048dedb462578218d",
"https://esm.sh/v117/style-vendorizer@2.2.3/deno/style-vendorizer.mjs": "fb725497dd9621a84f552f9b6a4f3df82af5989ff18c40e972de1bdf475c9765",
"https://esm.sh/v117/twind@0.16.19/deno/sheets.js": "dcdb26e5d2860d9fff3ad81b81625799e501d465efdc99b206d3b7cd94151913",
"https://esm.sh/v117/twind@0.16.19/deno/twind.mjs": "c9eb3e4fbaef9fcff45b48f5efec6babd32b5e89e207acf40ba19c508598e579",
"https://esm.sh/v117/twind@0.16.19/sheets/sheets.d.ts": "fb4c593effec75b45c617415f5b75d3e89330d5c4c5baa5730b8a4075460d2eb",
"https://esm.sh/v117/twind@0.16.19/twind.d.ts": "2a761e77beadd4e73bf20fc7981f6ac8ab25228a89b63c724df1cbe43114e9f6",
"https://raw.githubusercontent.com/lucacasonato/esbuild_deno_loader/8031f71afa1bbcd3237a94b11f53a2e5c5c0e7bf/deps.ts": "b7248e5b750be62613a9417f407e65ed43726d83b11f9631d6dbb58634bbd7d1",
"https://raw.githubusercontent.com/lucacasonato/esbuild_deno_loader/8031f71afa1bbcd3237a94b11f53a2e5c5c0e7bf/mod.ts": "3e507379372361162f93325a216b86f6098defb5bb60144555b507bca26d061f",
"https://raw.githubusercontent.com/lucacasonato/esbuild_deno_loader/8031f71afa1bbcd3237a94b11f53a2e5c5c0e7bf/src/deno.ts": "71bee6b14e72ca193c0686d8b4f1f47d639a64745b6f5c7576f7a3616f436f57",
"https://raw.githubusercontent.com/lucacasonato/esbuild_deno_loader/8031f71afa1bbcd3237a94b11f53a2e5c5c0e7bf/src/native_loader.ts": "2a0f5a7b68a57c4651ad48161b32532356b434597a6cf282683427482b38f6fa",
"https://raw.githubusercontent.com/lucacasonato/esbuild_deno_loader/8031f71afa1bbcd3237a94b11f53a2e5c5c0e7bf/src/portable_loader.ts": "47adb6d9a00f13a87d0a15f2af79118eb93503234008c31392d71270bc0a42fa",
"https://raw.githubusercontent.com/lucacasonato/esbuild_deno_loader/8031f71afa1bbcd3237a94b11f53a2e5c5c0e7bf/src/shared.ts": "007e8d575cb6ebcac4110f1f72188a8bec3aa29287b4ad26e98403c00bebf036"
}
}

5
dev.ts Executable file
View file

@ -0,0 +1,5 @@
#!/usr/bin/env -S deno run -A --watch=static/,routes/
import dev from "$fresh/dev.ts";
await dev(import.meta.url, "./main.ts");

46
fresh.gen.ts Normal file
View file

@ -0,0 +1,46 @@
// 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 config from "./deno.json" assert { type: "json" };
import * as $0 from "./routes/[conversation_id].tsx";
import * as $1 from "./routes/[conversation_id]/i/index.tsx";
import * as $2 from "./routes/_404.tsx";
import * as $3 from "./routes/_500.tsx";
import * as $4 from "./routes/api/conv/[id].ts";
import * as $5 from "./routes/api/conv/index.ts";
import * as $6 from "./routes/api/db/index.ts";
import * as $7 from "./routes/api/joke.ts";
import * as $8 from "./routes/api/msg/[id].ts";
import * as $9 from "./routes/api/msg/index.ts";
import * as $10 from "./routes/index.tsx";
import * as $11 from "./routes/m/[message_id].tsx";
import * as $$0 from "./islands/Counter.tsx";
import * as $$1 from "./islands/Home.tsx";
import * as $$2 from "./islands/Interactive.tsx";
const manifest = {
routes: {
"./routes/[conversation_id].tsx": $0,
"./routes/[conversation_id]/i/index.tsx": $1,
"./routes/_404.tsx": $2,
"./routes/_500.tsx": $3,
"./routes/api/conv/[id].ts": $4,
"./routes/api/conv/index.ts": $5,
"./routes/api/db/index.ts": $6,
"./routes/api/joke.ts": $7,
"./routes/api/msg/[id].ts": $8,
"./routes/api/msg/index.ts": $9,
"./routes/index.tsx": $10,
"./routes/m/[message_id].tsx": $11,
},
islands: {
"./islands/Counter.tsx": $$0,
"./islands/Home.tsx": $$1,
"./islands/Interactive.tsx": $$2,
},
baseUrl: import.meta.url,
config,
};
export default manifest;

19
import_map.json Normal file
View file

@ -0,0 +1,19 @@
{
"imports": {
"$fresh/": "https://deno.land/x/fresh@1.1.5/",
"preact": "https://esm.sh/preact@10.13.1",
"preact/": "https://esm.sh/preact@10.13.1/",
"preact-render-to-string": "https://esm.sh/*preact-render-to-string@5.2.6",
"@preact/signals": "https://esm.sh/*@preact/signals@1.1.3",
"@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.2.3",
"twind": "https://esm.sh/twind@0.16.19",
"twind/": "https://esm.sh/twind@0.16.19/",
"common/": "./common/",
"db": "./common/db.ts",
"types": "./common/types.ts",
"utils": "./common/utils.ts",
"style": "./common/style.ts",
"optionals": "https://deno.land/x/optionals@v3.0.0/mod.ts",
"components/": "./components/"
}
}

17
islands/Counter.tsx Normal file
View file

@ -0,0 +1,17 @@
import { useState } from "preact/hooks";
import { Button } from "components/Button.tsx";
interface CounterProps {
start: number;
}
export default function Counter(props: CounterProps) {
const [count, setCount] = useState(props.start);
return (
<div class="flex gap-2 w-full">
<p class="flex-grow-1 font-bold text-xl">{count}</p>
<Button onClick={() => setCount(count - 1)}>-1</Button>
<Button onClick={() => setCount(count + 1)}>+1</Button>
</div>
);
}

83
islands/Home.tsx Normal file
View file

@ -0,0 +1,83 @@
import { useState } from "preact/hooks";
import { Database } from "types";
import { Head } from "$fresh/runtime.ts";
import { DEFAULT_STYLE } from "style";
import ConversationLink from "components/ConversationLink.tsx";
import WithStyleSheet from "components/WithStyleSheet.tsx";
import { fetch_db } from "db";
import { URL } from "utils";
export default function Home({ db }: { db: Database }) {
const [data, setData] = useState(db);
const links = Object.keys(data.conversations)
.reverse()
.map(c => <ConversationLink conv={c} db={data} interactive={true} />);
return (
<>
<Head>
<title>Freshter Logs</title>
</Head>
<WithStyleSheet href="/index.css" />
<a href="/">
<h1 className="title" style={DEFAULT_STYLE}>
freshter logs
</h1>
</a>
<MakeConversation
onsubmit={async () => (await fetch_db()).map(db => setData(db))}
/>
{links}
<div className="promo" style={DEFAULT_STYLE}>
by <a href="https://pl.pyrope.net/terezi">mehbark</a>
</div>
</>
);
}
function MakeConversation({ onsubmit }: { onsubmit?: () => void }) {
const [name, setName] = useState("");
const [desc, setDesc] = useState("");
async function handleClick() {
await fetch(`${URL}/api/conv`, {
method: "PUT",
body: JSON.stringify({ name, description: desc }),
});
setName("");
setDesc("");
onsubmit && onsubmit();
}
return (
<>
<WithStyleSheet href="/MakeConversation.css" />
<div className="make-conversation">
<input
value={name}
onInput={(e: any) => setName(e.target.value)}
className="mc-name"
placeholder="name"
/>
<textarea
value={desc}
onInput={(e: any) => setDesc(e.target.value)}
className="mc-desc"
placeholder="description"
/>
<button className="mc-submit" onClick={handleClick}>
create
</button>
</div>
</>
);
}
//TODO: making new conversations
//TODO: ui obv
//TODO: adding presets to convs (i think i'll have global presets be just manual tbh, people can email)
//TODO: conversation browser (ez)
//TODO: maybe preview but ehh name and description sbs
//TODO: oo def integrate their custom colors

89
islands/Interactive.tsx Normal file
View file

@ -0,0 +1,89 @@
import { useEffect, useState } from "preact/hooks";
import { URL, catcher_async, fetch_json } from "utils";
import { Database } from "types";
import Conv from "components/Conv.tsx";
import WithStyleSheet from "components/WithStyleSheet.tsx";
import AddMsg from "components/AddMsg.tsx";
import PresetSelector from "components/PresetSelector.tsx";
import PresetCreator from "components/PresetCreator.tsx";
import { fetch_db } from "../common/db.ts";
const UPDATE_DB_INTERVAL_MS = 3000;
export default function Interactive({
conv,
db,
}: {
conv: string;
db: Database;
}) {
const [database, setDatabase] = useState(db);
const conv_ = database.conversations[conv];
useEffect(() => {
const interval = setInterval(updateDB, UPDATE_DB_INTERVAL_MS);
return () => clearInterval(interval);
}, []);
const [preset, setPreset] = useState("default");
const [creating, setCreating] = useState("preset");
const [fg, setFg] = useState("black");
const [bg, setBg] = useState("");
const [font, setFont] = useState("");
async function updateDB() {
(await fetch_db()).map(db => setDatabase(db));
}
function select_preset(s: string) {
setPreset(s);
setCreating(s);
setFg(conv_.presets[s].fg);
setBg(conv_.presets[s].bg ?? "");
setFont(conv_.presets[s].font ?? "");
}
return (
<>
<WithStyleSheet href="/Interactive.css" />
<Conv conv={conv} db={database}>
<AddMsg
preset={preset}
db={database}
conv={conv_}
onsubmit={async function (msg) {
await fetch(`${URL}/api/conv/${conv}`, {
method: "PUT",
body: JSON.stringify(msg),
});
updateDB();
}}
/>
<PresetSelector
selected={preset}
setPreset={select_preset}
db={database}
conv={conv_}
/>
<PresetCreator
conv={conv}
name={creating}
setName={setCreating}
onsubmit={updateDB}
{...{ fg, setFg, bg, setBg, font, setFont }}
/>
<GoToStaticPage conv={conv} />
</Conv>
</>
);
}
function GoToStaticPage({ conv }: { conv: string }) {
return (
<footer>
<a href={`/${conv}`} className="back-to-static">
Go to static page
</a>
</footer>
);
}

13
main.ts Normal file
View file

@ -0,0 +1,13 @@
/// <reference no-default-lib="true" />
/// <reference lib="dom" />
/// <reference lib="dom.iterable" />
/// <reference lib="dom.asynciterable" />
/// <reference lib="deno.ns" />
import { start } from "$fresh/server.ts";
import manifest from "./fresh.gen.ts";
import twindPlugin from "$fresh/plugins/twind.ts";
import twindConfig from "./twind.config.ts";
await start(manifest, { plugins: [twindPlugin(twindConfig)] });

View file

@ -0,0 +1,32 @@
import { Handlers, PageProps } from "$fresh/server.ts";
import { Database, Option } from "types";
import { get_db_obj } from "db";
import Conv from "components/Conv.tsx";
export const handler: Handlers<Option<Database>> = {
async GET(req, ctx) {
const db = await get_db_obj();
if (
db.isNone() ||
!db.unwrap().conversations[ctx.params.conversation_id]
) {
return ctx.renderNotFound();
}
return ctx.render(db);
},
};
export default function ConversationPreview({
data,
params,
}: PageProps<Option<Database>>) {
if (
data.isSome() &&
params.conversation_id &&
data.unwrap().conversations[params.conversation_id]
) {
return <Conv conv={params.conversation_id} db={data.unwrap()} />;
}
}
//TODO: keyboard shortcut (advertised elsewhere) that activates interactive mode

View file

@ -0,0 +1,33 @@
import { Handlers, PageProps } from "$fresh/server.ts";
import { Database, Option } from "types";
import { get_db_obj } from "db";
import Interactive from "../../../islands/Interactive.tsx";
export const handler: Handlers<Option<Database>> = {
async GET(req, ctx) {
const db = await get_db_obj();
if (
db.isNone() ||
(db.isSome() &&
!db.unwrap().conversations[ctx.params.conversation_id])
) {
return ctx.renderNotFound();
}
return ctx.render(db);
},
};
export default function ConversationPreview({
data,
params,
}: PageProps<Option<Database>>) {
if (
data.isSome() &&
params.conversation_id &&
data.unwrap().conversations[params.conversation_id]
) {
return <Interactive conv={params.conversation_id} db={data.unwrap()} />;
}
}
//TODO: keyboard shortcut (advertised elsewhere) that activates interactive mode

15
routes/_404.tsx Normal file
View file

@ -0,0 +1,15 @@
import { UnknownPageProps } from "$fresh/server.ts";
export default function NotFoundPage({ url }: UnknownPageProps) {
return (
<div>
<p>404 not found: {url.pathname}</p>
<a
href="/"
className="font-medium text-blue-600 dark:text-blue-500 hover:underline"
>
go back home
</a>
</div>
);
}

5
routes/_500.tsx Normal file
View file

@ -0,0 +1,5 @@
import { ErrorPageProps } from "$fresh/server.ts";
export default function Error500Page({ error }: ErrorPageProps) {
return <p>500 internal error: {(error as Error).message}</p>;
}

33
routes/api/conv/[id].ts Normal file
View file

@ -0,0 +1,33 @@
import { PageProps } from "$fresh/server.ts";
import { catcher_async, json_response } from "utils";
import { message_under, add_preset } from "db";
export async function handler(
req: Request,
props: PageProps
): Promise<Response> {
if (req.method == "PUT") {
return await put(req, props);
} else {
return new Response(JSON.stringify({ err: "expected a PUT" }));
}
}
async function put(req: Request, props: PageProps): Promise<Response> {
const json = await catcher_async(() => req.json());
const id = props.params.id;
if (!id || json.isNone()) {
return json_response({ err: "you SUCK" }, { status: 400 });
} else if (json.unwrap().register_preset) {
return json_response(
await add_preset(json.unwrap().register_preset, json.unwrap(), id),
{
status: 300,
}
);
} else {
return json_response(await message_under(json.unwrap(), id), {
status: 300,
});
}
}

34
routes/api/conv/index.ts Normal file
View file

@ -0,0 +1,34 @@
import { HandlerContext } from "$fresh/server.ts";
import { catcher_async, json_response } from "utils";
import { new_conversation } from "db";
export async function handler(
req: Request,
_ctx: HandlerContext
): Promise<Response> {
if (req.method == "PUT") {
return await put(req);
} else {
return new Response(JSON.stringify({ err: "expected a PUT" }));
}
}
async function put(req: Request): Promise<Response> {
const json = await catcher_async(() => req.json());
if (json.isNone()) {
return json_response({ err: "expected JSON :(" }, { status: 400 });
}
const json_ = json.unwrap();
if (!json_.name || !json_.description) {
return json_response(
{ err: "i need a `name` and a `description`" },
{ status: 400 }
);
}
const new_id = await new_conversation(json_.name, json_.description);
return json_response(new_id.unwrapOr("fail"));
}
//TODO: validate that they give a valid message object
//TODO: put under some id
//TODO: e.g. {under: string, message: Message}

14
routes/api/db/index.ts Normal file
View file

@ -0,0 +1,14 @@
import { json_response } from "utils";
import { get_db_obj } from "db";
export async function handler(req: Request): Promise<Response> {
if (req.method == "GET") {
return await get();
} else {
return new Response(JSON.stringify({ err: "expected a GET" }));
}
}
async function get(): Promise<Response> {
return json_response(await get_db_obj());
}

21
routes/api/joke.ts Normal file
View file

@ -0,0 +1,21 @@
import { HandlerContext } from "$fresh/server.ts";
// Jokes courtesy of https://punsandoneliners.com/randomness/programmer-jokes/
const JOKES = [
"Why do Java developers often wear glasses? They can't C#.",
"A SQL query walks into a bar, goes up to two tables and says “can I join you?”",
"Wasn't hard to crack Forrest Gump's password. 1forrest1.",
"I love pressing the F5 key. It's refreshing.",
"Called IT support and a chap from Australia came to fix my network connection. I asked “Do you come from a LAN down under?”",
"There are 10 types of people in the world. Those who understand binary and those who don't.",
"Why are assembly programmers often wet? They work below C level.",
"My favourite computer based band is the Black IPs.",
"What programme do you use to predict the music tastes of former US presidential candidates? An Al Gore Rhythm.",
"An SEO expert walked into a bar, pub, inn, tavern, hostelry, public house.",
];
export const handler = (_req: Request, _ctx: HandlerContext): Response => {
const randomIndex = Math.floor(Math.random() * JOKES.length);
const body = JOKES[randomIndex];
return new Response(body);
};

23
routes/api/msg/[id].ts Normal file
View file

@ -0,0 +1,23 @@
import { PageProps } from "$fresh/server.ts";
import { json_response } from "utils";
import { get_message } from "db";
export async function handler(
req: Request,
props: PageProps
): Promise<Response> {
if (req.method == "GET") {
return await get(props);
} else {
return new Response(JSON.stringify({ err: "expected a PUT" }));
}
}
async function get(props: PageProps): Promise<Response> {
const got = await get_message(props.params.id);
if (!got) {
return json_response({ err: "not found" }, { status: 404 });
} else {
return json_response(got, { status: 300 });
}
}

28
routes/api/msg/index.ts Normal file
View file

@ -0,0 +1,28 @@
import { HandlerContext } from "$fresh/server.ts";
import { catcher_async, json_response } from "utils";
import { orphan_message } from "db";
export async function handler(
req: Request,
_ctx: HandlerContext
): Promise<Response> {
if (req.method == "PUT") {
return await put(req);
} else {
return new Response(JSON.stringify({ err: "expected a PUT" }));
}
}
async function put(req: Request): Promise<Response> {
const json = await catcher_async(() => req.json());
if (json.isNone()) {
return json_response({ err: "expected JSON :(" }, { status: 400 });
}
const json_ = json.unwrap();
const new_id = await orphan_message(json_);
return new Response(new_id.unwrapOr("fail"));
}
//TODO: validate that they give a valid message object
//TODO: put under some id
//TODO: e.g. {under: string, message: Message}

18
routes/index.tsx Normal file
View file

@ -0,0 +1,18 @@
import { Handlers, PageProps } from "$fresh/server.ts";
import { get_db_obj } from "db";
import { Database } from "types";
import Home from "../islands/Home.tsx";
export const handler: Handlers<Database> = {
async GET(req, ctx) {
const db = await get_db_obj();
if (db.isNone()) {
return ctx.renderNotFound();
}
return ctx.render(db.unwrap());
},
};
export default function Index({ data }: PageProps<Database>) {
return <Home db={data} />;
}

27
routes/m/[message_id].tsx Normal file
View file

@ -0,0 +1,27 @@
import { Handlers, PageProps } from "$fresh/server.ts";
import { Database, Option } from "types";
import Msg from "components/Msg.tsx";
import { get_db_obj } from "db";
export const handler: Handlers<Option<Database>> = {
async GET(_, ctx) {
const db = await get_db_obj();
if (db.isNone() || !db.unwrap().messages[ctx.params.message_id]) {
return ctx.renderNotFound();
}
return ctx.render(db);
},
};
export default function MessagePreview({
data,
params,
}: PageProps<Option<Database>>) {
if (
data.isSome() &&
params.message_id &&
data.unwrap().messages[params.message_id]
) {
return <Msg message={params.message_id} db={data.unwrap()} />;
}
}

46
static/Conv.css Normal file
View file

@ -0,0 +1,46 @@
/* largely from https://homestuck2.com */
.chat-container {
border-style: dashed;
border-width: 1px;
border-color: gray;
width: calc(min(590px, 100vw));
margin: auto;
}
div.chat {
line-height: 1.35;
font-size: 14px;
margin: 15px 25px;
font-family: "courier-std", courier, monospace;
}
body {
color: #000000;
font-family: "courier-std", courier, monospace;
font-weight: bold;
overflow-wrap: break-word;
width: 100%;
}
html {
height: 100%;
width: 100%;
}
.name {
text-align: center;
}
.description {
font-weight: normal;
width: fit-content;
margin: auto;
}
.convo-body {
min-height: 100vh;
width: 100%;
}
/* stolen from homestuck.com (I NEED IT TO BE JUST RIGHT */
/* nvm idc bc the uhc is diff nyway */

View file

@ -0,0 +1,15 @@
.conversation-link {
outline: 1px dashed grey;
width: calc(min(590px, 99vw));
text-align: center;
margin: auto;
margin-bottom: 10px;
}
.name {
font-size: 1.1em;
}
.description {
font-weight: normal !important;
}

127
static/Interactive.css Normal file
View file

@ -0,0 +1,127 @@
/* TODO: would be neat to have it be based on the page */
/* maybe a link preset */
a.back-to-static {
color: #007bff;
text-decoration: underline;
transition: all 0.2s ease-in-out;
}
a.back-to-static:hover {
color: #0056b3;
text-decoration-color: #0056b3;
}
.back-to-static {
display: block;
width: fit-content;
margin: auto;
}
html,
body {
width: 100%;
}
footer {
/* position: absolute;
bottom: 0; */
width: 100%;
padding: 20px;
text-align: center;
}
.add-msg {
display: block;
margin: auto;
margin-top: 10px;
border: 1px dashed grey;
width: calc(min(590px, 100vw));
padding: 15px 25px;
}
.add-msg:focus {
inset: none;
outline: none;
border: 1px dashed black;
/* background-tr */
}
.preset-selector {
margin: auto;
margin-top: 10px;
width: calc(min(590px, 100vw));
max-height: 20vh;
overflow: scroll;
user-select: none;
}
.preset-option {
border: 1px dashed grey;
margin-bottom: 3px;
cursor: pointer;
text-align: center;
}
.preset-option .selected {
text-decoration: underline !important;
/* border: 1px dashed black; */
}
.preset-creator {
width: calc(min(590px, 100vw));
margin: auto;
border: 1px dashed grey;
margin-top: 10px;
white-space: pre;
font-variant-ligatures: none;
display: grid;
grid-template-areas:
"name name name"
"fg bg font"
"submit submit submit";
}
.pc-input {
width: 95%;
font-variant-ligatures: none;
}
.pc-input::before {
content: "Name: ";
}
.pc-name > .pc-input {
font-weight: bold;
}
.pc-name,
.pc-fg,
.pc-bg,
.pc-font {
display: flex;
}
.pc-name {
grid-area: name;
}
.pc-fg {
grid-area: fg;
}
.pc-bg {
grid-area: bg;
}
.pc-font {
grid-area: font;
}
.pc-submit {
grid-area: submit;
}
.pc-input {
background: none;
}

View file

@ -0,0 +1,24 @@
.make-conversation {
outline: 1px dashed grey;
width: calc(min(590px, 99vw));
text-align: center;
margin: auto;
margin-bottom: 10px;
}
.mc-name,
.mc-desc {
width: 100%;
font-family: "Courier New", Courier, monospace;
border-bottom: 1px dashed grey;
}
.mc-name:focus,
.mc-desc:focus,
.mc-submit:focus {
background-color: lightgray;
}
.mc-submit {
width: 100%;
}

BIN
static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

13
static/index.css Normal file
View file

@ -0,0 +1,13 @@
.title {
font-size: larger;
text-align: center;
}
.promo {
text-align: center;
}
.promo > a {
color: #008282;
text-decoration: underline;
}

6
static/logo.svg Normal file
View file

@ -0,0 +1,6 @@
<svg width="40" height="40" fill="none" xmlns="http://www.w3.org/2000/svg">
<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"/>
<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"/>
<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"/>
<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"/>
</svg>

After

Width:  |  Height:  |  Size: 1 KiB

5
twind.config.ts Normal file
View file

@ -0,0 +1,5 @@
import { Options } from "$fresh/plugins/twind.ts";
export default {
selfURL: import.meta.url,
} as Options;