diff --git a/.gitignore b/.gitignore index 4cb396f..10e9324 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ **/.DS_Store node_modules/ -build/ +dist/ .secret/ .svelte-kit/ diff --git a/README.md b/README.md index 9ea7d71..adab278 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,17 @@ -# Campfire +# space social social media for the galaxy-wide-web! 🌌 -this is a *very experimental* frontend for browsing the fediverse, built -from the ground up in svelte! +this is a neat experiment in building as much of a fediverse-compatible +software stack as i can (at least before the crippling weight of the full +activitypub spec finally cripples me) + +starting, of course, with a nice frontend! ✨ should you choose to play around with this yourself, just know that *many -things are bound not to work!* notably, campfire is currently only being -battle-tested on mastodon API-compliant instances. anything beyond this -will likely be incompatible, and the web console will get very upset. +things are bound not to work!* notably, this has only been tested on iceshrimp +and mastodon API-compliant instances. anything beyond this will likely be +incompatible, and the web console will get very upset. ## features @@ -31,17 +34,10 @@ will likely be incompatible, and the web console will get very upset. - fast account switching - post editing/deletion - push notifications -- ...and potentially much more as development continues! ## try it out! - `git clone` this repo - `npm install` the dependencies - `npm run dev` to spin up the dev environment - -if you wish to run this in production, you need only `npm run build` and -place the static files somewhere accessible by a static webhost, such as -nginx or apache! **note:** your web server should attempt to reach -`/fallback.html` before erroring out. - -have fun! ✨ +- have fun! ✨ diff --git a/package.json b/package.json index 873a26b..cb454e0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "spacesocial-client", - "version": "0.2.0_rev3", + "version": "0.2.0_rev2", "description": "social media for the galaxy-wide-web! 🌌", "private": true, "type": "module", diff --git a/res/campfire-favicon.afdesign b/res/campfire-favicon.afdesign deleted file mode 100644 index 8ff94a6..0000000 --- a/res/campfire-favicon.afdesign +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:846759440d8bdc603d08bec02c4a5e5e65e15aedd0de394b8d75c83be83857eb -size 58281 diff --git a/res/campfire-logo.afdesign b/res/campfire-logo.afdesign deleted file mode 100644 index 017152f..0000000 --- a/res/campfire-logo.afdesign +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f670c0f8c1785a3bfc16f0d343175291a6dcd460760bac07ae959068be532854 -size 31593 diff --git a/res/spacesocial-logo.afdesign b/res/spacesocial-logo.afdesign new file mode 100644 index 0000000..7e42a6e --- /dev/null +++ b/res/spacesocial-logo.afdesign @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a03c7e1af2cc54bbe621de3a68f41a75574dbcc498a9918e9fe387c5cb9d31c0 +size 41570 diff --git a/src/app.html b/src/app.html index ce47f4e..bfa4811 100644 --- a/src/app.html +++ b/src/app.html @@ -4,23 +4,7 @@ - - Campfire - - - - - - - - - - - - - - - + space social %sveltekit.head% diff --git a/src/img/CampfireLogo.svelte b/src/img/CampfireLogo.svelte deleted file mode 100644 index 2634a57..0000000 --- a/src/img/CampfireLogo.svelte +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/src/img/campfire-logo.svg b/src/img/campfire-logo.svg deleted file mode 100644 index 99365b6..0000000 --- a/src/img/campfire-logo.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/img/spacesocial-logo.svg b/src/img/spacesocial-logo.svg new file mode 100644 index 0000000..b4f6ac0 --- /dev/null +++ b/src/img/spacesocial-logo.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + space social + + diff --git a/src/lib/app.css b/src/lib/app.css index b2fcd4c..c49cb44 100644 --- a/src/lib/app.css +++ b/src/lib/app.css @@ -20,15 +20,6 @@ --accent: #CDA1EC; --text: #E2DFE3; } - .light-only { - display: none - } -} - -@media screen and (prefers-color-scheme: light) { - .dark-only { - display: none - } } @supports (font-variation-settings: normal) { @@ -58,7 +49,7 @@ a:hover { text-decoration: underline; } -#app { +#spacesocial-app { margin: auto 0; padding: 0 16px; display: flex; diff --git a/src/lib/client/api.js b/src/lib/client/api.js index 27f0e0b..403ea44 100644 --- a/src/lib/client/api.js +++ b/src/lib/client/api.js @@ -7,10 +7,10 @@ import { get } from 'svelte/store'; export async function createApp(host) { let form = new FormData(); - form.append("client_name", "Campfire"); - form.append("redirect_uris", `${location.origin}/callback`); + form.append("client_name", "space social"); + form.append("redirect_uris", `${location.origin}`); form.append("scopes", "read write push"); - form.append("website", "https://campfire.bliss.town"); + form.append("website", "https://spacesocial.arimelody.me"); const res = await fetch(`https://${host}/api/v1/apps`, { method: "POST", @@ -35,7 +35,7 @@ export function getOAuthUrl() { return `https://${client.instance.host}/oauth/authorize` + `?client_id=${client.app.id}` + "&scope=read+write+push" + - `&redirect_uri=${location.origin}/callback` + + `&redirect_uri=${location.origin}` + "&response_type=code"; } @@ -44,7 +44,7 @@ export async function getToken(code) { let form = new FormData(); form.append("client_id", client.app.id); form.append("client_secret", client.app.secret); - form.append("redirect_uri", `${location.origin}/callback`); + form.append("redirect_uri", `${location.origin}`); form.append("grant_type", "authorization_code"); form.append("code", code); form.append("scope", "read write push"); @@ -212,6 +212,9 @@ export async function parsePost(data, ancestor_count, with_context) { let client = get(Client.get()); let post = new Post(); + // if (client.instance.capabilities.includes(capabilities.MARKDOWN_CONTENT)) + // post.text = data.text; + // else post.text = data.content; post.reply = null; @@ -220,10 +223,10 @@ export async function parsePost(data, ancestor_count, with_context) { ancestor_count !== 0 ) { const reply_data = data.reply || await getPost(data.in_reply_to_id, ancestor_count - 1); + post.reply = await parsePost(reply_data, ancestor_count - 1, false); // if the post returns false, we probably don't have permission to read it. // we'll respect the thread's privacy, and leave it alone :) - if (!reply_data) return false; - post.reply = await parsePost(reply_data, ancestor_count - 1, false); + if (post.reply === false) return false; } post.boost = data.reblog ? await parsePost(data.reblog, 1, false) : null; @@ -256,7 +259,7 @@ export async function parsePost(data, ancestor_count, with_context) { post.reply_count = data.replies_count; post.favourite_count = data.favourites_count; post.favourited = data.favourited; - post.boosted = data.reblogged; + post.boosted = data.boosted; post.mentions = data.mentions; post.files = data.media_attachments; post.url = data.url; @@ -302,7 +305,7 @@ export async function parseUser(data) { if (data.acct.includes('@')) user.host = data.acct.split('@')[1]; else - user.host = client.instance.host; + user.host = get(Client.get()).instance.host; user.emojis = []; data.emojis.forEach(emoji_data => { @@ -312,7 +315,7 @@ export async function parseUser(data) { user.emojis.push(parseEmoji(emoji_data)); }); - client.putCacheUser(user); + get(Client.get()).putCacheUser(user); return user; } diff --git a/src/lib/client/client.js b/src/lib/client/client.js index f4e3788..5153c52 100644 --- a/src/lib/client/client.js +++ b/src/lib/client/client.js @@ -4,7 +4,7 @@ import { get, writable } from 'svelte/store'; let client = writable(false); -const save_name = "campfire"; +const save_name = "spacesocial"; export class Client { instance; @@ -15,7 +15,6 @@ export class Client { constructor() { this.instance = null; this.app = null; - this.user = null; this.cache = { users: {}, emojis: {}, @@ -23,9 +22,10 @@ export class Client { } static get() { - let current = get(client); - if (current && current.app) return client; + if (get(client)) return client; let new_client = new Client(); + if (typeof window !== typeof undefined) + window.peekie = new_client; new_client.load(); client.set(new_client); return client; @@ -44,13 +44,13 @@ export class Client { if (this.instance.type == server_types.UNSUPPORTED) { console.warn(`Server ${host} is unsupported - ${data.version}`); if (!confirm( - `This app does not officially support ${host}. ` + - `Things may break, or otherwise not work as epxected! ` + - `Are you sure you wish to continue?` - )) return false; + `This app does not officially support ${host}. ` + + `Things may break, or otherwise not work as epxected! ` + + `Are you sure you wish to continue?` + )) return false; } else { - console.log(`Server is "${this.instance.type}" (or compatible) with capabilities: [${this.instance.capabilities}].`); - } + console.log(`Server is "${this.instance.type}" (or compatible) with capabilities: [${this.instance.capabilities}].`); + } this.app = await api.createApp(host); @@ -85,21 +85,11 @@ export class Client { } async verifyCredentials() { - if (this.user) return this.user; - if (!this.app || !this.app.token) { - this.user = false; - return false; - } const data = await api.verifyCredentials(); - if (!data) { - this.user = false; - return false; - } - await client.update(async c => { - c.user = await api.parseUser(data); - console.log(`Logged in as @${c.user.username}@${c.user.host}`); - }); - return this.user; + if (!data) return false; + this.user = await api.parseUser(data); + client.set(this); + return data; } async getTimeline(last_post_id) { diff --git a/src/lib/timeline.js b/src/lib/timeline.js index 5858199..667b4ee 100644 --- a/src/lib/timeline.js +++ b/src/lib/timeline.js @@ -4,14 +4,13 @@ import { parsePost } from '$lib/client/api.js'; export let posts = writable([]); +let client = get(Client.get()); let loading = false; export async function getTimeline(clean) { if (loading) return; // no spamming!! loading = true; - let client = get(Client.get()); - let timeline_data; if (clean || get(posts).length === 0) timeline_data = await client.getTimeline() else timeline_data = await client.getTimeline(get(posts)[get(posts).length - 1].id); diff --git a/src/lib/ui/Navigation.svelte b/src/lib/ui/Navigation.svelte index 7a01fd3..c5c1a2e 100644 --- a/src/lib/ui/Navigation.svelte +++ b/src/lib/ui/Navigation.svelte @@ -1,15 +1,13 @@
🗨️ - 🔁 - + toggleBoost()} bind:active={post.boosted} bind:count={post.boost_count} sound="boost">🔁 + toggleFavourite()} bind:active={post.favourited} bind:count={post.favourite_count}>⭐ 😃 🗣️ 🛠️ diff --git a/src/lib/ui/post/ReplyContext.svelte b/src/lib/ui/post/ReplyContext.svelte index dc7dd10..b328d3b 100644 --- a/src/lib/ui/post/ReplyContext.svelte +++ b/src/lib/ui/post/ReplyContext.svelte @@ -16,8 +16,8 @@ let aria_label = post.user.username + '; ' + post.text + '; ' + post.created_at; function gotoPost() { + if (focused) return; if (event.key && event.key !== "Enter") return; - console.log(`/post/${post.id}`); goto(`/post/${post.id}`); } @@ -108,8 +108,8 @@
🗨️ - 🔁 - + toggleBoost()} bind:active={post.boosted} bind:count={post.boost_count} sound="boost">🔁 + toggleFavourite()} bind:active={post.favourited} bind:count={post.favourite_count}>⭐ 😃 🗣️ 🛠️ diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte deleted file mode 100644 index b55ec41..0000000 --- a/src/routes/+layout.svelte +++ /dev/null @@ -1,21 +0,0 @@ - - -
- -
- -
- -
- -
- -
- -
- -
diff --git a/src/routes/+page.js b/src/routes/+page.js deleted file mode 100644 index 8a7c3ff..0000000 --- a/src/routes/+page.js +++ /dev/null @@ -1,15 +0,0 @@ -import Feed from '$lib/ui/Feed.svelte'; -import { Client } from '$lib/client/client.js'; -import Button from '$lib/ui/Button.svelte'; -import { get } from 'svelte/store'; - -export const prerender = true; -export const ssr = false; - -export async function load() { - let client = get(Client.get()); - await client.verifyCredentials(); - return { - client: client - }; -} diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index ffa3414..197b7d9 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,30 +1,41 @@ -{#if logged_in} +
+
-

Home

- +
- -{:else} -
- -

Welcome, fediverse user!

-

Please enter your instance domain to log in.

-
- - {#if instance_url_error} -

{instance_url_error}

- {/if} -
-
- -

- Please note this is - extremely experimental software; - things are likely to break! -
- If that's all cool with you, welcome aboard! -

+
+ {#if ready} + {#if logged_in} +
+

Home

+ +
- - -{/if} + + {:else} +
+
+

Space Social

+

Welcome, fediverse user!

+

Please enter your instance domain to log in.

+
+ + {#if instance_url_error} +

{instance_url_error}

+ {/if} +
+
+ +

+ Please note this is + extremely experimental software; + things are likely to break! +
+ If that's all cool with you, welcome aboard! +

+ + +
+
+ {/if} + {:else} +
+ just a moment... +
+ {/if} +
+ +
+ +
+ +
diff --git a/src/routes/callback/+page.js b/src/routes/callback/+page.js deleted file mode 100644 index 80122d2..0000000 --- a/src/routes/callback/+page.js +++ /dev/null @@ -1,20 +0,0 @@ -import { Client } from '$lib/client/client.js'; -import { goto } from '$app/navigation'; -import { error } from '@sveltejs/kit'; -import { get } from 'svelte/store'; - -export const ssr = false; - -export async function load({ params, url }) { - const client = get(Client.get()); - let auth_code = url.searchParams.get("code"); - if (auth_code) { - client.getToken(auth_code).then(() => { - client.save(); - goto("/"); - }); - } - error(400, { - message: "Bad request" - }); -} diff --git a/src/routes/post/+page.js b/src/routes/post/+page.js deleted file mode 100644 index c0ac9bd..0000000 --- a/src/routes/post/+page.js +++ /dev/null @@ -1,5 +0,0 @@ -import { error } from '@sveltejs/kit'; - -export function load(event) { - error(404, 'Not Found'); -} diff --git a/src/routes/post/[id]/+layout.svelte b/src/routes/post/[id]/+layout.svelte new file mode 100644 index 0000000..b4b556d --- /dev/null +++ b/src/routes/post/[id]/+layout.svelte @@ -0,0 +1,50 @@ + + +
+ +
+ +
+ +
+
+

Home

+ +
+ + +
+ +
+ +
+ +
+ + diff --git a/src/routes/post/[id]/+page.js b/src/routes/post/[id]/+page.js index e9f391c..ea5ef2c 100644 --- a/src/routes/post/[id]/+page.js +++ b/src/routes/post/[id]/+page.js @@ -3,11 +3,22 @@ import { Client } from '$lib/client/client.js'; import { parsePost } from '$lib/client/api.js'; import { get } from 'svelte/store'; +export const prerender = true; export const ssr = false; export async function load({ params }) { let client = get(Client.get()); - await client.verifyCredentials(); + if (client.app && client.app.token) { + // this triggers the client actually getting the authenticated user's data. + const res = await client.verifyCredentials() + if (res) { + console.log(`Logged in as @${client.user.username}@${client.user.host}`); + } else { + return null; + } + } else { + return null; + } const post_id = params.id; diff --git a/src/routes/post/[id]/+page.svelte b/src/routes/post/[id]/+page.svelte index a5e9edc..c583bd9 100644 --- a/src/routes/post/[id]/+page.svelte +++ b/src/routes/post/[id]/+page.svelte @@ -1,57 +1,27 @@ -
-

Home

- -
-
{#if data.posts.length <= 0}
just a moment...
{:else} - {#key data}
{#each replies as post} {/each} - {/key} {/if}