Compare commits

..

No commits in common. "5183f73006c66e8e9f7eee3e38f696e4b4544315" and "998e8f2517bee19b54539e54de0a9b130ee1f272" have entirely different histories.

13 changed files with 53 additions and 79 deletions

View file

@ -1,10 +0,0 @@
# Campfire v0.3.0
- Added notifications view
- Many more background tweaks, fixes, and optimisations
# Campfire v0.2.0
- Complete UI overhaul (thanks mae!)
- Added light and dark themes
- Added ability to like and boost posts
- Added ability to view threads in context
- Many background tweaks, fixes, and optimisations

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "campfire-client", "name": "campfire-client",
"version": "0.3.0", "version": "0.2.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "campfire-client", "name": "campfire-client",
"version": "0.3.0", "version": "0.2.0",
"license": "GPL-3.0", "license": "GPL-3.0",
"devDependencies": { "devDependencies": {
"@poppanator/sveltekit-svg": "^4.2.1", "@poppanator/sveltekit-svg": "^4.2.1",

View file

@ -1,6 +1,6 @@
{ {
"name": "campfire-client", "name": "campfire-client",
"version": "0.3.0", "version": "0.2.0",
"description": "social media for the galaxy-wide-web! 🌌", "description": "social media for the galaxy-wide-web! 🌌",
"private": true, "private": true,
"type": "module", "type": "module",

View file

@ -1,9 +1,8 @@
import { client } from '$lib/client/client.js'; import { client } from '../client/client.js';
import { user } from '$lib/stores/user.js';
import { capabilities } from '../client/instance.js'; import { capabilities } from '../client/instance.js';
import Post from '$lib/post.js'; import Post from '../post.js';
import User from '$lib/user/user.js'; import User from '../user/user.js';
import Emoji from '$lib/emoji.js'; import Emoji from '../emoji.js';
import { get } from 'svelte/store'; import { get } from 'svelte/store';
export async function createApp(host) { export async function createApp(host) {
@ -93,7 +92,7 @@ export async function verifyCredentials() {
} }
export async function getNotifications(since_id, limit, types) { export async function getNotifications(since_id, limit, types) {
if (!get(user)) return false; if (!get(client).user) return false;
let url = `https://${get(client).instance.host}/api/v1/notifications`; let url = `https://${get(client).instance.host}/api/v1/notifications`;
@ -113,7 +112,6 @@ export async function getNotifications(since_id, limit, types) {
} }
export async function getTimeline(last_post_id) { export async function getTimeline(last_post_id) {
if (!get(user)) return false;
let url = `https://${get(client).instance.host}/api/v1/timelines/home`; let url = `https://${get(client).instance.host}/api/v1/timelines/home`;
if (last_post_id) url += "?max_id=" + last_post_id; if (last_post_id) url += "?max_id=" + last_post_id;
const data = await fetch(url, { const data = await fetch(url, {

View file

@ -2,7 +2,7 @@ import { Instance, server_types } from './instance.js';
import * as api from './api.js'; import * as api from './api.js';
import { get, writable } from 'svelte/store'; import { get, writable } from 'svelte/store';
import { last_read_notif_id } from '$lib/notifications.js'; import { last_read_notif_id } from '$lib/notifications.js';
import { user, logged_in } from '$lib/stores/user.js'; import { user } from '$lib/stores/user.js';
export const client = writable(false); export const client = writable(false);
@ -206,7 +206,6 @@ export class Client {
console.warn("Failed to log out correctly; ditching the old tokens anyways."); console.warn("Failed to log out correctly; ditching the old tokens anyways.");
} }
localStorage.removeItem(save_name); localStorage.removeItem(save_name);
logged_in.set(false);
client.set(new Client()); client.set(new Client());
console.log("Logged out successfully."); console.log("Logged out successfully.");
} }

View file

@ -29,7 +29,7 @@ export async function getNotifications() {
} }
} }
} }
notif.status = notif.status ? await api.parsePost(notif.status, 0, false) : null; notif.status = await api.parsePost(notif.status, 0, false);
notifications.update(notifications => [...notifications, notif]); notifications.update(notifications => [...notifications, notif]);
} }
last_read_notif_id.set(data[0].id); last_read_notif_id.set(data[0].id);

View file

@ -1,22 +1,4 @@
import { client } from '$lib/client/client.js'; import { writable } from 'svelte/store';
import * as api from '$lib/client/api.js';
import { get, writable } from 'svelte/store';
export let user = writable(0); export let user = writable(0);
export let logged_in = writable(false); export let logged_in = writable(false);
export async function getUser() {
// already known
if (get(user)) return get(user);
// cannot provide- not logged in
if (!get(client).app || !get(client).app.token) return false;
// logged in- attempt to retrieve using token
const data = await api.verifyCredentials();
if (!data) return false;
user.set(await api.parseUser(data));
console.log(`Logged in as @${get(user).username}@${get(user).host}`);
return get(user);
}

View file

@ -3,7 +3,6 @@
import Button from './Button.svelte'; import Button from './Button.svelte';
import Feed from './Feed.svelte'; import Feed from './Feed.svelte';
import { client } from '$lib/client/client.js'; import { client } from '$lib/client/client.js';
import { user } from '$lib/stores/user.js';
import { play_sound } from '$lib/sound.js'; import { play_sound } from '$lib/sound.js';
import { getTimeline } from '$lib/timeline.js'; import { getTimeline } from '$lib/timeline.js';
import { getNotifications } from '$lib/notifications.js'; import { getNotifications } from '$lib/notifications.js';
@ -151,11 +150,11 @@
</div> </div>
<div id="account-button"> <div id="account-button">
<img src={$user.avatar_url} class="account-avatar" height="64px" alt="" aria-hidden="true" on:click={() => play_sound()}> <img src={$client.user.avatar_url} class="account-avatar" height="64px" alt="" aria-hidden="true" on:click={() => play_sound()}>
<div class="account-name" aria-hidden="true"> <div class="account-name" aria-hidden="true">
<a href={$user.url} class="nickname" title={$user.nickname}>{$user.nickname}</a> <a href={$client.user.url} class="nickname" title={$client.user.nickname}>{$client.user.nickname}</a>
<span class="username" title={`@${$user.username}@${$user.host}`}> <span class="username" title={`@${$client.user.username}@${$client.user.host}`}>
{`@${$user.username}@${$user.host}`} {`@${$client.user.username}@${$client.user.host}`}
</span> </span>
</div> </div>
</div> </div>

View file

@ -48,7 +48,7 @@
} }
</script> </script>
<a class="notification" href={data.status ? `/post/${data.status.id}` : null} aria-label={aria_label}> <a class="notification" href={`/post/${data.status.id}`} aria-label={aria_label}>
<header aria-hidden> <header aria-hidden>
<span class="notif-icon"> <span class="notif-icon">
{#if data.type === "favourite"} {#if data.type === "favourite"}
@ -92,7 +92,7 @@
<style> <style>
.notification { .notification {
display: block; display: block;
margin-bottom: 8px; margin: 8px 0;
padding: 16px; padding: 16px;
border-radius: 8px; border-radius: 8px;
background: var(--bg-800); background: var(--bg-800);

View file

@ -3,25 +3,27 @@
import Navigation from '$lib/ui/Navigation.svelte'; import Navigation from '$lib/ui/Navigation.svelte';
import Widgets from '$lib/ui/Widgets.svelte'; import Widgets from '$lib/ui/Widgets.svelte';
import { client, Client } from '$lib/client/client.js'; import { client, Client } from '$lib/client/client.js';
import { user, getUser } from '$lib/stores/user.js';
import { get } from 'svelte/store'; import { get } from 'svelte/store';
import { logged_in } from '$lib/stores/user.js'; import { logged_in } from '$lib/stores/user.js';
import { unread_notif_count, last_read_notif_id } from '$lib/notifications.js'; import { unread_notif_count, last_read_notif_id } from '$lib/notifications.js';
let ready = new Promise(resolve => { let ready = new Promise(resolve => {
if (get(client)) { if (get(client)) {
if (get(user)) logged_in.set(true); if (get(client).user) logged_in.set(true);
return resolve(); return resolve();
} }
let new_client = new Client(); let new_client = new Client();
new_client.load(); new_client.load();
client.set(new_client); client.set(new_client);
return getUser().then(new_user => { return new_client.getClientUser().then(user => {
if (!new_user) return resolve(); if (!user) {
client.set(new_client);
logged_in.set(true); return resolve();
user.set(new_user); }
if (user) logged_in.set(true);
new_client.user = user;
window.peekie = new_client;
// spin up async task to fetch notifications // spin up async task to fetch notifications
get(client).getNotifications( get(client).getNotifications(
@ -31,6 +33,10 @@
unread_notif_count.set(notif_data.length); unread_notif_count.set(notif_data.length);
}); });
client.update(client => {
client.user = user;
return client;
});
return resolve(); return resolve();
}); });
}); });

View file

@ -1,7 +1,7 @@
<script> <script>
import { page } from '$app/stores'; import { page } from '$app/stores';
import { get } from 'svelte/store'; import { get } from 'svelte/store';
import { logged_in } from '$lib/stores/user.js'; import { client } from '$lib/client/client.js';
import { timeline, getTimeline } from '$lib/timeline.js'; import { timeline, getTimeline } from '$lib/timeline.js';
import LoginForm from '$lib/ui/LoginForm.svelte'; import LoginForm from '$lib/ui/LoginForm.svelte';
@ -9,18 +9,16 @@
import User from '$lib/user/user.js'; import User from '$lib/user/user.js';
import Button from '$lib/ui/Button.svelte'; import Button from '$lib/ui/Button.svelte';
logged_in.subscribe(logged_in => { getTimeline();
if (logged_in) getTimeline();
});
document.addEventListener("scroll", event => { document.addEventListener("scroll", event => {
if (get(logged_in) && get(page).url.pathname !== "/") return; if (get(page).url.pathname !== "/") return;
if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 2048) { if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 2048) {
getTimeline(); getTimeline();
} }
}); });
</script> </script>
{#if $logged_in} {#if $client.user}
<Feed posts={$timeline} /> <Feed posts={$timeline} />
{:else} {:else}
<LoginForm /> <LoginForm />

View file

@ -3,8 +3,6 @@
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { error } from '@sveltejs/kit'; import { error } from '@sveltejs/kit';
import { get } from 'svelte/store'; import { get } from 'svelte/store';
import { last_read_notif_id } from '$lib/notifications.js';
import { logged_in, user, getUser } from '$lib/stores/user.js';
export let data; export let data;
@ -25,18 +23,24 @@
return c; return c;
}); });
getUser().then(new_user => { get(client).getClientUser().then(user => {
if (!new_user) return; if (user) client.update(client => {
client.user = user
logged_in.set(true); return client;
user.set(new_user); });
return get(client).getNotifications( return get(client).getNotifications(
get(last_read_notif_id) get(last_read_notification_id)
).then(notif_data => { ).then(notif_data => {
if (notif_data.constructor === Array && notif_data.length > 0) client.update(client => {
last_read_notif_id.set(notif_data[0].id); // we've just logged in, so assume all past notifications are read.
get(client).save(); // i *would* just use the mastodon marker API to get the last read
// notification, but this does not appear to be widely supported.
if (notif_data.constructor === Array && notif_data.length > 0)
last_read_notification_id.set(notif_data[0].id);
client.save();
return client;
});
goto("/"); goto("/");
}); });
}); });

View file

@ -1,16 +1,10 @@
<script> <script>
import { notifications, getNotifications } from '$lib/notifications.js'; import { notifications, getNotifications } from '$lib/notifications.js';
import { logged_in } from '$lib/stores/user.js';
import { goto } from '$app/navigation';
import { get } from 'svelte/store';
import Notification from '$lib/ui/Notification.svelte'; import Notification from '$lib/ui/Notification.svelte';
if (!get(logged_in)) goto("/");
getNotifications(); getNotifications();
/* /*
document.addEventListener("scroll", event => { document.addEventListener("scroll", event => {
if (get(logged_in) && get(page).url.pathname !== "/") return;
if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 2048) { if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 2048) {
getNotifications(); getNotifications();
} }
@ -47,6 +41,10 @@
font-size: 1.5em; font-size: 1.5em;
} }
.notifications {
margin: 16px 0;
}
.loading { .loading {
width: 100%; width: 100%;
height: 80vh; height: 80vh;