gubes mirror. how does this work
1
fork

Configure Feed

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

yeah!

leah eddedbd6 b4468e64

+37 -23
+1 -1
core/capabilities.ts
··· 9 9 "sasl", 10 10 "setname", 11 11 "draft/chathistory", 12 - // "draft/event-playback", 12 + "draft/event-playback", 13 13 "draft/account-registration", 14 14 "soju.im/bouncer-networks", 15 15 "draft/metadata-2",
+1 -1
neo/package.json
··· 14 14 "async-mutex": "^0.5.0", 15 15 "dayjs": "^1.11.13", 16 16 "motion": "^11.18.2", 17 - "preact": "^10.23.1", 17 + "preact": "^10.26.9", 18 18 "wouter-preact": "^3.3.1", 19 19 "goober": "^2.1.16", 20 20 "idb": "^8.0.0"
+2 -2
neo/src/bits/dialog.tsx
··· 86 86 } 87 87 } 88 88 89 - const dialog_spring = { type: "spring", mass: 1.5, stiffness: 500, damping: 25 }; 89 + const dialog_spring = { type: "spring", mass: 5, stiffness: 2000, damping: 150 }; 90 90 const dialog_spring_out = { type: "spring", visualDuration: .2, bounce: 0.1 }; 91 91 const scrim_spring = { ease: "easeInOut", duration: .15 } 92 92 93 93 const trans_in = (dialog: HTMLDialogElement) => animate([ 94 - [dialog.children[0], { opacity: [0, 1], scale: [0.75, 1] }], 94 + [dialog.children[0], { opacity: [0, 1], scale: [0.65, 1] }], 95 95 [".dialog-scrim", { opacity: [0, 1] }, { at: 0, ...scrim_spring }], 96 96 ], { defaultTransition: dialog_spring }); 97 97
+5 -2
neo/src/buffer/members.tsx
··· 1 + import { css } from "goober"; 1 2 import { FunctionalComponent } from "preact"; 2 3 import { IrcChannel } from "tubes_core/channel"; 3 4 4 - export const MembersPanel: FunctionalComponent<{ channel: IrcChannel }> = ({channel}) => { 5 + export const MembersPanel: FunctionalComponent<{ channel: IrcChannel }> = ({ channel }) => { 5 6 const members = channel.$members.value; 6 - return <aside class="members-panel"> 7 + return <aside class={css` 8 + display: flex; 9 + `}> 7 10 <ul> 8 11 {members.map(x => <li>{x}</li>)} 9 12 </ul>
+18 -3
neo/src/buffer/page.tsx
··· 15 15 import dump from "@src/debug/dump"; 16 16 17 17 import MembersIcon from "~icons/ph/users"; 18 - import { IconButton } from "@src/bits/buttons"; 18 + import { IconButton, PrimaryButton } from "@src/bits/buttons"; 19 19 import { ChatBuffer } from "tubes_core/buffer"; 20 20 21 21 async function load_msgs(buffer: ChatBuffer, limit = 100): Promise<IrcMessage[]> { ··· 103 103 104 104 marker.focused.value = elem.scrollHeight <= elem.scrollTop + elem.clientHeight + padding; 105 105 }} 106 + load_more={async () => { 107 + const new_stuff = await load_msgs(buffer); 108 + msgs.value = [...msgs.value, ...new_stuff]; 109 + }} 106 110 /> 107 111 : <SkeletonLoader ref2={list_elem} /> 108 112 } ··· 132 136 </BufferContext.Provider>; 133 137 } 134 138 139 + export const LoadMore = ({ onClick }: { onClick: (e: MouseEvent) => any }) => { 140 + return <PrimaryButton class={css` 141 + grid-column: 2; 142 + width: max-content; 143 + `} onClick={onClick}> 144 + Load More 145 + </PrimaryButton> 146 + } 147 + 135 148 export const MessageList 136 149 : FunctionalComponent<{ 137 150 list_elem: RefObject<HTMLUListElement>, 138 151 buffer: ChatBuffer, 139 152 is_loading: Signal<boolean>, 140 153 msgs: Signal<IrcMessage[]>, 154 + load_more: () => any, 141 155 onScroll: HTMLProps<HTMLUListElement>['onScroll'], 142 156 }> 143 - = ({ list_elem, is_loading, onScroll, buffer, msgs }) => { 157 + = ({ list_elem, is_loading, onScroll, buffer, msgs, load_more }) => { 144 158 const squished = squish_messages(buffer, msgs.value); 145 159 return <ul class="messages" ref={list_elem} onScroll={onScroll}> 146 160 {/* header. todo: should not be in a ul element */} 147 161 <StartOfHistory buffer={buffer} /> 148 - 162 + <LoadMore onClick={e => load_more()} /> 149 163 {/* history getting bits */} 150 164 {is_loading.value && "loadin"} 151 165 {/* <LoadTrigger onIntersect={async () => {}} parent={list_elem} /> */} ··· 192 206 import DebugIcon from "~icons/ph/hammer"; 193 207 import { create_menu, Menu, MenuItem } from "@src/bits/menu.tsx"; 194 208 import { MembersPanel } from "./members"; 209 + import { css } from "goober"; 195 210 196 211 const StartOfHistory: FunctionalComponent<{ buffer: ChatBuffer }> = ({ buffer }) => { 197 212 const chathistory = buffer.conn.capabilities.has("draft/chathistory");
-4
neo/src/css/messages.css
··· 565 565 color: white; 566 566 } 567 567 } 568 - 569 - .members-panel { 570 - display: flex; 571 - }
+5 -5
neo/src/pages/network-info.tsx
··· 2 2 import { useComputed, useSignal } from "@preact/signals"; 3 3 import { ActionGroup, ActionItem, ActionLink } from "@src/bits/actions"; 4 4 import { PrimaryButton } from "@src/bits/buttons"; 5 + import RegisteredSticker from "@src/bits/registered.svg?raw"; 6 + import Spinner from "@src/bits/spinner"; 5 7 import { pick_colour } from "@src/chat/colours"; 6 8 import conns, { connection_base } from "@src/chat/conns"; 7 9 import { css } from "goober"; 8 10 import { FunctionalComponent } from "preact"; 9 11 import { Connection } from "tubes_core"; 10 12 import { ConnectionState } from "tubes_core/connection"; 13 + import { useLocation } from "wouter-preact"; 11 14 12 15 export default function NetworkInfoPage({ conn }: { conn: Connection }) { 13 16 const status = useComputed(() => { ··· 143 146 } 144 147 `; 145 148 149 + import AnimatedIconSwitcher from "@src/bits/icon-switcher"; 146 150 import EditProfileIcon from "~icons/ph/pen"; 147 151 import LoginIcon from "~icons/ph/sign-in"; 148 - import RegisterIcon from "~icons/ph/user-plus"; 149 - import AnimatedIconSwitcher from "@src/bits/icon-switcher"; 150 152 import LogoutIcon from "~icons/ph/stairs"; 151 - import Spinner from "@src/bits/spinner"; 152 - import RegisteredSticker from "@src/bits/registered.svg?raw"; 153 - import { useLocation } from "wouter-preact"; 153 + import RegisterIcon from "~icons/ph/user-plus"; 154 154 155 155 const AccountSection: FunctionalComponent<{ conn: Connection }> = ({ conn }) => { 156 156 const authed = conn.sasl.$authed.value;
+1 -1
neo/src/pages/profile-settings.tsx
··· 103 103 </FormField> 104 104 <FormField label="Real Name" 105 105 flavour_text={<> 106 - your name, pronouns, etc. doesn't actually have to be your real name 106 + your name or whatever else you want to put here. 107 107 {!conn.supports.setname() 108 108 && details.realname.value != conn.realname 109 109 && <><br /><span class={css`
+4 -4
package-lock.json
··· 45 45 "goober": "^2.1.16", 46 46 "idb": "^8.0.0", 47 47 "motion": "^11.18.2", 48 - "preact": "^10.23.1", 48 + "preact": "^10.26.9", 49 49 "wouter-preact": "^3.3.1" 50 50 }, 51 51 "devDependencies": { ··· 2737 2737 } 2738 2738 }, 2739 2739 "node_modules/preact": { 2740 - "version": "10.26.8", 2741 - "resolved": "https://registry.npmjs.org/preact/-/preact-10.26.8.tgz", 2742 - "integrity": "sha512-1nMfdFjucm5hKvq0IClqZwK4FJkGXhRrQstOQ3P4vp8HxKrJEMFcY6RdBRVTdfQS/UlnX6gfbPuTvaqx/bDoeQ==", 2740 + "version": "10.26.9", 2741 + "resolved": "https://registry.npmjs.org/preact/-/preact-10.26.9.tgz", 2742 + "integrity": "sha512-SSjF9vcnF27mJK1XyFMNJzFd5u3pQiATFqoaDy03XuN00u4ziveVVEGt5RKJrDR8MHE/wJo9Nnad56RLzS2RMA==", 2743 2743 "license": "MIT", 2744 2744 "funding": { 2745 2745 "type": "opencollective",