slack status without the slack status.zzstoatzz.io
hatk statusphere
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 101 lines 3.5 kB view raw
1<script lang="ts"> 2 import { page } from '$app/stores' 3 import { callXrpc } from '$hatk/client' 4 import { isCustomEmoji, customEmojiName, bufoImageUrl, bufoFallbackUrl } from '$lib/utils/emoji' 5 import EmojiPicker from './EmojiPicker.svelte' 6 7 let { currentEmoji = '😊', oncreated }: { currentEmoji?: string; oncreated?: () => void } = $props() 8 9 let selectedEmoji = $derived(currentEmoji) 10 let text = $state('') 11 let expiresValue = $state('') 12 let customDatetime = $state('') 13 let showPicker = $state(false) 14 let submitting = $state(false) 15 16 function toLocalDatetimeString(date: Date) { 17 const offset = date.getTimezoneOffset() 18 const local = new Date(date.getTime() - offset * 60 * 1000) 19 return local.toISOString().slice(0, 16) 20 } 21 22 function onExpiresChange() { 23 if (expiresValue === 'custom') { 24 const defaultTime = new Date(Date.now() + 60 * 60 * 1000) 25 customDatetime = toLocalDatetimeString(defaultTime) 26 } 27 } 28 29 async function submit(e: Event) { 30 e.preventDefault() 31 if (!selectedEmoji || !$page.data.viewer) return 32 33 submitting = true 34 try { 35 const record: Record<string, string> = { 36 emoji: selectedEmoji, 37 createdAt: new Date().toISOString(), 38 } 39 if (text.trim()) record.text = text.trim() 40 if (expiresValue === 'custom' && customDatetime) { 41 record.expires = new Date(customDatetime).toISOString() 42 } else if (expiresValue && expiresValue !== 'custom') { 43 record.expires = new Date(Date.now() + parseInt(expiresValue) * 60 * 1000).toISOString() 44 } 45 46 await callXrpc('dev.hatk.createRecord', { 47 collection: 'io.zzstoatzz.status.record', 48 repo: $page.data.viewer.did, 49 record, 50 }) 51 52 text = '' 53 expiresValue = '' 54 oncreated?.() 55 } catch (err: any) { 56 alert('Failed to set status: ' + (err?.message ?? err)) 57 } finally { 58 submitting = false 59 } 60 } 61</script> 62 63<form class="status-form" onsubmit={submit}> 64 <div class="emoji-input-row"> 65 <button type="button" class="emoji-trigger" onclick={() => showPicker = true}> 66 {#if isCustomEmoji(selectedEmoji)} 67 {@const name = customEmojiName(selectedEmoji)} 68 <img src={bufoImageUrl(name)} alt={name} onerror={(e) => { (e.currentTarget as HTMLImageElement).src = bufoFallbackUrl(name) }} /> 69 {:else} 70 {selectedEmoji} 71 {/if} 72 </button> 73 <input type="text" placeholder="what's happening?" maxlength="256" bind:value={text} /> 74 </div> 75 <div class="form-actions"> 76 <select bind:value={expiresValue} onchange={onExpiresChange}> 77 <option value="">don't clear</option> 78 <option value="30">30 min</option> 79 <option value="60">1 hour</option> 80 <option value="120">2 hours</option> 81 <option value="240">4 hours</option> 82 <option value="480">8 hours</option> 83 <option value="1440">1 day</option> 84 <option value="10080">1 week</option> 85 <option value="custom">custom...</option> 86 </select> 87 {#if expiresValue === 'custom'} 88 <input type="datetime-local" class="custom-datetime" bind:value={customDatetime} min={toLocalDatetimeString(new Date())} /> 89 {/if} 90 <button type="submit" disabled={submitting}> 91 {submitting ? 'setting...' : 'set status'} 92 </button> 93 </div> 94</form> 95 96{#if showPicker} 97 <EmojiPicker 98 onselect={(emoji) => { selectedEmoji = emoji; showPicker = false }} 99 onclose={() => showPicker = false} 100 /> 101{/if}