diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index e2149e5d..00000000 --- a/CLAUDE.md +++ /dev/null @@ -1,26 +0,0 @@ -## Project Overview - -Flotilla is a Discord-like Nostr client that operates on the concept of "relays as groups/spaces." Built with SvelteKit 2.5 and Svelte 5, it provides messaging, threads, calendar events, and social features across Nostr relays. - -## Important Patterns - -### Finding Code -- Prefer navigating from one file to the next following imports when possible -- If search is necessary, use `ack`, not `grep` or `rg`. - -### Nostr Event Handling -- Prefer seconds to milliseconds when handling nostr events. - -### Styling Conventions -- When styling html, prefer flex/gap classes over margin or space-y classes. - -### Room/space memberships - -Memberships are surfaced as "bookmarks" to the user. - -```typescript -import {membershipsByPubkey, getMembershipUrls} from '@app/state' - -const spaces = getMembershipUrls($membershipsByPubkey.get(pubkey)) -const rooms = getMembershipRooms($membershipsByPubkey.get(pubkey)) -``` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..fa54362e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,96 @@ +# Contributing guidelines + +## Project Overview + +Flotilla is a svelte/typescript/capacitor project. It's intended to be an alternative to Discord for Nostr users. A high-quality UX is a priority, with an emphasis on well-tested, intuitive designs, and robust implementations. + +## Getting Started + +Run `pnpm run dev` to get a dev server, and `pnpm run check:watch` to watch for typescript errors. When you're ready to commit, a pre-commit hook will run to lint and typecheck your work. To run the project on Android or iOS, use Android Studio or Xcode. + +The `master` branch is automatically deployed to production, so always work on feature branches based on the `dev` branch. This project frequently uses unreleased versions of [welshman](https://welshman.coracle.social), using `pnpm` link to hotlink a local copy of the code. To set that up, clone welshman to the parent directory of your `coracle` client, then add `link:../welshman/packages/packagename` to the `pnpm.overrides` section of your `package.json`. Below is a nodejs script that will do that automatically for you: + +```javascript +#!/usr/bin/env node + +import fs from 'fs' +import path from 'path' + +const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8')) + +packageJson.pnpm.overrides = Object.keys(packageJson.dependencies) + .filter(pkg => pkg.startsWith('@welshman/')) + .reduce((acc, pkg) => { + const packageName = pkg.split('/')[1] + acc[pkg] = `link:../welshman/packages/${packageName}` + return acc + }, {}) + +fs.writeFileSync('./package.json', JSON.stringify(packageJson, null, 2) + '\n') + +console.log('Added welshman package overrides.') +``` + +Be sure to avoid committing overrides to either `package.json` or `pnpm-lock.yaml`. These overrides can generally be added, installed, and removed, and will persist until another `pnpm install` command gets run. + +## File Structure + +The main parts of the application are as follows: + +- `static` - static assets like fonts, images, etc. +- `src/assets` - svgs for use as icons. +- `src/lib` - general purpose components and utilities. +- `src/app/core/state` - environment variables, constants, custom stores, and some utilities derived from them. +- `src/app/core/requests` - utilities related to loading data from the nostr network. +- `src/app/core/commands` - utilities related to publishing nostr events and uploading media to blossom servers. +- `src/app/utils` - other application logic, including stuff related to modals, routing, etc. +- `src/app/editor` - configuration for `@welshman/editor` for use in various app views. +- `src/app/components` - reusable components that depend on other `app` stuff. +- `src/routes` - file-based routing interpreted by sveltekit. + +Application organization is based on an acyclic dependency graph: + +- `routes` can depend on anything +- `app/components` can depend on anything in `app` or `lib` +- `app/utils` and `app/core` can only depend on `lib` +- `lib` (and everything else) can depend only on external libraries + +The main stylistic/organizational rule when working in this project is that imports should be sorted based on the dependency graph. Third-party libraries should come first, then `lib`, then `app`. + +## System Architecture + +Flotilla's architecture generally mirrors the file structure. State is stored using Svelte `store`s provided either by `@welshman/app` or by `app/core/state`, allowing for idiomatic svelte 4 usage (svelte 5 runes are [ghey](https://habla.news/u/hodlbod@coracle.social/1739830562159) and not allowed outside of UI components). + +State is then synchronized to local storage or indexeddb using storage helpers provided by welshman in `routes/+layout.svelte`. Other top level synchronization logic generally belongs there. + +`app/core/state` contains all environment variables, constants, custom stores, and utilities derived from them. Most stores are `derived` from our event `repository` using `deriveEventsMapped`, which efficiently queries the repository and maps events to custom data structures. Some of these data structures are provided by `welshman`, and some are defined in `app/core/state`. In either case, they can always be mapped back to an event, which is important for updating replaceables without dropping unknown data. + +Here are a few important domain objects: + +- Spaces are relays used as community groups. Their `url`s are core to a lot of data and components, and are frequently passed around from place to place. +- Chats are direct message conversations. There is currently some ambiguity in routing, since relays that don't support NIP 29 also have a "chat" tab, which uses vanilla NIP-C7. +- NIP 29 groups are variously called "rooms" and "channels". Conventionally, a "room" is a group id, while a "channel" as an object representing the group's metadata. +- "Alerts" are records of requests the user has made to be notified, following [this NIP](https://github.com/nostr-protocol/nips/pull/1796) + +`app/core/requests` contains utilities related to loading data from the nostr network. This might include feed manager utilities, loaders, or listeners. + +`app/core/commands` contains utilities related to publishing nostr events and uploading media to blossom servers. This also includes utilities related to sending lighting payments, authenticating with relays, or probing relay policy. Event creation should generally be split into `make` functions which build the event, and `publish` functions which publish the event using `publishThunk`. + +Any of these utilities can be included either in `app/components` or `routes`. Crucial to keep in mind is that nearly all global state runs through welshman's `repository` in a unidirectional way. To update state, run `publishThunk`, which immediately publishes the event to the local repository. State can be read from the repository using `deriveEventsMapped` or other utilities provided by welshman like `deriveProfile`. + +Thunks are designed to reduce UI latency, handling signatures and delayed sending the background. In most cases, thunk status should be displayed to the user so that they can cancel sending or address errors. + +Toast, modals, and sidebar dialogs are controlled in `app/util/modal` and `app/util/toast`. In both cases, component objects can be passed along with parameters, but care has to be taken that the calling component either doesn't unmount before the modal (as when one modal replaces another), or that `$state.snapshot` is appropriately called on any state runes. These components frequently run into weird svelte compiler bugs too, in which case you may have to do some silly things to cope. + +## Issues and Pull Requests + +All work by contributors should be done against an issue. If there is no issue for the work you're doing, please open one or ask the project owner to open one. All PRs should be opened against the `dev` branch (unless for hotfixes). + +## Communication + +Discussion about development is done [on Flotilla](https://app.flotilla.social/spaces/internal.coracle.social). The group is currently closed, so please let me know if you'd like access. + +## Project License + +This project is licensed under the MIT license. By contributing, you agree to waive all intellectual property rights to your contributions to this project. + diff --git a/README.md b/README.md index 6371aa3e..eea6c7e6 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ If you're deploying a custom version of flotilla, be sure to remove the `plausib ## Development -Run `pnpm run dev` to get a dev server, and `pnpm run check:watch` to watch for typescript errors. When you're ready to commit, a pre-commit hook will run to lint and typecheck your work. +See [./CONTRIBUTING.md](CONTRIBUTING.md). ## Deployment diff --git a/src/app/components/AlertAdd.svelte b/src/app/components/AlertAdd.svelte index dc8fcb92..07e6b59c 100644 --- a/src/app/components/AlertAdd.svelte +++ b/src/app/components/AlertAdd.svelte @@ -27,12 +27,12 @@ userMembership, NOTIFIER_PUBKEY, NOTIFIER_RELAY, - } from "@app/state" - import {loadAlertStatuses, requestRelayClaim} from "@app/requests" - import {publishAlert, attemptAuth} from "@app/commands" - import type {AlertParams} from "@app/commands" - import {platform, platformName, canSendPushNotifications, getPushInfo} from "@app/push" - import {pushToast} from "@app/toast" + } from "@app/core/state" + import {loadAlertStatuses, requestRelayClaim} from "@app/core/requests" + import {publishAlert, attemptAuth} from "@app/core/commands" + import type {AlertParams} from "@app/core/commands" + import {platform, platformName, canSendPushNotifications, getPushInfo} from "@app/util/push" + import {pushToast} from "@app/util/toast" type Props = { url?: string diff --git a/src/app/components/AlertDelete.svelte b/src/app/components/AlertDelete.svelte index ba0878cb..f741b702 100644 --- a/src/app/components/AlertDelete.svelte +++ b/src/app/components/AlertDelete.svelte @@ -1,9 +1,9 @@ diff --git a/src/app/components/Chat.svelte b/src/app/components/Chat.svelte index 9da21ab0..977fc321 100644 --- a/src/app/components/Chat.svelte +++ b/src/app/components/Chat.svelte @@ -53,10 +53,10 @@ deriveChat, splitChatId, PLATFORM_NAME, - } from "@app/state" - import {pushModal} from "@app/modal" - import {prependParent} from "@app/commands" - import {pushToast} from "@app/toast" + } from "@app/core/state" + import {pushModal} from "@app/util/modal" + import {prependParent} from "@app/core/commands" + import {pushToast} from "@app/util/toast" type Props = { id: string diff --git a/src/app/components/ChatEnable.svelte b/src/app/components/ChatEnable.svelte index 2a730f1a..cff8e4b5 100644 --- a/src/app/components/ChatEnable.svelte +++ b/src/app/components/ChatEnable.svelte @@ -8,8 +8,8 @@ import Spinner from "@lib/components/Spinner.svelte" import ModalHeader from "@lib/components/ModalHeader.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte" - import {canDecrypt, PLATFORM_NAME, ensureUnwrapped} from "@app/state" - import {clearModals} from "@app/modal" + import {canDecrypt, PLATFORM_NAME, ensureUnwrapped} from "@app/core/state" + import {clearModals} from "@app/util/modal" const {next} = $props() diff --git a/src/app/components/ChatItem.svelte b/src/app/components/ChatItem.svelte index 400ccc13..613faf7a 100644 --- a/src/app/components/ChatItem.svelte +++ b/src/app/components/ChatItem.svelte @@ -9,8 +9,8 @@ import ProfileName from "@app/components/ProfileName.svelte" import ProfileCircle from "@app/components/ProfileCircle.svelte" import ProfileCircles from "@app/components/ProfileCircles.svelte" - import {makeChatPath} from "@app/routes" - import {notifications} from "@app/notifications" + import {makeChatPath} from "@app/util/routes" + import {notifications} from "@app/util/notifications" interface Props { id: string diff --git a/src/app/components/ChatMenu.svelte b/src/app/components/ChatMenu.svelte index df945c3a..de84693d 100644 --- a/src/app/components/ChatMenu.svelte +++ b/src/app/components/ChatMenu.svelte @@ -2,8 +2,8 @@ import Icon from "@lib/components/Icon.svelte" import Button from "@lib/components/Button.svelte" import ChatStart from "@app/components/ChatStart.svelte" - import {setChecked} from "@app/notifications" - import {pushModal} from "@app/modal" + import {setChecked} from "@app/util/notifications" + import {pushModal} from "@app/util/modal" const startChat = () => pushModal(ChatStart, {}, {replaceState: true}) diff --git a/src/app/components/ChatMessage.svelte b/src/app/components/ChatMessage.svelte index 65687e23..3b8bf568 100644 --- a/src/app/components/ChatMessage.svelte +++ b/src/app/components/ChatMessage.svelte @@ -15,9 +15,9 @@ import ProfileDetail from "@app/components/ProfileDetail.svelte" import ChatMessageMenu from "@app/components/ChatMessageMenu.svelte" import ChatMessageMenuMobile from "@app/components/ChatMessageMenuMobile.svelte" - import {colors} from "@app/state" - import {makeDelete, makeReaction} from "@app/commands" - import {pushModal} from "@app/modal" + import {colors} from "@app/core/state" + import {makeDelete, makeReaction} from "@app/core/commands" + import {pushModal} from "@app/util/modal" interface Props { event: TrustedEvent diff --git a/src/app/components/ChatMessageEmojiButton.svelte b/src/app/components/ChatMessageEmojiButton.svelte index 3abe04c0..47f8e2cc 100644 --- a/src/app/components/ChatMessageEmojiButton.svelte +++ b/src/app/components/ChatMessageEmojiButton.svelte @@ -4,7 +4,7 @@ import {sendWrapped} from "@welshman/app" import Icon from "@lib/components/Icon.svelte" import EmojiButton from "@lib/components/EmojiButton.svelte" - import {makeReaction} from "@app/commands" + import {makeReaction} from "@app/core/commands" interface Props { event: TrustedEvent diff --git a/src/app/components/ChatMessageMenu.svelte b/src/app/components/ChatMessageMenu.svelte index 2059c53f..ebc57159 100644 --- a/src/app/components/ChatMessageMenu.svelte +++ b/src/app/components/ChatMessageMenu.svelte @@ -3,7 +3,7 @@ import Button from "@lib/components/Button.svelte" import ChatMessageEmojiButton from "@app/components/ChatMessageEmojiButton.svelte" import EventInfo from "@app/components/EventInfo.svelte" - import {pushModal} from "@app/modal" + import {pushModal} from "@app/util/modal" const {event, pubkeys, popover, replyTo} = $props() diff --git a/src/app/components/ChatMessageMenuMobile.svelte b/src/app/components/ChatMessageMenuMobile.svelte index 1b977e29..cad8169d 100644 --- a/src/app/components/ChatMessageMenuMobile.svelte +++ b/src/app/components/ChatMessageMenuMobile.svelte @@ -6,9 +6,9 @@ import Button from "@lib/components/Button.svelte" import EmojiPicker from "@lib/components/EmojiPicker.svelte" import EventInfo from "@app/components/EventInfo.svelte" - import {makeReaction} from "@app/commands" - import {pushModal} from "@app/modal" - import {clip} from "@app/toast" + import {makeReaction} from "@app/core/commands" + import {pushModal} from "@app/util/modal" + import {clip} from "@app/util/toast" type Props = { pubkeys: string[] diff --git a/src/app/components/ChatStart.svelte b/src/app/components/ChatStart.svelte index dfa6df17..60ea0611 100644 --- a/src/app/components/ChatStart.svelte +++ b/src/app/components/ChatStart.svelte @@ -13,7 +13,7 @@ import ModalHeader from "@lib/components/ModalHeader.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte" import ProfileMultiSelect from "@app/components/ProfileMultiSelect.svelte" - import {makeChatPath} from "@app/routes" + import {makeChatPath} from "@app/util/routes" const back = () => history.back() diff --git a/src/app/components/CommentActions.svelte b/src/app/components/CommentActions.svelte index 90335608..6cffc5d5 100644 --- a/src/app/components/CommentActions.svelte +++ b/src/app/components/CommentActions.svelte @@ -4,8 +4,8 @@ import ThunkStatusOrDeleted from "@app/components/ThunkStatusOrDeleted.svelte" import EventActivity from "@app/components/EventActivity.svelte" import EventActions from "@app/components/EventActions.svelte" - import {publishDelete, publishReaction, canEnforceNip70} from "@app/commands" - import {makeThreadPath} from "@app/routes" + import {publishDelete, publishReaction, canEnforceNip70} from "@app/core/commands" + import {makeThreadPath} from "@app/util/routes" interface Props { url: any diff --git a/src/app/components/Content.svelte b/src/app/components/Content.svelte index ec947b03..53bc125e 100644 --- a/src/app/components/Content.svelte +++ b/src/app/components/Content.svelte @@ -31,7 +31,7 @@ import ContentQuote from "@app/components/ContentQuote.svelte" import ContentTopic from "@app/components/ContentTopic.svelte" import ContentMention from "@app/components/ContentMention.svelte" - import {entityLink, userSettingValues} from "@app/state" + import {entityLink, userSettingValues} from "@app/core/state" interface Props { event: any diff --git a/src/app/components/ContentEmoji.svelte b/src/app/components/ContentEmoji.svelte index 62f6fc5c..1c29deb4 100644 --- a/src/app/components/ContentEmoji.svelte +++ b/src/app/components/ContentEmoji.svelte @@ -1,6 +1,6 @@
diff --git a/src/app/components/InfoHandle.svelte b/src/app/components/InfoHandle.svelte index 3136125f..fd29544c 100644 --- a/src/app/components/InfoHandle.svelte +++ b/src/app/components/InfoHandle.svelte @@ -2,7 +2,7 @@ import Button from "@lib/components/Button.svelte" import Link from "@lib/components/Link.svelte" import ModalHeader from "@lib/components/ModalHeader.svelte" - import {PLATFORM_NAME} from "@app/state" + import {PLATFORM_NAME} from "@app/core/state"
diff --git a/src/app/components/InfoKeys.svelte b/src/app/components/InfoKeys.svelte index 611554f7..0390a151 100644 --- a/src/app/components/InfoKeys.svelte +++ b/src/app/components/InfoKeys.svelte @@ -6,8 +6,8 @@ import ModalHeader from "@lib/components/ModalHeader.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte" import ProfileEject from "@app/components/ProfileEject.svelte" - import {PLATFORM_NAME} from "@app/state" - import {pushModal} from "@app/modal" + import {PLATFORM_NAME} from "@app/core/state" + import {pushModal} from "@app/util/modal" const back = () => history.back() diff --git a/src/app/components/InfoRelay.svelte b/src/app/components/InfoRelay.svelte index fd6d9c20..05c5baeb 100644 --- a/src/app/components/InfoRelay.svelte +++ b/src/app/components/InfoRelay.svelte @@ -2,7 +2,7 @@ import Button from "@lib/components/Button.svelte" import Link from "@lib/components/Link.svelte" import ModalHeader from "@lib/components/ModalHeader.svelte" - import {PLATFORM_NAME} from "@app/state" + import {PLATFORM_NAME} from "@app/core/state"
diff --git a/src/app/components/Landing.svelte b/src/app/components/Landing.svelte index 74d08882..e0aa2230 100644 --- a/src/app/components/Landing.svelte +++ b/src/app/components/Landing.svelte @@ -6,8 +6,8 @@ import CardButton from "@lib/components/CardButton.svelte" import LogIn from "@app/components/LogIn.svelte" import SignUp from "@app/components/SignUp.svelte" - import {PLATFORM_TERMS, PLATFORM_PRIVACY, PLATFORM_NAME} from "@app/state" - import {pushModal} from "@app/modal" + import {PLATFORM_TERMS, PLATFORM_PRIVACY, PLATFORM_NAME} from "@app/core/state" + import {pushModal} from "@app/util/modal" const logIn = () => pushModal(LogIn) diff --git a/src/app/components/LogIn.svelte b/src/app/components/LogIn.svelte index 91e80eae..c5467b65 100644 --- a/src/app/components/LogIn.svelte +++ b/src/app/components/LogIn.svelte @@ -10,11 +10,11 @@ import InfoNostr from "@app/components/InfoNostr.svelte" import LogInBunker from "@app/components/LogInBunker.svelte" import LogInPassword from "@app/components/LogInPassword.svelte" - import {pushModal, clearModals} from "@app/modal" - import {PLATFORM_NAME, BURROW_URL} from "@app/state" - import {pushToast} from "@app/toast" - import {loadUserData} from "@app/requests" - import {setChecked} from "@app/notifications" + import {pushModal, clearModals} from "@app/util/modal" + import {PLATFORM_NAME, BURROW_URL} from "@app/core/state" + import {pushToast} from "@app/util/toast" + import {loadUserData} from "@app/core/requests" + import {setChecked} from "@app/util/notifications" let signers: any[] = $state([]) let loading: string | undefined = $state() diff --git a/src/app/components/LogInBunker.svelte b/src/app/components/LogInBunker.svelte index 296d52eb..263f3d5a 100644 --- a/src/app/components/LogInBunker.svelte +++ b/src/app/components/LogInBunker.svelte @@ -11,12 +11,12 @@ import ModalFooter from "@lib/components/ModalFooter.svelte" import BunkerConnect from "@app/components/BunkerConnect.svelte" import BunkerUrl from "@app/components/BunkerUrl.svelte" - import {Nip46Controller} from "@app/nip46" - import {loadUserData} from "@app/requests" - import {clearModals} from "@app/modal" - import {setChecked} from "@app/notifications" - import {pushToast} from "@app/toast" - import {SIGNER_RELAYS, NIP46_PERMS} from "@app/state" + import {Nip46Controller} from "@app/util/nip46" + import {loadUserData} from "@app/core/requests" + import {clearModals} from "@app/util/modal" + import {setChecked} from "@app/util/notifications" + import {pushToast} from "@app/util/toast" + import {SIGNER_RELAYS, NIP46_PERMS} from "@app/core/state" const back = () => { if (mode === "connect") { diff --git a/src/app/components/LogInPassword.svelte b/src/app/components/LogInPassword.svelte index cef605ed..14a364de 100644 --- a/src/app/components/LogInPassword.svelte +++ b/src/app/components/LogInPassword.svelte @@ -12,11 +12,17 @@ import ModalHeader from "@lib/components/ModalHeader.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte" import PasswordResetRequest from "@app/components/PasswordResetRequest.svelte" - import {loadUserData} from "@app/requests" - import {clearModals, pushModal} from "@app/modal" - import {setChecked} from "@app/notifications" - import {pushToast} from "@app/toast" - import {NIP46_PERMS, BURROW_URL, PLATFORM_URL, PLATFORM_NAME, PLATFORM_LOGO} from "@app/state" + import {loadUserData} from "@app/core/requests" + import {clearModals, pushModal} from "@app/util/modal" + import {setChecked} from "@app/util/notifications" + import {pushToast} from "@app/util/toast" + import { + NIP46_PERMS, + BURROW_URL, + PLATFORM_URL, + PLATFORM_NAME, + PLATFORM_LOGO, + } from "@app/core/state" interface Props { email?: string diff --git a/src/app/components/LogOut.svelte b/src/app/components/LogOut.svelte index 06e69fb6..5367bc15 100644 --- a/src/app/components/LogOut.svelte +++ b/src/app/components/LogOut.svelte @@ -5,7 +5,7 @@ import Spinner from "@lib/components/Spinner.svelte" import ModalHeader from "@lib/components/ModalHeader.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte" - import {logout} from "@app/commands" + import {logout} from "@app/core/commands" const back = () => history.back() diff --git a/src/app/components/MenuSettings.svelte b/src/app/components/MenuSettings.svelte index 6db07ee5..4b8da049 100644 --- a/src/app/components/MenuSettings.svelte +++ b/src/app/components/MenuSettings.svelte @@ -4,8 +4,8 @@ import Button from "@lib/components/Button.svelte" import CardButton from "@lib/components/CardButton.svelte" import LogOut from "@app/components/LogOut.svelte" - import {PLATFORM_NAME} from "@app/state" - import {pushModal} from "@app/modal" + import {PLATFORM_NAME} from "@app/core/state" + import {pushModal} from "@app/util/modal" const logout = () => pushModal(LogOut) diff --git a/src/app/components/MenuSpace.svelte b/src/app/components/MenuSpace.svelte index 0a8f5994..1782569a 100644 --- a/src/app/components/MenuSpace.svelte +++ b/src/app/components/MenuSpace.svelte @@ -26,10 +26,10 @@ deriveOtherRooms, hasNip29, alerts, - } from "@app/state" - import {notifications} from "@app/notifications" - import {pushModal} from "@app/modal" - import {makeSpacePath} from "@app/routes" + } from "@app/core/state" + import {notifications} from "@app/util/notifications" + import {pushModal} from "@app/util/modal" + import {makeSpacePath} from "@app/util/routes" const {url} = $props() diff --git a/src/app/components/MenuSpaceButton.svelte b/src/app/components/MenuSpaceButton.svelte index 5ad73872..7a5649b0 100644 --- a/src/app/components/MenuSpaceButton.svelte +++ b/src/app/components/MenuSpaceButton.svelte @@ -2,9 +2,9 @@ import Icon from "@lib/components/Icon.svelte" import Button from "@lib/components/Button.svelte" import MenuSpace from "@app/components/MenuSpace.svelte" - import {notifications} from "@app/notifications" - import {makeSpacePath} from "@app/routes" - import {pushDrawer} from "@app/modal" + import {notifications} from "@app/util/notifications" + import {makeSpacePath} from "@app/util/routes" + import {pushDrawer} from "@app/util/modal" const {url} = $props() diff --git a/src/app/components/MenuSpaceRoomItem.svelte b/src/app/components/MenuSpaceRoomItem.svelte index e19cc265..52587213 100644 --- a/src/app/components/MenuSpaceRoomItem.svelte +++ b/src/app/components/MenuSpaceRoomItem.svelte @@ -2,9 +2,9 @@ import Icon from "@lib/components/Icon.svelte" import SecondaryNavItem from "@lib/components/SecondaryNavItem.svelte" import ChannelName from "@app/components/ChannelName.svelte" - import {makeRoomPath} from "@app/routes" - import {deriveChannel} from "@app/state" - import {notifications} from "@app/notifications" + import {makeRoomPath} from "@app/util/routes" + import {deriveChannel} from "@app/core/state" + import {notifications} from "@app/util/notifications" interface Props { url: any diff --git a/src/app/components/MenuSpaces.svelte b/src/app/components/MenuSpaces.svelte index 406e07b2..21a05260 100644 --- a/src/app/components/MenuSpaces.svelte +++ b/src/app/components/MenuSpaces.svelte @@ -5,8 +5,8 @@ import CardButton from "@lib/components/CardButton.svelte" import MenuSpacesItem from "@app/components/MenuSpacesItem.svelte" import SpaceAdd from "@app/components/SpaceAdd.svelte" - import {userRoomsByUrl, PLATFORM_RELAYS} from "@app/state" - import {pushModal} from "@app/modal" + import {userRoomsByUrl, PLATFORM_RELAYS} from "@app/core/state" + import {pushModal} from "@app/util/modal" const addSpace = () => pushModal(SpaceAdd) diff --git a/src/app/components/MenuSpacesItem.svelte b/src/app/components/MenuSpacesItem.svelte index 08bf2e88..abb8afa0 100644 --- a/src/app/components/MenuSpacesItem.svelte +++ b/src/app/components/MenuSpacesItem.svelte @@ -4,8 +4,8 @@ import SpaceAvatar from "@app/components/SpaceAvatar.svelte" import RelayName from "@app/components/RelayName.svelte" import RelayDescription from "@app/components/RelayDescription.svelte" - import {makeSpacePath} from "@app/routes" - import {notifications} from "@app/notifications" + import {makeSpacePath} from "@app/util/routes" + import {notifications} from "@app/util/notifications" const {url} = $props() diff --git a/src/app/components/ModalContainer.svelte b/src/app/components/ModalContainer.svelte index 99d2f36b..45cb61ec 100644 --- a/src/app/components/ModalContainer.svelte +++ b/src/app/components/ModalContainer.svelte @@ -2,7 +2,7 @@ import {page} from "$app/stores" import Drawer from "@lib/components/Drawer.svelte" import Dialog from "@lib/components/Dialog.svelte" - import {modals, clearModals} from "@app/modal" + import {modals, clearModals} from "@app/util/modal" const onKeyDown = (e: any) => { if (e.code === "Escape" && e.target === document.body) { diff --git a/src/app/components/NoteCard.svelte b/src/app/components/NoteCard.svelte index 849c8f43..70a49f28 100644 --- a/src/app/components/NoteCard.svelte +++ b/src/app/components/NoteCard.svelte @@ -12,7 +12,7 @@ import Button from "@lib/components/Button.svelte" import Profile from "@app/components/Profile.svelte" import ProfileName from "@app/components/ProfileName.svelte" - import {entityLink} from "@app/state" + import {entityLink} from "@app/core/state" const { event, diff --git a/src/app/components/NoteItem.svelte b/src/app/components/NoteItem.svelte index 539a59a8..113942ae 100644 --- a/src/app/components/NoteItem.svelte +++ b/src/app/components/NoteItem.svelte @@ -6,7 +6,7 @@ import NoteContent from "@app/components/NoteContent.svelte" import NoteCard from "@app/components/NoteCard.svelte" import ReactionSummary from "@app/components/ReactionSummary.svelte" - import {publishDelete, publishReaction, canEnforceNip70} from "@app/commands" + import {publishDelete, publishReaction, canEnforceNip70} from "@app/core/commands" const {url, event} = $props() diff --git a/src/app/components/PasswordReset.svelte b/src/app/components/PasswordReset.svelte index a74c0050..9c94efda 100644 --- a/src/app/components/PasswordReset.svelte +++ b/src/app/components/PasswordReset.svelte @@ -7,9 +7,9 @@ import FieldInline from "@lib/components/FieldInline.svelte" import ModalHeader from "@lib/components/ModalHeader.svelte" import LogInPassword from "@app/components/LogInPassword.svelte" - import {pushModal} from "@app/modal" - import {pushToast} from "@app/toast" - import {BURROW_URL} from "@app/state" + import {pushModal} from "@app/util/modal" + import {pushToast} from "@app/util/toast" + import {BURROW_URL} from "@app/core/state" const {email, reset_token} = $props() diff --git a/src/app/components/PasswordResetRequest.svelte b/src/app/components/PasswordResetRequest.svelte index e4bc3af4..bf829ecd 100644 --- a/src/app/components/PasswordResetRequest.svelte +++ b/src/app/components/PasswordResetRequest.svelte @@ -8,9 +8,9 @@ import ModalHeader from "@lib/components/ModalHeader.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte" import LogInPassword from "@app/components/LogInPassword.svelte" - import {pushModal} from "@app/modal" - import {pushToast} from "@app/toast" - import {BURROW_URL} from "@app/state" + import {pushModal} from "@app/util/modal" + import {pushToast} from "@app/util/toast" + import {BURROW_URL} from "@app/core/state" interface Props { email: string diff --git a/src/app/components/PeopleItem.svelte b/src/app/components/PeopleItem.svelte index de680436..17783908 100644 --- a/src/app/components/PeopleItem.svelte +++ b/src/app/components/PeopleItem.svelte @@ -5,7 +5,7 @@ import ProfileInfo from "@app/components/ProfileInfo.svelte" import ProfileBadges from "@app/components/ProfileBadges.svelte" import ProfileDetail from "@app/components/ProfileDetail.svelte" - import {pushModal} from "@app/modal" + import {pushModal} from "@app/util/modal" type Props = { pubkey: string diff --git a/src/app/components/PrimaryNav.svelte b/src/app/components/PrimaryNav.svelte index 7564712c..63779308 100644 --- a/src/app/components/PrimaryNav.svelte +++ b/src/app/components/PrimaryNav.svelte @@ -13,10 +13,10 @@ import MenuOtherSpaces from "@app/components/MenuOtherSpaces.svelte" import MenuSettings from "@app/components/MenuSettings.svelte" import PrimaryNavItemSpace from "@app/components/PrimaryNavItemSpace.svelte" - import {userRoomsByUrl, canDecrypt, PLATFORM_RELAYS, PLATFORM_LOGO} from "@app/state" - import {pushModal} from "@app/modal" - import {makeSpacePath} from "@app/routes" - import {notifications} from "@app/notifications" + import {userRoomsByUrl, canDecrypt, PLATFORM_RELAYS, PLATFORM_LOGO} from "@app/core/state" + import {pushModal} from "@app/util/modal" + import {makeSpacePath} from "@app/util/routes" + import {notifications} from "@app/util/notifications" type Props = { children?: Snippet diff --git a/src/app/components/PrimaryNavItemSpace.svelte b/src/app/components/PrimaryNavItemSpace.svelte index 5d7ed5ca..8faa6703 100644 --- a/src/app/components/PrimaryNavItemSpace.svelte +++ b/src/app/components/PrimaryNavItemSpace.svelte @@ -2,8 +2,8 @@ import {displayRelayUrl} from "@welshman/util" import PrimaryNavItem from "@lib/components/PrimaryNavItem.svelte" import SpaceAvatar from "@app/components/SpaceAvatar.svelte" - import {makeSpacePath} from "@app/routes" - import {notifications} from "@app/notifications" + import {makeSpacePath} from "@app/util/routes" + import {notifications} from "@app/util/notifications" const {url} = $props() diff --git a/src/app/components/Profile.svelte b/src/app/components/Profile.svelte index 63d6e6eb..57522828 100644 --- a/src/app/components/Profile.svelte +++ b/src/app/components/Profile.svelte @@ -13,8 +13,8 @@ import Avatar from "@lib/components/Avatar.svelte" import WotScore from "@app/components/WotScore.svelte" import ProfileDetail from "@app/components/ProfileDetail.svelte" - import {pushModal} from "@app/modal" - import {clip} from "@app/toast" + import {pushModal} from "@app/util/modal" + import {clip} from "@app/util/toast" type Props = { pubkey: string diff --git a/src/app/components/ProfileBadges.svelte b/src/app/components/ProfileBadges.svelte index 44a455dd..5520b534 100644 --- a/src/app/components/ProfileBadges.svelte +++ b/src/app/components/ProfileBadges.svelte @@ -9,9 +9,9 @@ import {repository, loadRelaySelections} from "@welshman/app" import Button from "@lib/components/Button.svelte" import ProfileSpaces from "@app/components/ProfileSpaces.svelte" - import {membershipsByPubkey} from "@app/state" - import {goToEvent} from "@app/routes" - import {pushModal} from "@app/modal" + import {membershipsByPubkey} from "@app/core/state" + import {goToEvent} from "@app/util/routes" + import {pushModal} from "@app/util/modal" type Props = { pubkey: string diff --git a/src/app/components/ProfileDelete.svelte b/src/app/components/ProfileDelete.svelte index a61c028b..989e472c 100644 --- a/src/app/components/ProfileDelete.svelte +++ b/src/app/components/ProfileDelete.svelte @@ -16,9 +16,9 @@ import Spinner from "@lib/components/Spinner.svelte" import ModalHeader from "@lib/components/ModalHeader.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte" - import {pushToast} from "@app/toast" - import {logout} from "@app/commands" - import {INDEXER_RELAYS, PLATFORM_NAME, userMembership, getMembershipUrls} from "@app/state" + import {pushToast} from "@app/util/toast" + import {logout} from "@app/core/commands" + import {INDEXER_RELAYS, PLATFORM_NAME, userMembership, getMembershipUrls} from "@app/core/state" let progress: number | undefined = $state(undefined) let confirmText = $state("") diff --git a/src/app/components/ProfileDetail.svelte b/src/app/components/ProfileDetail.svelte index 204e71a7..7167103f 100644 --- a/src/app/components/ProfileDetail.svelte +++ b/src/app/components/ProfileDetail.svelte @@ -9,9 +9,9 @@ import ProfileInfo from "@app/components/ProfileInfo.svelte" import ProfileBadges from "@app/components/ProfileBadges.svelte" import ChatEnable from "@app/components/ChatEnable.svelte" - import {canDecrypt, pubkeyLink} from "@app/state" - import {pushModal} from "@app/modal" - import {makeChatPath} from "@app/routes" + import {canDecrypt, pubkeyLink} from "@app/core/state" + import {pushModal} from "@app/util/modal" + import {makeChatPath} from "@app/util/routes" export type Props = { pubkey: string diff --git a/src/app/components/ProfileEdit.svelte b/src/app/components/ProfileEdit.svelte index b3a2af3e..ba27c900 100644 --- a/src/app/components/ProfileEdit.svelte +++ b/src/app/components/ProfileEdit.svelte @@ -14,9 +14,9 @@ import {pubkey, profilesByPubkey, publishThunk} from "@welshman/app" import Button from "@lib/components/Button.svelte" import ProfileEditForm from "@app/components/ProfileEditForm.svelte" - import {clearModals} from "@app/modal" - import {pushToast} from "@app/toast" - import {PROTECTED, getMembershipUrls, userMembership} from "@app/state" + import {clearModals} from "@app/util/modal" + import {pushToast} from "@app/util/toast" + import {PROTECTED, getMembershipUrls, userMembership} from "@app/core/state" const profile = $profilesByPubkey.get($pubkey!) || makeProfile() const shouldBroadcast = !getTag(PROTECTED, profile.event?.tags || []) diff --git a/src/app/components/ProfileEditForm.svelte b/src/app/components/ProfileEditForm.svelte index 8524bf5b..dab37b82 100644 --- a/src/app/components/ProfileEditForm.svelte +++ b/src/app/components/ProfileEditForm.svelte @@ -8,7 +8,7 @@ import Button from "@lib/components/Button.svelte" import InputProfilePicture from "@lib/components/InputProfilePicture.svelte" import InfoHandle from "@app/components/InfoHandle.svelte" - import {pushModal} from "@app/modal" + import {pushModal} from "@app/util/modal" type Values = { profile: Profile diff --git a/src/app/components/ProfileEject.svelte b/src/app/components/ProfileEject.svelte index e646bdd1..d1524a62 100644 --- a/src/app/components/ProfileEject.svelte +++ b/src/app/components/ProfileEject.svelte @@ -9,9 +9,9 @@ import Field from "@lib/components/Field.svelte" import ModalHeader from "@lib/components/ModalHeader.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte" - import {PLATFORM_NAME, BURROW_URL} from "@app/state" - import {pushToast} from "@app/toast" - import {logout} from "@app/commands" + import {PLATFORM_NAME, BURROW_URL} from "@app/core/state" + import {pushToast} from "@app/util/toast" + import {logout} from "@app/core/commands" const email = $session?.email diff --git a/src/app/components/ProfileLink.svelte b/src/app/components/ProfileLink.svelte index b9cbd66d..c9c77a9c 100644 --- a/src/app/components/ProfileLink.svelte +++ b/src/app/components/ProfileLink.svelte @@ -4,7 +4,7 @@ import Button from "@lib/components/Button.svelte" import ProfileName from "@app/components/ProfileName.svelte" import ProfileDetail from "@app/components/ProfileDetail.svelte" - import {pushModal} from "@app/modal" + import {pushModal} from "@app/util/modal" type Props = { pubkey: string diff --git a/src/app/components/ProfileMultiSelect.svelte b/src/app/components/ProfileMultiSelect.svelte index 00af8f10..a9715699 100644 --- a/src/app/components/ProfileMultiSelect.svelte +++ b/src/app/components/ProfileMultiSelect.svelte @@ -11,7 +11,7 @@ import ProfileSuggestion from "@app/editor/ProfileSuggestion.svelte" import ProfileName from "@app/components/ProfileName.svelte" import ProfileDetail from "@app/components/ProfileDetail.svelte" - import {pushModal} from "@app/modal" + import {pushModal} from "@app/util/modal" interface Props { value: string[] diff --git a/src/app/components/ProfileSpaces.svelte b/src/app/components/ProfileSpaces.svelte index 5ce5061a..15fa843d 100644 --- a/src/app/components/ProfileSpaces.svelte +++ b/src/app/components/ProfileSpaces.svelte @@ -5,8 +5,8 @@ import ModalFooter from "@lib/components/ModalFooter.svelte" import SpaceAvatar from "@app/components/SpaceAvatar.svelte" import RelayName from "@app/components/RelayName.svelte" - import {makeSpacePath} from "@app/routes" - import {getMembershipUrls, membershipsByPubkey} from "@app/state" + import {makeSpacePath} from "@app/util/routes" + import {getMembershipUrls, membershipsByPubkey} from "@app/core/state" type Props = { pubkey: string diff --git a/src/app/components/QRCode.svelte b/src/app/components/QRCode.svelte index f3aef80e..242229fc 100644 --- a/src/app/components/QRCode.svelte +++ b/src/app/components/QRCode.svelte @@ -2,7 +2,7 @@ import QRCode from "qrcode" import {onMount} from "svelte" import Button from "@lib/components/Button.svelte" - import {clip} from "@app/toast" + import {clip} from "@app/util/toast" const {code, ...props} = $props() diff --git a/src/app/components/ReactionSummary.svelte b/src/app/components/ReactionSummary.svelte index 0f8fed9f..07a53666 100644 --- a/src/app/components/ReactionSummary.svelte +++ b/src/app/components/ReactionSummary.svelte @@ -21,8 +21,8 @@ import Icon from "@lib/components/Icon.svelte" import Reaction from "@app/components/Reaction.svelte" import EventReportDetails from "@app/components/EventReportDetails.svelte" - import {REACTION_KINDS} from "@app/state" - import {pushModal} from "@app/modal" + import {REACTION_KINDS} from "@app/core/state" + import {pushModal} from "@app/util/modal" interface Props { event: TrustedEvent diff --git a/src/app/components/RoomCreate.svelte b/src/app/components/RoomCreate.svelte index 62c81746..797d1367 100644 --- a/src/app/components/RoomCreate.svelte +++ b/src/app/components/RoomCreate.svelte @@ -10,9 +10,9 @@ import Icon from "@lib/components/Icon.svelte" import ModalHeader from "@lib/components/ModalHeader.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte" - import {hasNip29, loadChannel} from "@app/state" - import {makeSpacePath} from "@app/routes" - import {pushToast} from "@app/toast" + import {hasNip29, loadChannel} from "@app/core/state" + import {makeSpacePath} from "@app/util/routes" + import {pushToast} from "@app/util/toast" const {url} = $props() diff --git a/src/app/components/SignUp.svelte b/src/app/components/SignUp.svelte index 09d98847..174fe7c6 100644 --- a/src/app/components/SignUp.svelte +++ b/src/app/components/SignUp.svelte @@ -10,9 +10,9 @@ import InfoNostr from "@app/components/InfoNostr.svelte" import SignUpProfile from "@app/components/SignUpProfile.svelte" import SignUpSuccess from "@app/components/SignUpSuccess.svelte" - import {pushModal} from "@app/modal" - import {BURROW_URL, PLATFORM_NAME} from "@app/state" - import {pushToast} from "@app/toast" + import {pushModal} from "@app/util/modal" + import {BURROW_URL, PLATFORM_NAME} from "@app/core/state" + import {pushToast} from "@app/util/toast" const login = () => pushModal(LogIn) diff --git a/src/app/components/SignUpComplete.svelte b/src/app/components/SignUpComplete.svelte index 4c847898..deebf613 100644 --- a/src/app/components/SignUpComplete.svelte +++ b/src/app/components/SignUpComplete.svelte @@ -7,7 +7,7 @@ import Button from "@lib/components/Button.svelte" import ModalHeader from "@lib/components/ModalHeader.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte" - import {PROTECTED} from "@app/state" + import {PROTECTED} from "@app/core/state" type Props = { secret: string diff --git a/src/app/components/SignUpKey.svelte b/src/app/components/SignUpKey.svelte index cc30c027..8e55bae9 100644 --- a/src/app/components/SignUpKey.svelte +++ b/src/app/components/SignUpKey.svelte @@ -11,8 +11,8 @@ import ModalHeader from "@lib/components/ModalHeader.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte" import SignUpComplete from "@app/components/SignUpComplete.svelte" - import {pushToast} from "@app/toast" - import {pushModal} from "@app/modal" + import {pushToast} from "@app/util/toast" + import {pushModal} from "@app/util/modal" type Props = { profile: Profile diff --git a/src/app/components/SignUpProfile.svelte b/src/app/components/SignUpProfile.svelte index dc349ee4..1c59e63d 100644 --- a/src/app/components/SignUpProfile.svelte +++ b/src/app/components/SignUpProfile.svelte @@ -6,7 +6,7 @@ import ModalFooter from "@lib/components/ModalFooter.svelte" import ProfileEditForm from "@app/components/ProfileEditForm.svelte" import SignUpKey from "@app/components/SignUpKey.svelte" - import {pushModal} from "@app/modal" + import {pushModal} from "@app/util/modal" const initialValues = { profile: makeProfile(), diff --git a/src/app/components/SignUpSuccess.svelte b/src/app/components/SignUpSuccess.svelte index 0ef1639e..7f81c39e 100644 --- a/src/app/components/SignUpSuccess.svelte +++ b/src/app/components/SignUpSuccess.svelte @@ -1,7 +1,7 @@