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`)
+
+
+
+
@@ -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)"
}
}),
{}