diff --git a/client/index.html b/client/index.html
index f418ffb15..91fe2e89f 100644
--- a/client/index.html
+++ b/client/index.html
@@ -6,16 +6,7 @@
Projectx
-
+
diff --git a/client/package.json b/client/package.json
index 67a0302b9..107e0ad1d 100644
--- a/client/package.json
+++ b/client/package.json
@@ -31,6 +31,7 @@
"@vueuse/core": "^14.2.1",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
+ "dompurify": "^3.3.3",
"echarts": "^6.0.0",
"howler": "^2.2.4",
"lucide-vue-next": "^1.0.0",
@@ -49,6 +50,7 @@
},
"devDependencies": {
"@tsconfig/node24": "^24.0.4",
+ "@types/dompurify": "^3.2.0",
"@types/jsdom": "^28.0.1",
"@types/node": "^25.6.0",
"@vitejs/plugin-vue": "^6.0.5",
diff --git a/client/public/theme-init.js b/client/public/theme-init.js
new file mode 100644
index 000000000..d25e609b8
--- /dev/null
+++ b/client/public/theme-init.js
@@ -0,0 +1,8 @@
+;(function () {
+ var theme = localStorage.getItem('theme') || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
+ var accent = localStorage.getItem('accent') || 'neutral'
+ var radius = localStorage.getItem('radius') || 'default'
+ if (theme === 'dark') document.documentElement.classList.add('dark')
+ if (accent !== 'neutral') document.documentElement.classList.add('accent-' + accent)
+ if (radius !== 'default') document.documentElement.classList.add('radius-' + radius)
+})()
diff --git a/client/src/features/book/components/BookQuickView.vue b/client/src/features/book/components/BookQuickView.vue
index bd3760712..9139b03e8 100644
--- a/client/src/features/book/components/BookQuickView.vue
+++ b/client/src/features/book/components/BookQuickView.vue
@@ -15,6 +15,7 @@ import { getFormatColor } from '../lib/format-colors'
import { FORMAT_TO_GROUP } from '@projectx/types'
import { COVER_ASPECT_RATIO_KEY, DEFAULT_COVER_ASPECT_RATIO } from '../lib/cover-aspect-ratio'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
+import { useSafeHtml } from '@/features/book/composables/useSafeHtml'
const props = defineProps<{ bookId: number | null; open: boolean }>()
const { hasPermission } = usePermissions()
@@ -131,6 +132,7 @@ const providerLinks = computed(() => {
const descriptionExpanded = ref(false)
const genresExpanded = ref(false)
const coverLightboxOpen = ref(false)
+const safeDescription = useSafeHtml(() => detail.value?.description)
const coverAspectRatio = inject(COVER_ASPECT_RATIO_KEY, ref(DEFAULT_COVER_ASPECT_RATIO))
@@ -373,7 +375,7 @@ function toggleGenres() {