Experiment to rebuild Diffuse using web applets.
at main 118 lines 3.2 kB view raw
1import { computed, effect, type Signal, signal } from "spellcaster"; 2import { type Props, repeat, tags, text } from "spellcaster/hyperscript.js"; 3 4import type { Bucket } from "./types"; 5import { bucketId, loadBuckets, saveBuckets } from "./common"; 6 7//////////////////////////////////////////// 8// UI 9//////////////////////////////////////////// 10export const [buckets, setBuckets] = signal<Record<string, Bucket>>(await loadBuckets()); 11export const [form, setForm] = signal<{ 12 access_key?: string; 13 bucket_name?: string; 14 host?: string; 15 path?: string; 16 region?: string; 17 secret_key?: string; 18}>({}); 19 20export const bucketsMap = computed(() => { 21 return new Map(Object.entries(buckets())); 22}); 23 24effect(() => { 25 saveBuckets(buckets()); 26}); 27 28//////////////////////////////////////////// 29// UI ~ BUCKETS 30//////////////////////////////////////////// 31const Bucket = (bucket: Signal<Bucket>) => { 32 const onclick = () => { 33 const b = bucket(); 34 const id = bucketId(b); 35 36 const col = { ...buckets() }; 37 delete col[id]; 38 39 setBuckets(col); 40 }; 41 42 return tags.li({ onclick, style: "cursor: pointer" }, text(bucket().host)); 43}; 44 45const BucketList = computed(() => { 46 if (bucketsMap().size === 0) { 47 return tags.p({ id: "buckets" }, [tags.small({}, text("Nothing added so far."))]); 48 } 49 50 return tags.ul({ id: "buckets" }, repeat(bucketsMap, Bucket)); 51}); 52 53effect(() => { 54 document.querySelector("#buckets")?.replaceWith(BucketList()); 55}); 56 57//////////////////////////////////////////// 58// UI ~ FORM 59//////////////////////////////////////////// 60function addBucket(event: Event) { 61 event.preventDefault(); 62 63 const f = form(); 64 65 const bucket: Bucket = { 66 accessKey: f.access_key || "", 67 bucketName: f.bucket_name || "", 68 host: f.host || "s3.amazonaws.com", 69 path: f.path || "/", 70 region: f.region || "us-east-1", 71 secretKey: f.secret_key || "", 72 }; 73 74 setBuckets({ 75 ...buckets(), 76 [bucketId(bucket)]: bucket, 77 }); 78} 79 80function Form() { 81 return tags.form({ onsubmit: addBucket }, [ 82 tags.fieldset({ className: "grid" }, [ 83 Input("access_key", "Access key", "r31w7m9c", { required: true }), 84 Input("secret_key", "Secret key", "v02g2l29", { required: true }), 85 ]), 86 tags.fieldset({ className: "grid" }, [ 87 Input("bucket_name", "Bucket name", "bucket", { required: true }), 88 Input("region", "Region", "us-east-1", { required: true }), 89 ]), 90 tags.fieldset({ className: "grid" }, [ 91 Input("host", "Host", "s3.amazonaws.com", { required: true }), 92 Input("path", "Path", "/"), 93 ]), 94 tags.fieldset({ className: "grid" }, [tags.input({ type: "submit", value: "Connect" }, [])]), 95 ]); 96} 97 98function Input(name: string, label: string, placeholder: string, opts: Props = {}) { 99 return tags.label({}, [ 100 tags.span({}, [ 101 tags.span({}, text(label)), 102 tags.small({}, text("required" in opts ? "" : " (optional)")), 103 ]), 104 tags.input({ 105 ...opts, 106 name, 107 placeholder, 108 oninput: (event: InputEvent) => formInput(name, (event.target as HTMLInputElement).value), 109 }), 110 ]); 111} 112 113function formInput(name: string, value: string) { 114 setForm({ ...form(), [name]: value }); 115} 116 117// 🚀 118document.querySelector("#form")?.replaceWith(Form());