{post.warning}
+ {/if} + {#if post.text} + {@html post.rich_text} + {/if} +this is quoting a post! quotes are not supported yet.
+ + {/if} +diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..520b89d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +**/.DS_Store +node_modules/ +dist/ diff --git a/index.html b/index.html new file mode 100644 index 0000000..f4976ad --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + +
+ + + +social media for the galaxy-wide-web! 🌌
+ +this app requires a instance host and session token to work! you may enter these below:
+ + + +ice.arimelody.me
.
+ + your login credentials will not be saved to an external server. + they are required for communication with the fediverse instance, and are saved entirely within your browser. + a cleaner login flow will be built in the future. +
++ oh yeah i should also probably mention this is extremely experimental software; + even if you use the exact same instance as me, you may encounter problems. + if that's all cool with you, welcome aboard! +
+ +made with ❤️ by ari melody, 2024
+{@html msg}
+ {/if} + {#if trace} +{trace}+ {/if} +
{post.warning}
+ {/if} + {#if post.text} + {@html post.rich_text} + {/if} +this is quoting a post! quotes are not supported yet.
+ + {/if} +${current.text}
`;
+ if (current.parent) current.parent.text += out;
+ else response += out;
+ current = current.parent;
+ } else {
+ current.text += sample[0];
+ index++;
+ }
+ } else if (allow_new) {
+ // can we add to stack?
+ let pushed = false;
+ for (let i = 0; i < markdown_tokens.length; i++) {
+ let item = markdown_tokens[i];
+ if (sample.startsWith(item.token)) {
+ let new_current = {
+ token: item.token,
+ tag: item.tag,
+ text: "",
+ parent: current,
+ };
+ if (item.token === '```' || item.token === '`') new_current.nostack = true;
+ current = new_current;
+ pushed = true;
+ index += current.token.length;
+ break;
+ }
+ }
+ if (!pushed) {
+ response += sample[0];
+ index++;
+ }
+ }
+ }
+
+ // destroy the remaining stack
+ while (current) {
+ let out = current.token + current.text;
+ if (current.parent) current.parent.text += out;
+ else response += out;
+ current = current.parent;
+ }
+
+ return response;
+ }
+}
diff --git a/src/sound.js b/src/sound.js
new file mode 100644
index 0000000..bbbd62f
--- /dev/null
+++ b/src/sound.js
@@ -0,0 +1,17 @@
+const sounds = {
+ "default": new Audio("sound/log.ogg"),
+ "post": new Audio("sound/success.ogg"),
+ "boost": new Audio("sound/hello.ogg"),
+};
+
+export function play_sound(name) {
+ if (!name) name = "default";
+ const sound = sounds[name];
+ if (!sound) {
+ console.warn(`Attempted to play sound "${name}", which does not exist!`);
+ return;
+ }
+ sound.pause();
+ sound.currentTime = 0;
+ sound.play();
+}
diff --git a/src/time.js b/src/time.js
new file mode 100644
index 0000000..27ff200
--- /dev/null
+++ b/src/time.js
@@ -0,0 +1,23 @@
+const denoms = [
+ { unit: 's', min: 0 },
+ { unit: 'm', min: 60 },
+ { unit: 'h', min: 60 },
+ { unit: 'd', min: 24 },
+ { unit: 'w', min: 7 },
+ { unit: 'y', min: 52 },
+];
+
+export function shorthand(date) {
+ let value = (new Date() - date) / 1000;
+ let unit = 's';
+ let index = 0;
+ while (index < denoms.length - 1) {
+ if (value < denoms[index + 1].min) break;
+ index++
+ value /= denoms[index].min;
+ unit = denoms[index].unit;
+ }
+ if (value > 0)
+ return Math.floor(value) + unit + " ago";
+ return "in " + Math.floor(value) + unit;
+}
diff --git a/src/user/user.js b/src/user/user.js
new file mode 100644
index 0000000..2a8a803
--- /dev/null
+++ b/src/user/user.js
@@ -0,0 +1,83 @@
+import Instance from '../instance.js';
+import Emoji from '../emoji.js';
+
+let user_cache = Object;
+
+export default class User {
+ id;
+ nickname;
+ username;
+ host;
+ avatar_url;
+ emojis;
+
+ static resolve_id(id) {
+ return user_cache[id];
+ }
+
+ static resolve_mention(mention) {
+ for (let i = 0; i < Object.keys(user_cache).length; i++) {
+ let user = user_cache[Object.keys(user_cache)[i]];
+ if (user.mention === mention) return user;
+ }
+ }
+
+ static parse(data) {
+ const instance = Instance.get_instance();
+ let user = null;
+ switch (instance.type) {
+ case Instance.types.ICESHRIMP:
+ user = User.#parse_iceshrimp(data);
+ break;
+ case Instance.types.MASTODON:
+ user = User.#parse_mastodon(data);
+ break;
+ default:
+ break;
+ }
+ if (!user) {
+ console.error("Error while parsing user data");
+ return null;
+ }
+ user_cache[user.id] = user;
+ return user;
+ }
+
+ static #parse_iceshrimp(data) {
+ let user = new User();
+ user.id = data.id;
+ user.nickname = data.name;
+ user.username = data.username;
+ user.host = data.host || Instance.get_instance().host;
+ user.avatar_url = data.avatarUrl;
+ user.emojis = [];
+ data.emojis.forEach(emoji => {
+ user.emojis.push(Emoji.parse(emoji, user.host));
+ });
+ return user;
+ }
+
+ static #parse_mastodon(data) {
+ let user = new User();
+ user.id = data.id;
+ user.nickname = data.display_name;
+ user.username = data.username;
+ user.host = data.acct.search('@') ? data.acct.substring(data.acct.search('@') + 1) : instance.host;
+ user.avatar_url = data.avatar;
+ user.emojis = [];
+ data.emojis.forEach(emoji => {
+ user.emojis.push(Emoji.parse(emoji, user.host));
+ });
+ return user;
+ }
+
+ get name() {
+ return this.nickname || this.username;
+ }
+
+ get mention() {
+ let res = "@" + this.username;
+ if (this.host) res += "@" + this.host;
+ return res;
+ }
+}
diff --git a/svelte.config.js b/svelte.config.js
new file mode 100644
index 0000000..61eb947
--- /dev/null
+++ b/svelte.config.js
@@ -0,0 +1,7 @@
+import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
+
+export default {
+ // Consult https://svelte.dev/docs#compile-time-svelte-preprocess
+ // for more information about preprocessors
+ preprocess: vitePreprocess(),
+}
diff --git a/vite.config.js b/vite.config.js
new file mode 100644
index 0000000..5f1c8cb
--- /dev/null
+++ b/vite.config.js
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vite'
+import { svelte } from '@sveltejs/vite-plugin-svelte'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [svelte()],
+})