diff --git a/README.md b/README.md index 48cf36d8..1555b71e 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,105 @@ # Flotilla -A discord-like nostr client based on the idea of "relays as groups". WIP. +A discord-like nostr client based on the idea of "relays as groups". # Deploy To run your own Flotilla, it's as simple as `npm run build`, then serve the `build` directory. +## Environment + +You can also optionally create an `.env.local` file and populate it with the following environment variables (see `.env` for examples): + +- `VITE_DEFAULT_PUBKEYS` - A comma-separated list of hex pubkeys for bootstrapping web of trust. +- `VITE_PLATFORM_URL` - The url where the app will be hosted. This is only used for build-time population of meta tags. +- `VITE_PLATFORM_NAME` - The name of the app +- `VITE_PLATFORM_LOGO` - A logo url for the app +- `VITE_PLATFORM_RELAY` - A relay url that will make flotilla operate in "platform mode". Disables all space browse/add/select functionality and makes the platform relay the home page. +- `VITE_PLATFORM_ACCENT` - A hex color for the app's accent color +- `VITE_PLATFORM_DESCRIPTION` - A description of the app +- `VITE_GLITCHTIP_API_KEY` - A Sentry DSN for use with glitchtip (error reporting) +- `GLITCHTIP_AUTH_TOKEN` - A glitchtip auth token for error reporting + +If you're deploying a custom version of flotilla, be sure to remove the `plausible.coracle.social` script from `app.html`. This sends analytics to a server hosted by the developer. + +## Nginx/TLS (optional) + +If you'd like to set up flotilla on a server you control, you'll want to set up a reverse proxy and provision a TSL certificate for the domain you'll be using. You should also make sure to add swap to your server. + +There will be some parts of the following templates, for example ``, which you'll need to fill in before running the code. + +First, create an `A` record with your DNS provider pointing to the IP of your server. This will allow certbot to create your certificate later. + +Next install `nginx`, `git`, and `certbot`. If you're on a debian- or ubuntu-based distro, run `sudo apt-get update && sudo apt-get install nginx git certbot python3-certbot-nginx`. + +Now, create a new user where your code will be stored, clone the repository, fill in your `.env.local` file, and build the app. + +```sh +# Replace with your password +PASSWORD= + +# Add the user and set a password +adduser flotilla +echo flotilla:$PASSWORD | chpasswd + +# Login as flotilla +sudo su flotilla + +# Go to flotilla's home directory +cd ~ + +# Install nvm, yarn, clone repos +wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash + +# Update PATH +. ~/.bashrc + +# Clone repository and install dependencies +git clone https://github.com/coracle-social/flotilla.git +cd ~/flotilla +nvm install +nvm use +npm i + +# Optionally create and populate .env.local to suit your use case + +# Build the app +NODE_OPTIONS=--max_old_space_size=16384 npm run build + +# Exit back to root +exit +``` + +Once you've exited back to root, you can set up nginx. Place the following in a file named after your domain in the `/etc/nginx/sites-available` directory, for example, `flotilla.example.com`. This should match the `A` record you registered above. + +```conf +server { + listen 80; + server_name ; + root /home/flotilla/flotilla/build; + index index.html; + + location / { + try_files $uri /index.html; + } +} +``` + +Now you can run `certbot`, which will provision a TLS certificate for your domain and update your nginx configuration. + +``` +certbot --nginx -d +``` + +Now, enable the site and restart nginx. If you want to be careful, run `nginx -t` before restarting nginx. + +``` +ln -s /etc/nginx/sites-{available,enabled}/ +service nginx restart +``` + +Now, visit your domain. You should be all set up! + # Development Run `npm run dev` to get a dev server, and `npm run check:watch` to watch for typescript errors. When you're ready to commit, run `npm run format && npm run lint` and fix any errors that come up. diff --git a/src/app/commands.ts b/src/app/commands.ts index 45b876dd..cb4d4f74 100644 --- a/src/app/commands.ts +++ b/src/app/commands.ts @@ -167,15 +167,8 @@ export const loadUserData = ( return promise } -export const discoverRelays = (lists: List[]) => { - const urls = uniq(lists.flatMap(getRelayUrls)) - - for (const url of urls) { - if (isShareableRelayUrl(url)) { - loadRelay(url) - } - } -} +export const discoverRelays = (lists: List[]) => + Promise.all(uniq(lists.flatMap(getRelayUrls)).filter(isShareableRelayUrl).map(loadRelay)) // Synchronization diff --git a/src/app/components/ChatItem.svelte b/src/app/components/ChatItem.svelte index c33d5b82..0c9dff59 100644 --- a/src/app/components/ChatItem.svelte +++ b/src/app/components/ChatItem.svelte @@ -16,7 +16,6 @@ export let pubkeys: string[] export let messages: TrustedEvent[] - const message = messages[0] const others = remove($pubkey!, pubkeys) const active = $page.params.chat === id const path = makeChatPath(pubkeys) @@ -53,7 +52,7 @@ {/if}

