wip bsky client for the web & android
0
fork

Configure Feed

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

feat: add KEYS constants for storage keys

willow 71f6e01a 4823b272

+68 -17
+30 -4
src/stores/auth.ts
··· 16 16 WebDidDocumentResolver, 17 17 XrpcHandleResolver, 18 18 } from '@atcute/identity-resolver' 19 - import { Client, simpleFetchHandler } from '@atcute/client' 19 + import { Client, simpleFetchHandler, ok } from '@atcute/client' 20 + import { AppBskyActorDefs } from '@atcute/bluesky' 20 21 import type { ActorIdentifier } from '@atcute/lexicons' 21 22 import type { DidString } from '@/types/atproto.ts' 22 23 24 + import _KEYS from '@/utils/keys' 25 + const KEYS = _KEYS.AUTH 26 + 23 27 export const useAuthStore = defineStore('auth', () => { 24 28 const session = ref<Session | null>(null) 25 29 const agent = ref<OAuthUserAgent | null>(null) ··· 28 32 const error = ref<string | null>(null) 29 33 30 34 const isAuthenticated = computed(() => !!session.value) 31 - const activeDid = ref<string | null>(localStorage.getItem('bluebell-active-did')) 35 + const activeDid = ref<string | null>(localStorage.getItem(KEYS.ACTIVE_DID)) 32 36 const userDid = computed(() => session.value?.info.sub) 37 + const profile = ref<AppBskyActorDefs.ProfileViewDetailed | null>(null) 33 38 34 39 function init() { 35 40 configureOAuth({ ··· 63 68 }) 64 69 session.value = restoredSession 65 70 agent.value = markRaw(new OAuthUserAgent(restoredSession)) 71 + await fetchProfile() 66 72 } catch (err) { 67 73 console.error('Failed to resume session', err) 68 74 } finally { ··· 70 76 } 71 77 } 72 78 79 + async function fetchProfile() { 80 + if (!session.value) return 81 + try { 82 + const rpc = getRpc() 83 + const data = await ok( 84 + rpc.get('app.bsky.actor.getProfile', { 85 + params: { actor: session.value.info.sub }, 86 + }), 87 + ) 88 + profile.value = data 89 + } catch (e) { 90 + console.error('Failed to fetch profile', e) 91 + } 92 + } 93 + 73 94 async function login(input: string) { 74 95 isLoading.value = true 75 96 error.value = null ··· 143 164 agent.value = markRaw(new OAuthUserAgent(result.session)) 144 165 145 166 activeDid.value = result.session.info.sub 146 - localStorage.setItem('bluebell-active-did', result.session.info.sub) 167 + localStorage.setItem(KEYS.ACTIVE_DID, result.session.info.sub) 147 168 169 + await fetchProfile() 148 170 return true 149 171 } catch (err: unknown) { 150 172 console.log(err) ··· 169 191 session.value = null 170 192 agent.value = null 171 193 activeDid.value = null 172 - localStorage.removeItem('bluebell-active-did') 194 + profile.value = null 195 + localStorage.removeItem(KEYS.ACTIVE_DID) 173 196 } 174 197 175 198 function getRpc() { ··· 188 211 handleCallback, 189 212 logout, 190 213 getRpc, 214 + agent, 215 + profile, 216 + fetchProfile, 191 217 } 192 218 })
+9 -13
src/stores/theme.ts
··· 2 2 import { ref, computed, watch } from 'vue' 3 3 import { useEnvironmentStore } from './environment' 4 4 5 + import KEYS from '@/utils/keys' 6 + 5 7 export interface ThemeDefinition { 6 8 id: string 7 9 name: string ··· 164 166 export type AccentColour = (typeof AccentColours)[number] 165 167 export const themes = [latte, frappe, macchiato, mocha] 166 168 167 - const STORAGE_KEYS = { 168 - FOLLOW_SYSTEM: 'bluebell-theme-follow', 169 - PREFERRED_LIGHT: 'bluebell-theme-light', 170 - PREFERRED_DARK: 'bluebell-theme-dark', 171 - CURRENT_MODE: 'bluebell-theme-mode', 172 - ACCENT_COLOUR: 'bluebell-theme-accent', 173 - } 169 + const STORAGE_KEYS = KEYS.THEME 174 170 175 171 export const useThemeStore = defineStore('theme', () => { 176 172 const env = useEnvironmentStore() ··· 238 234 } 239 235 240 236 function init() { 241 - const storedFollow = localStorage.getItem(STORAGE_KEYS.FOLLOW_SYSTEM) 237 + const storedFollow = localStorage.getItem(STORAGE_KEYS.FOLLOW_SYSTEM_THEME) 242 238 if (storedFollow !== null) { 243 239 followSystem.value = storedFollow === 'true' 244 240 } 245 241 246 - const storedLight = localStorage.getItem(STORAGE_KEYS.PREFERRED_LIGHT) 242 + const storedLight = localStorage.getItem(STORAGE_KEYS.PREFERRED_LIGHT_THEME) 247 243 if (storedLight && themes.some((t) => t.id === storedLight)) { 248 244 preferredLight.value = storedLight 249 245 } 250 246 251 - const storedDark = localStorage.getItem(STORAGE_KEYS.PREFERRED_DARK) 247 + const storedDark = localStorage.getItem(STORAGE_KEYS.PREFERRED_DARK_THEME) 252 248 if (storedDark && themes.some((t) => t.id === storedDark)) { 253 249 preferredDark.value = storedDark 254 250 } ··· 266 262 } 267 263 268 264 watch(followSystem, (val) => { 269 - localStorage.setItem(STORAGE_KEYS.FOLLOW_SYSTEM, String(val)) 265 + localStorage.setItem(STORAGE_KEYS.FOLLOW_SYSTEM_THEME, String(val)) 270 266 if (!val) { 271 267 currentMode.value = env.prefersDarkScheme ? 'dark' : 'light' 272 268 } 273 269 }) 274 - watch(preferredLight, (val) => localStorage.setItem(STORAGE_KEYS.PREFERRED_LIGHT, val)) 275 - watch(preferredDark, (val) => localStorage.setItem(STORAGE_KEYS.PREFERRED_DARK, val)) 270 + watch(preferredLight, (val) => localStorage.setItem(STORAGE_KEYS.PREFERRED_LIGHT_THEME, val)) 271 + watch(preferredDark, (val) => localStorage.setItem(STORAGE_KEYS.PREFERRED_DARK_THEME, val)) 276 272 watch(currentMode, (val) => localStorage.setItem(STORAGE_KEYS.CURRENT_MODE, val)) 277 273 watch(preferredAccent, (val) => localStorage.setItem(STORAGE_KEYS.ACCENT_COLOUR, val)) 278 274
+1
src/types/atproto.ts
··· 1 1 export type DidString = `did:${string}:${string}` 2 + export type HandleString = `${string}.${string}`
+28
src/utils/keys.ts
··· 1 + const PREFIX = 'bluebell' 2 + 3 + function defineScope<S extends string, const K extends readonly string[]>(scope: S, keys: K) { 4 + const entries = keys.map((key) => { 5 + const value = `${PREFIX}:${scope}:${key.toLowerCase().replace(/_/g, '-')}` 6 + return [key, value] as const 7 + }) 8 + 9 + return Object.fromEntries(entries) as { 10 + [P in K[number]]: `${typeof PREFIX}:${S}:${Lowercase<string>}` 11 + } 12 + } 13 + 14 + export const KEYS = { 15 + THEME: defineScope('theme', [ 16 + 'FOLLOW_SYSTEM_THEME', 17 + 'PREFERRED_LIGHT_THEME', 18 + 'PREFERRED_DARK_THEME', 19 + 'CURRENT_MODE', 20 + 'ACCENT_COLOUR', 21 + ]), 22 + 23 + STATE: defineScope('state', ['ACTIVE_FEED_URI']), 24 + 25 + AUTH: defineScope('auth', ['SESSION', 'ACTIVE_DID']), 26 + } 27 + 28 + export default KEYS