diff --git a/apps/web/src/chatStickers.ts b/apps/web/src/chatStickers.ts new file mode 100644 index 0000000..fe2d9b0 --- /dev/null +++ b/apps/web/src/chatStickers.ts @@ -0,0 +1,39 @@ +export type ChatSticker = { + label: string; + text: string; +}; + +export const STICKER_PREFIX = "[gashboard sticker]"; + +export const CHAT_STICKERS: ChatSticker[] = [ + { label: "fiat heater", text: "FIAT HEATER DETECTED: warm room, cold wallet." }, + { label: "no hashes", text: "NO HASHES. JUST GHEI. just fiat and a pension." }, + { label: "cope block", text: "BLOCK FOUND: not by us, obviously. carry on pretending." }, + { label: "desk miner", text: "DESK MINER ENERGY: tiny fan, enormous delusion." }, + { label: "pool bully", text: "BIG POOL ENTERED CHAT: scaled up to not shame the children." }, + { label: "paper hands", text: "PAPER HANDS, PLASTIC HEATER, ZERO SATS." }, + { label: "nonce cult", text: "NONCE CULT MEETING: attendance low, conviction insane." }, + { label: "fiat friend", text: "YOUR FIAT FRIEND THINKS THE HEATER IS AN INVESTMENT." }, + { label: "warm tonight", text: "SOMEONE'S GETTING WARMED TONIGHT. maybe not paid." }, + { label: "difficulty", text: "DIFFICULTY ADJUSTMENT: reality filed another complaint." }, + { label: "best calc", text: "BEST CALC: almost important, spiritually devastating." }, + { label: "hash high", text: "HASHRATE UP. ODDS STILL NEED A TELESCOPE." }, + { label: "pension", text: "JUST FIAT AND A PENSION: the saddest proof-of-warmth." }, + { label: "sovereign", text: "SOVEREIGN MINER: no block, no boss, no apology." }, + { label: "amber", text: "SIGNED BY A REAL SIGNER, UNLIKE YOUR BOOMER'S DIRECT DEBIT." }, + { label: "mempool", text: "MEMPOOL SAYS NO. DASHBOARD SAYS LOL." }, + { label: "reject", text: "REJECTED SHARE: even the server had standards." }, + { label: "bigpapa", text: "BIGPAPA IS WATCHING. probably collecting fuck all." }, + { label: "lottery", text: "SOLO LOTTERY TICKET PURCHASED WITH ELECTRICITY AND DENIAL." }, + { label: "fiat people", text: "FIAT PEOPLE SEE A HEATER. MINERS SEE A COWARD." }, +]; + +export function stickerContent(sticker: ChatSticker): string { + return `${STICKER_PREFIX} ${sticker.text}`; +} + +export function unsticker(content: string): string | null { + return content.startsWith(`${STICKER_PREFIX} `) + ? content.slice(STICKER_PREFIX.length + 1) + : null; +} diff --git a/apps/web/src/components/ChatDrawer.vue b/apps/web/src/components/ChatDrawer.vue index b2569f1..8a79d01 100644 --- a/apps/web/src/components/ChatDrawer.vue +++ b/apps/web/src/components/ChatDrawer.vue @@ -3,6 +3,7 @@ import { computed, nextTick, onMounted, onUnmounted, ref, watch } from "vue"; import { useAuthStore } from "../stores/auth"; import * as chat from "../services/chat"; import type { ChatMessage, ChatProfile } from "../services/chat"; +import { CHAT_STICKERS, stickerContent, unsticker, type ChatSticker } from "../chatStickers"; const props = defineProps<{ open: boolean }>(); const emit = defineEmits<{ close: [] }>(); @@ -13,6 +14,7 @@ const profiles = ref>({}); const draft = ref(""); const error = ref(""); const loading = ref(false); +const showStickers = ref(false); const listEl = ref(null); let sub: { close: () => void } | null = null; @@ -81,11 +83,20 @@ async function loadMissingProfiles(): Promise { async function send(): Promise { const content = draft.value.trim(); if (!content) return; + await sendContent(content); + draft.value = ""; +} + +async function sendSticker(sticker: ChatSticker): Promise { + await sendContent(stickerContent(sticker)); + showStickers.value = false; +} + +async function sendContent(content: string): Promise { error.value = ""; try { const message = await chat.sendChat(content); if (!messages.value.some((m) => m.id === message.id)) messages.value.push(message); - draft.value = ""; await loadMissingProfiles(); await scrollBottom(); } catch (e) { @@ -101,6 +112,10 @@ function timeLabel(ts: number): string { return new Date(ts * 1000).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }); } +function stickerText(content: string): string | null { + return unsticker(content); +} + async function scrollBottom(): Promise { await nextTick(); if (listEl.value) listEl.value.scrollTop = listEl.value.scrollHeight; @@ -138,12 +153,35 @@ async function scrollBottom(): Promise { {{ profile(message.pubkey).name }} {{ timeLabel(message.createdAt) }} -

{{ message.content }}

+

{{ message.content }}

+

{{ stickerText(message.content) }}

+
+ + {{ CHAT_STICKERS.length }} signed insults ready +
+
+ +