- {message.content} + {messages[0].content}

diff --git a/src/app/components/LogOut.svelte b/src/app/components/LogOut.svelte index 1a8be282..9222b96b 100644 --- a/src/app/components/LogOut.svelte +++ b/src/app/components/LogOut.svelte @@ -26,9 +26,9 @@
-
Are you sure you
want to log out?
+
Are you sure you want
to log out?
-

Your local database will be cleared.

+

Your local database will be cleared.

+ {#if !PLATFORM_RELAY} + + {/if} diff --git a/src/app/components/PeopleItem.svelte b/src/app/components/PeopleItem.svelte index 1aa805a9..8b1fb96d 100644 --- a/src/app/components/PeopleItem.svelte +++ b/src/app/components/PeopleItem.svelte @@ -5,8 +5,11 @@ import type {Filter} from "@welshman/util" import {deriveEvents} from "@welshman/store" import {repository, load, loadRelaySelections, formatTimestampRelative} from "@welshman/app" + import Icon from "@lib/components/Icon.svelte" + import Link from "@lib/components/Link.svelte" import Profile from "@app/components/Profile.svelte" import ProfileInfo from "@app/components/ProfileInfo.svelte" + import {makeChatPath} from "@app/routes" export let pubkey @@ -28,7 +31,13 @@
- +
+ + + + Start a Chat + +
{#if roots.length > 0} {@const event = first(sortBy(e => -e.created_at, roots))} diff --git a/src/app/state.ts b/src/app/state.ts index e18f5385..6b756dfa 100644 --- a/src/app/state.ts +++ b/src/app/state.ts @@ -441,7 +441,7 @@ export type Chat = { search_text: string } -export const makeChatId = (pubkeys: string[]) => sort(uniq(pubkeys)).join(",") +export const makeChatId = (pubkeys: string[]) => sort(uniq(pubkeys.concat(pubkey.get()!))).join(",") export const splitChatId = (id: string) => id.split(",") diff --git a/src/routes/discover/+page.svelte b/src/routes/discover/+page.svelte index 981334e6..315a0a82 100644 --- a/src/routes/discover/+page.svelte +++ b/src/routes/discover/+page.svelte @@ -7,6 +7,7 @@ import {createScroller} from "@lib/html" import Icon from "@lib/components/Icon.svelte" import Page from "@lib/components/Page.svelte" + import Spinner from "@lib/components/Spinner.svelte" import Button from "@lib/components/Button.svelte" import PageHeader from "@lib/components/PageHeader.svelte" import RelayName from "@app/components/RelayName.svelte" @@ -40,6 +41,7 @@ let term = "" let limit = 20 let element: Element + let promise: Promise $: relaySearch = createSearch($relays, { getValue: (relay: Relay) => relay.url, @@ -57,8 +59,7 @@ }) onMount(() => { - discoverRelays($memberships) - discoverRelays($relaySelections) + promise = Promise.all([discoverRelays($memberships), discoverRelays($relaySelections)]) const scroller = createScroller({ element, @@ -125,5 +126,8 @@ {/if} {/each} + {#await promise} + Loading more relays... + {/await}