gubes mirror. how does this work
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

more whois nonsense

leah ce49c1a4 42e13697

+124 -45
+1
README.md
··· 18 18 19 19 - **Ergo Testnet**: `wss://testnet.ergo.chat/webirc` 20 20 - **Libera.Chat**: `wss://web.libera.chat/webirc/websocket/` 21 + - Some others I imagine 21 22 22 23 a plea to network administrators: please disable CORS on your webirc endpoints. i really really do not want to have to set up a proxy. 23 24
+8 -6
core/whois.ts
··· 50 50 conn.send(`WHOIS :${nick}`); 51 51 const result = await q; 52 52 53 + let thisguy: Partial<UserMetadata> = { 54 + operator: false, 55 + registered: false, 56 + modes: [], 57 + }; 58 + 53 59 if (conn.supports.metadata()) { 60 + thisguy.metadata = {}; 54 61 const meta_query = conn.collect_batch("metadata"); 55 62 conn.send(`METADATA ${nick} GET ${supported_keys.join(" ")}`); 56 63 result.push(...(await meta_query)); 57 64 } 58 65 59 - let thisguy: Partial<UserMetadata> = { 60 - metadata: {}, 61 - operator: false, 62 - registered: false, 63 - modes: [], 64 - }; 65 66 66 67 for (const msg of result) { 67 68 if (!msg.params) continue; ··· 73 74 thisguy.realname = msg.params.at(-1); 74 75 break; 75 76 case Numeric.RPL_KEYVALUE: 77 + if (!thisguy.metadata) continue; 76 78 const key = msg.params[2]; 77 79 const value = msg.params.at(-1); 78 80 if (!value) break;
+1 -1
neo/src/bits/dialog.tsx
··· 117 117 ], { defaultTransition: dialog_spring_out }); 118 118 119 119 120 - const DialogHeader: FunctionalComponent<{ colour?: string }> = ({ children, colour = 'grey' }) => { 120 + export const DialogHeader: FunctionalComponent<{ colour?: string }> = ({ children, colour = 'grey' }) => { 121 121 const border_colour = colour == "grey" 122 122 ? `var(--colour-grey-100)` 123 123 : `rgb(from var(--colour-${colour}-900) r g b / .1)`;
+1 -4
neo/src/buffer/page.tsx
··· 91 91 </ul>, { anchor: "right" }); 92 92 93 93 const whois_nick = signal<string>() 94 - const whois_dialog = create_dialog(WhoisDialog, { conn: buffer.conn, nick: whois_nick }, { 95 - header: ({ nick }: { nick: Signal<string> }) => <><h1>{nick.value}</h1></>, 96 - header_colour: computed(() => pick_colour(whois_nick.value ?? "")) 97 - }); 94 + const whois_dialog = create_dialog(WhoisDialog, { conn: buffer.conn, nick: whois_nick }); 98 95 99 96 return <BufferContext.Provider value={buffer}> 100 97 <WhoisDialogContext.Provider value={{ diag: whois_dialog, nick: whois_nick }}>
+78 -18
neo/src/buffer/whois.tsx
··· 1 - import { Signal, signal } from "@preact/signals"; 1 + import { Signal, signal, useSignal } from "@preact/signals"; 2 2 import { SecondaryButton } from "@src/bits/buttons"; 3 - import { DialogControls, DialogInnards } from "@src/bits/dialog"; 3 + import { DialogControls, DialogHeader, DialogInnards } from "@src/bits/dialog"; 4 + import { pick_colour } from "@src/chat/colours"; 5 + import { css, styled } from "goober"; 6 + import { FunctionalComponent } from "preact"; 7 + import { useEffect, useMemo } from "preact/hooks"; 4 8 import { Connection } from "tubes_core"; 9 + import { UserMetadata } from "tubes_core/whois"; 5 10 6 11 export interface WhoisState { 7 12 nick: Signal<string | undefined>, ··· 14 19 state: WhoisState 15 20 ) { 16 21 state.nick.value = who_exactly; 17 - const whois = await conn.whois(who_exactly); 18 - 19 - // whois_state.value = { 20 - // nick: who_exactly, 21 - // resp: whois, 22 - // } 23 22 24 23 state.diag.open(); 25 24 } 26 25 27 - export const WhoisDialog: DialogInnards<{ conn: Connection, nick: Signal<string | undefined> }> = ({ nick, close }) => { 28 - if (!nick.value) { 26 + export const WhoisDialog: DialogInnards<{ conn: Connection, nick: Signal<string | undefined> }> = ({ nick, close, conn }) => { 27 + const whois = useSignal<UserMetadata>(); 28 + 29 + useEffect(() => { 30 + whois.value = undefined; 31 + if (!nick.value) return; 32 + conn.whois(nick.value).then(x => whois.value = x); 33 + }, [nick]) 34 + 35 + if (!whois.value) { 29 36 return <></> 30 37 } 38 + const colour = useMemo(() => pick_colour(nick.value!), [nick]) 31 39 32 - return <div style="width: 36rem; padding: 1rem; padding-top: 0rem;"> 33 - {/* {whois_state.value.nick} aaa */} 34 - <p class="body-small">helloo I'm the nostalgia critic</p> 35 - <div style="display: flex"> 36 - <SecondaryButton style="margin-left: auto;" onClick={() => close()} title="Close"> 37 - that will be all 38 - </SecondaryButton> 40 + return <> 41 + <DialogHeader colour={pick_colour(nick.value!)}> 42 + <HeaderInnards> 43 + <hgroup> 44 + <h1 style="font-size: 1.5rem; font-weight: 400;">{nick.value}</h1> 45 + <p>{whois.value.realname}</p> 46 + </hgroup> 47 + <Avatar url={whois.value.metadata?.["avatar"]} nick={whois.value.nick} colour={colour} /> 48 + </HeaderInnards> 49 + </DialogHeader> 50 + <div style="width: 36rem; margin-top: 2rem; padding: 1rem; padding-top: 0rem;"> 51 + {/* {whois_state.value.nick} aaa */} 52 + <p class="body-small">{JSON.stringify(whois.value)}</p> 53 + <div style="display: flex"> 54 + <SecondaryButton style="margin-left: auto;" onClick={() => close()} title="Close"> 55 + i've seen enough 56 + </SecondaryButton> 57 + </div> 39 58 </div> 40 - </div> 59 + </> 60 + } 61 + 62 + const HeaderInnards = styled('div')` 63 + display: flex; 64 + justify-content: space-between; 65 + align-items: end; 66 + width: 100%; 67 + font-variation-settings: 'GRAD' 150; 68 + 69 + p { 70 + margin: .15rem 0; 71 + color: rgb(from currentColor r g b / .75); 72 + } 73 + ` 74 + 75 + const Avatar = ({ url, nick, colour }: { url?: string, nick: string, colour: string }) => { 76 + return <figure class={css` 77 + width: 6rem; 78 + height: 6rem; 79 + background-color: var(--colour-${colour}-500); 80 + border: 6px solid var(--colour-${colour}-400); 81 + outline: 1px solid rgb(from var(--colour-${colour}-700) r g b / .5); 82 + margin: 1rem .5rem; 83 + margin-bottom: -2.5rem; 84 + border-radius: 22px; 85 + box-shadow: 0 4px 4px 1px rgb(0 0 0 / .05); 86 + 87 + display: flex; 88 + align-items: center; 89 + justify-content: center; 90 + font-size: 3rem; 91 + color: var(--colour-${colour}-50); 92 + font-style: italic; 93 + line-height: 1; 94 + font-weight: 300; 95 + font-variation-settings: 'GRAD' 150; 96 + `}> 97 + {url 98 + ? <img src={url} /> 99 + : <span>{nick.substring(0, 2)}</span>} 100 + </figure> 41 101 }
+16 -3
neo/src/chat/commands.ts
··· 21 21 input = input.substring(1); 22 22 } 23 23 24 - const cutoff = input.search(" "); 25 - const cmd_name = input.substring(0, cutoff == -1 ? 0 : cutoff); 26 - input = cutoff == -1 ? "" : input.substring(cutoff + 1); 24 + let cmd_name: string; 25 + 26 + if (!input.includes(" ")) { 27 + cmd_name = input; 28 + input = ""; 29 + } else { 30 + const cutoff = input.search(" "); 31 + cmd_name = input.substring(0, cutoff == -1 ? 0 : cutoff); 32 + input = cutoff == -1 ? "" : input.substring(cutoff + 1); 33 + } 27 34 28 35 const cmd = commands[cmd_name]; 29 36 ··· 50 57 } 51 58 52 59 await buffer.set_topic(input); 60 + } 61 + }, 62 + "peg": { 63 + description: "Open Steely Dan's undisputed magnum opus, 1977's <i>Peg</i> in a new tab", 64 + activate: async () => { 65 + window.open("https://www.youtube.com/watch?v=LI7NDDQLvbo", "_blank")?.focus() 53 66 } 54 67 } 55 68 };
+19 -13
neo/src/css/sidebar.css
··· 258 258 .selected & { 259 259 background-color: var(--colour-accent-600); 260 260 color: white; 261 + 262 + li.sidebar-item:hover & { 263 + background-color: var(--colour-accent-600); 264 + } 265 + 261 266 } 262 267 } 263 268 ··· 292 297 } 293 298 } 294 299 295 - .connection-error blockquote, .error-quote { 300 + .connection-error blockquote, 301 + .error-quote { 296 302 position: relative; 297 303 z-index: 1; 298 304 margin: .5rem 0; ··· 415 421 padding: .4rem .5rem; 416 422 417 423 @media screen and not (prefers-reduced-motion) { 418 - &:hover { 419 - animation: addbutton-rainbow 2s linear infinite; 424 + &:hover { 425 + animation: addbutton-rainbow 2s linear infinite; 426 + } 420 427 } 421 - } 422 428 423 429 &:hover { 424 430 background: linear-gradient(to right, 425 - var(--colour-red-200), 426 - var(--colour-orange-200), 427 - var(--colour-yellow-200), 428 - var(--colour-ectoplasm-200), 429 - var(--colour-weezer-200), 430 - var(--colour-aubergine-200), 431 - var(--colour-bubblegum-200), 432 - var(--colour-red-200)) 0 0/200% 100%; 431 + var(--colour-red-200), 432 + var(--colour-orange-200), 433 + var(--colour-yellow-200), 434 + var(--colour-ectoplasm-200), 435 + var(--colour-weezer-200), 436 + var(--colour-aubergine-200), 437 + var(--colour-bubblegum-200), 438 + var(--colour-red-200)) 0 0/200% 100%; 433 439 434 440 font-variation-settings: 'GRAD' 100; 435 441 color: black; 436 442 } 437 - } 443 + }