diff --git a/.gitignore b/.gitignore index ba26183..1c06830 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ node_modules /dist - # local env files .env.local .env.*.local diff --git a/src/components/FontChange.vue b/src/components/FontChange.vue index ff3f97c..f5de0dc 100644 --- a/src/components/FontChange.vue +++ b/src/components/FontChange.vue @@ -18,10 +18,22 @@ const fontSizes = Array.from({ length: 7 }, (_, i) => `${9 + i * 2}pt`)
+ + + + apoena - + + + +
@@ -105,19 +147,11 @@ h1 { flex-direction: column; justify-content: space-between; - .get-started { - margin: center; - text-align: center; - display: flex; - flex-wrap: wrap; - gap: 1rem; - justify-content: center; - } - .title { text-align: center; } } + .github-form { display: flex; align-items: center; @@ -127,15 +161,31 @@ h1 { max-width: 140px; } } + footer { display: flex; gap: 1rem; align-items: center; +} - img { - vertical-align: middle; - margin-top: 0; - } +.profile-avatar { + max-width: 100%; + border-radius: 50%; + object-fit: cover; + box-shadow: none; +} + +.profile-modal-box { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.profile-section { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; + align-items: center; } .to-user-repo { diff --git a/src/hooks/useATProtoLogin.hook.ts b/src/hooks/useATProtoLogin.hook.ts index 8d23be6..2317397 100644 --- a/src/hooks/useATProtoLogin.hook.ts +++ b/src/hooks/useATProtoLogin.hook.ts @@ -14,14 +14,32 @@ import { const did = ref(null) const handle = ref(null) +const avatarUrl = ref(null) let init = true +const fetchAvatar = async (actorDid: string) => { + try { + const res = await fetch( + `https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile?actor=${encodeURIComponent(actorDid)}` + ) + if (res.ok) { + const data = await res.json() + avatarUrl.value = data.avatar ?? null + } + } catch { + avatarUrl.value = null + } +} + const initializeAuth = async () => { // Load cached session from IndexedDB first (fast, local) so the UI can render immediately const stored = await loadSession() did.value = stored?.did ?? "" handle.value = stored?.handle ?? "" + if (stored?.did) { + fetchAvatar(stored.did) + } // Then restore OAuth session in the background (may involve network) const session = await restoreSession() @@ -32,6 +50,7 @@ const initializeAuth = async () => { did.value = session.did handle.value = resolvedHandle await saveSession(session.did, resolvedHandle) + fetchAvatar(session.did) window.history.replaceState( null, @@ -61,11 +80,13 @@ export const useATProtoLogin = () => { await clearSession() did.value = "" handle.value = "" + avatarUrl.value = null } return { did, handle, + avatarUrl, isLoggedIn, isATProtoReady, signIn, diff --git a/src/modules/repo/interfaces/UserSettings.ts b/src/modules/repo/interfaces/UserSettings.ts index b3c4527..edfefe4 100644 --- a/src/modules/repo/interfaces/UserSettings.ts +++ b/src/modules/repo/interfaces/UserSettings.ts @@ -8,4 +8,6 @@ export interface UserSettings extends Model { fontSize?: string chosenFontSize?: string backlink?: boolean + chosenTitleFont?: string + chosenBodyFont?: string } diff --git a/src/modules/repo/services/repo.ts b/src/modules/repo/services/repo.ts index 6d4804a..72fbfa5 100644 --- a/src/modules/repo/services/repo.ts +++ b/src/modules/repo/services/repo.ts @@ -104,7 +104,16 @@ export const getUserSettingsContent = async ( return null } - return JSON.parse(atob(content)) as UserSettings + const raw = JSON.parse(atob(content)) as UserSettings & { + t?: string + p?: string + } + const { t, p, ...rest } = raw + return { + ...rest, + chosenTitleFont: t, + chosenBodyFont: p + } } export const queryFileContent = async ( diff --git a/src/modules/repo/store/userRepo.store.ts b/src/modules/repo/store/userRepo.store.ts index db325dd..44a7958 100644 --- a/src/modules/repo/store/userRepo.store.ts +++ b/src/modules/repo/store/userRepo.store.ts @@ -81,6 +81,14 @@ export const useUserRepoStore = defineStore("USER_REPO_STATE", { : userSettings?.fontFamily const chosenFontSize = this.userSettings?.chosenFontSize ?? userSettings?.fontSize + const chosenTitleFont = + this.userSettings?.chosenTitleFont ?? + userSettings?.chosenTitleFont ?? + chosenFontFamily + const chosenBodyFont = + this.userSettings?.chosenBodyFont ?? + userSettings?.chosenBodyFont ?? + chosenFontFamily this.userSettings = userSettings if (!this.userSettings) { @@ -91,6 +99,8 @@ export const useUserRepoStore = defineStore("USER_REPO_STATE", { chosenFontFamily ?? this.userSettings.fontFamily this.userSettings.chosenFontSize = chosenFontSize ?? this.userSettings.fontSize + this.userSettings.chosenTitleFont = chosenTitleFont + this.userSettings.chosenBodyFont = chosenBodyFont data.update({ ...this.userSettings, @@ -156,6 +166,30 @@ export const useUserRepoStore = defineStore("USER_REPO_STATE", { } this.userSettings.chosenFontSize = fontSize + const userSettingsId = `UserSetting-${this.user}-${this.repo}` + data.update({ + ...this.userSettings, + _id: userSettingsId + }) + }, + setTitleFont(font: string) { + if (!this.userSettings) { + return + } + this.userSettings.chosenTitleFont = font + + const userSettingsId = `UserSetting-${this.user}-${this.repo}` + data.update({ + ...this.userSettings, + _id: userSettingsId + }) + }, + setBodyFont(font: string) { + if (!this.userSettings) { + return + } + this.userSettings.chosenBodyFont = font + const userSettingsId = `UserSetting-${this.user}-${this.repo}` data.update({ ...this.userSettings, diff --git a/src/modules/user/hooks/useUserSettings.hook.ts b/src/modules/user/hooks/useUserSettings.hook.ts index 6d05666..64ffadb 100644 --- a/src/modules/user/hooks/useUserSettings.hook.ts +++ b/src/modules/user/hooks/useUserSettings.hook.ts @@ -12,10 +12,15 @@ export const useUserSettings = () => { watchEffect(() => { const root = document.documentElement - const fontFamily = store.userSettings?.chosenFontFamily const fontSize = store.userSettings?.chosenFontSize + const bodyFont = store.userSettings?.chosenBodyFont + const titleFont = store.userSettings?.chosenTitleFont - downloadFont(fontFamily || DEFAULT_FONT_POLICY) + downloadFont(bodyFont || DEFAULT_FONT_POLICY, "--font-family") + downloadFont( + titleFont || bodyFont || DEFAULT_FONT_POLICY, + "--title-font-family" + ) root.style.setProperty("--font-size", fontSize || DEFAULT_FONT_SIZE) }) } diff --git a/src/styles/app.css b/src/styles/app.css index 8c4dab4..7cd0612 100644 --- a/src/styles/app.css +++ b/src/styles/app.css @@ -6,6 +6,7 @@ :root { --primary-color: #ffa4c0; --font-family: "Libertinus Serif", serif; + --title-font-family: "Libertinus Serif", serif; --font-size: 13pt; --font-color: #4a4a4a; --link: #445fb9; diff --git a/src/utils/downloadFont.ts b/src/utils/downloadFont.ts index c6f4425..dcc789d 100644 --- a/src/utils/downloadFont.ts +++ b/src/utils/downloadFont.ts @@ -6,7 +6,10 @@ const assembleFontLink = (font: string) => { .replaceAll(" ", "+")}` } -export const downloadFont = async (font: string): Promise => { +export const downloadFont = async ( + font: string, + cssVar = "--font-family" +): Promise => { const href = assembleFontLink(font) // check if the href already exists @@ -23,7 +26,7 @@ export const downloadFont = async (font: string): Promise => { try { await new FontFaceObserver(font).load() - document.documentElement.style.setProperty("--font-family", font) + document.documentElement.style.setProperty(cssVar, font) } catch (error) { console.warn("error when loading font") } diff --git a/tailwind.config.js b/tailwind.config.js index 7c76ae2..bf4472f 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -11,7 +11,8 @@ const defaultTitleStyles = Array.from( ...acc, [heading]: { "margin-top": "0", - "margin-bottom": "0.5em" + "margin-bottom": "0.5em", + "font-family": "var(--title-font-family)" } }), {}