Add loading indicator to discover page, add deploy directions to readme
This commit is contained in:
@@ -1,11 +1,105 @@
|
|||||||
# Flotilla
|
# 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
|
# Deploy
|
||||||
|
|
||||||
To run your own Flotilla, it's as simple as `npm run build`, then serve the `build` directory.
|
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 `<SERVER NAME>`, 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=<YOUR PASSWORD HERE>
|
||||||
|
|
||||||
|
# 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 <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 <SERVER NAME>
|
||||||
|
```
|
||||||
|
|
||||||
|
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}/<SERVER NAME>
|
||||||
|
service nginx restart
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, visit your domain. You should be all set up!
|
||||||
|
|
||||||
# Development
|
# 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.
|
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.
|
||||||
|
|||||||
+2
-9
@@ -167,15 +167,8 @@ export const loadUserData = (
|
|||||||
return promise
|
return promise
|
||||||
}
|
}
|
||||||
|
|
||||||
export const discoverRelays = (lists: List[]) => {
|
export const discoverRelays = (lists: List[]) =>
|
||||||
const urls = uniq(lists.flatMap(getRelayUrls))
|
Promise.all(uniq(lists.flatMap(getRelayUrls)).filter(isShareableRelayUrl).map(loadRelay))
|
||||||
|
|
||||||
for (const url of urls) {
|
|
||||||
if (isShareableRelayUrl(url)) {
|
|
||||||
loadRelay(url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Synchronization
|
// Synchronization
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
export let pubkeys: string[]
|
export let pubkeys: string[]
|
||||||
export let messages: TrustedEvent[]
|
export let messages: TrustedEvent[]
|
||||||
|
|
||||||
const message = messages[0]
|
|
||||||
const others = remove($pubkey!, pubkeys)
|
const others = remove($pubkey!, pubkeys)
|
||||||
const active = $page.params.chat === id
|
const active = $page.params.chat === id
|
||||||
const path = makeChatPath(pubkeys)
|
const path = makeChatPath(pubkeys)
|
||||||
@@ -53,7 +52,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<p class="overflow-hidden text-ellipsis whitespace-nowrap text-sm">
|
<p class="overflow-hidden text-ellipsis whitespace-nowrap text-sm">
|
||||||
{message.content}
|
{messages[0].content}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -26,9 +26,9 @@
|
|||||||
|
|
||||||
<form class="column gap-4" on:submit|preventDefault={logout}>
|
<form class="column gap-4" on:submit|preventDefault={logout}>
|
||||||
<ModalHeader>
|
<ModalHeader>
|
||||||
<div slot="title">Are you sure you<br />want to log out?</div>
|
<div slot="title">Are you sure you want<br />to log out?</div>
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
<p>Your local database will be cleared.</p>
|
<p class="text-center">Your local database will be cleared.</p>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button class="btn btn-link" on:click={back}>
|
<Button class="btn btn-link" on:click={back}>
|
||||||
<Icon icon="alt-arrow-left" />
|
<Icon icon="alt-arrow-left" />
|
||||||
|
|||||||
@@ -21,11 +21,13 @@
|
|||||||
{/each}
|
{/each}
|
||||||
<Divider />
|
<Divider />
|
||||||
{/if}
|
{/if}
|
||||||
<Button on:click={addSpace}>
|
{#if !PLATFORM_RELAY}
|
||||||
<CardButton>
|
<Button on:click={addSpace}>
|
||||||
<div slot="icon"><Icon icon="login-2" size={7} /></div>
|
<CardButton>
|
||||||
<div slot="title">Add a space</div>
|
<div slot="icon"><Icon icon="login-2" size={7} /></div>
|
||||||
<div slot="info">Join or create a new space</div>
|
<div slot="title">Add a space</div>
|
||||||
</CardButton>
|
<div slot="info">Join or create a new space</div>
|
||||||
</Button>
|
</CardButton>
|
||||||
|
</Button>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,8 +5,11 @@
|
|||||||
import type {Filter} from "@welshman/util"
|
import type {Filter} from "@welshman/util"
|
||||||
import {deriveEvents} from "@welshman/store"
|
import {deriveEvents} from "@welshman/store"
|
||||||
import {repository, load, loadRelaySelections, formatTimestampRelative} from "@welshman/app"
|
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 Profile from "@app/components/Profile.svelte"
|
||||||
import ProfileInfo from "@app/components/ProfileInfo.svelte"
|
import ProfileInfo from "@app/components/ProfileInfo.svelte"
|
||||||
|
import {makeChatPath} from "@app/routes"
|
||||||
|
|
||||||
export let pubkey
|
export let pubkey
|
||||||
|
|
||||||
@@ -28,7 +31,13 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="card2 bg-alt col-2 shadow-xl">
|
<div class="card2 bg-alt col-2 shadow-xl">
|
||||||
<Profile {pubkey} />
|
<div class="flex justify-between">
|
||||||
|
<Profile {pubkey} />
|
||||||
|
<Link class="btn btn-primary" href={makeChatPath([pubkey])}>
|
||||||
|
<Icon icon="letter" />
|
||||||
|
Start a Chat
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
<ProfileInfo {pubkey} />
|
<ProfileInfo {pubkey} />
|
||||||
{#if roots.length > 0}
|
{#if roots.length > 0}
|
||||||
{@const event = first(sortBy(e => -e.created_at, roots))}
|
{@const event = first(sortBy(e => -e.created_at, roots))}
|
||||||
|
|||||||
+1
-1
@@ -441,7 +441,7 @@ export type Chat = {
|
|||||||
search_text: string
|
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(",")
|
export const splitChatId = (id: string) => id.split(",")
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
import {createScroller} from "@lib/html"
|
import {createScroller} from "@lib/html"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Page from "@lib/components/Page.svelte"
|
import Page from "@lib/components/Page.svelte"
|
||||||
|
import Spinner from "@lib/components/Spinner.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import PageHeader from "@lib/components/PageHeader.svelte"
|
import PageHeader from "@lib/components/PageHeader.svelte"
|
||||||
import RelayName from "@app/components/RelayName.svelte"
|
import RelayName from "@app/components/RelayName.svelte"
|
||||||
@@ -40,6 +41,7 @@
|
|||||||
let term = ""
|
let term = ""
|
||||||
let limit = 20
|
let limit = 20
|
||||||
let element: Element
|
let element: Element
|
||||||
|
let promise: Promise<any>
|
||||||
|
|
||||||
$: relaySearch = createSearch($relays, {
|
$: relaySearch = createSearch($relays, {
|
||||||
getValue: (relay: Relay) => relay.url,
|
getValue: (relay: Relay) => relay.url,
|
||||||
@@ -57,8 +59,7 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
discoverRelays($memberships)
|
promise = Promise.all([discoverRelays($memberships), discoverRelays($relaySelections)])
|
||||||
discoverRelays($relaySelections)
|
|
||||||
|
|
||||||
const scroller = createScroller({
|
const scroller = createScroller({
|
||||||
element,
|
element,
|
||||||
@@ -125,5 +126,8 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</Button>
|
</Button>
|
||||||
{/each}
|
{/each}
|
||||||
|
{#await promise}
|
||||||
|
<Spinner loading>Loading more relays...</Spinner>
|
||||||
|
{/await}
|
||||||
</div>
|
</div>
|
||||||
</Page>
|
</Page>
|
||||||
|
|||||||
Reference in New Issue
Block a user