inject sakura css into cached html

This commit is contained in:
2025-05-13 11:55:50 +01:00
parent 83f0625843
commit 7f8b38e218
7 changed files with 141 additions and 72 deletions

View File

@@ -16,8 +16,8 @@ body {
line-height: 1.618;
max-width: 38em;
margin: auto;
color: #c9c9c9;
background-color: #222222;
color: #e7e5e4;
background-color: #1c1917;
padding: 13px;
}

View File

@@ -1,14 +1,15 @@
/* Sakura.css v1.5.0
* ================
* Minimal css theme.
* Colors have been slightly modified to match the rest of the website.
* Project: https://github.com/oxalorg/sakura/
*/
/* Body */
html {
font-size: 62.5%;
font-family:
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
Arial, "Noto Sans", sans-serif;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
"Helvetica Neue", Arial, "Noto Sans", sans-serif;
}
body {
@@ -16,8 +17,8 @@ body {
line-height: 1.618;
max-width: 38em;
margin: auto;
color: #4a4a4a;
background-color: #f9f9f9;
color: #292524;
background-color: #f5f5f4;
padding: 13px;
}
@@ -38,9 +39,8 @@ h4,
h5,
h6 {
line-height: 1.1;
font-family:
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
Arial, "Noto Sans", sans-serif;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
"Helvetica Neue", Arial, "Noto Sans", sans-serif;
font-weight: 700;
margin-top: 3rem;
margin-bottom: 1.5rem;

View File

@@ -12,8 +12,6 @@ import { FormField } from "~/components/form-field"
import { LoadingSpinner } from "~/components/loading-spinner"
import { useMnemonics } from "~/hooks/use-mnemonics"
import { useLogOut } from "~/auth"
import sakuraCssSrc from "~/reader-styles/sakura.css?url"
import sakuraDarkCssSrc from "~/reader-styles/sakura-dark.css?url"
const LAYOUT_MODE = {
popup: "popup",
@@ -153,8 +151,8 @@ function Main({ children }: React.PropsWithChildren) {
return (
<main
className={clsx(
"grid flex justify-center relative w-full",
isPreviewOpened && layoutMode === LAYOUT_MODE.sideBySide ? "grid-cols-3" : "grid-cols-1",
"relative w-full",
isPreviewOpened && layoutMode === LAYOUT_MODE.sideBySide ? "grid grid-cols-3" : "flex justify-center",
)}
>
{children}
@@ -166,7 +164,12 @@ function BookmarkListPane() {
const isBookmarkPreviewOpened = useBookmarkPageStore((state) => state.isBookmarkPreviewOpened)
return (
<div className={clsx("flex flex-col py-16", { "md:flex-row lg:py-32 justify-center ": !isBookmarkPreviewOpened })}>
<div
className={clsx(
"flex flex-col py-16",
isBookmarkPreviewOpened ? "w-full" : "container max-w-3xl md:flex-row lg:py-32",
)}
>
<header className="mb-4 md:mb-0 md:mr-16 text-start">
<h1 className={clsx("font-bold text-start", { "mb-4": isBookmarkPreviewOpened })}>
<span
@@ -179,7 +182,9 @@ function BookmarkListPane() {
YOUR BOOKMARKS
</h1>
</header>
<BookmarkListSection />
<div className="flex-1">
<BookmarkListSection />
</div>
</div>
)
}
@@ -393,7 +398,7 @@ function BookmarkListSection() {
switch (status) {
case "pending":
return (
<p className="container max-w-2xl">
<p>
Loading&nbsp;
<LoadingSpinner />
</p>
@@ -468,7 +473,7 @@ function BookmarkList({ bookmarks }: { bookmarks: LinkBookmark[] }) {
}
return (
<div className="flex flex-col container max-w-2xl -mt-2">
<div className="flex flex-col -mt-2">
{bookmarks.length === 0 ? (
<p className="mt-2">You have not saved any bookmark!</p>
) : (
@@ -495,15 +500,15 @@ function BookmarkPreview() {
},
)}
>
<BookmarkPreviewFrame />
<BookmarkPreviewContent />
</div>
)
}
function BookmarkPreviewFrame() {
function BookmarkPreviewContent() {
const selectedBookmarkId = useBookmarkPageStore((state) => state.selectedBookmarkId)
const actionBarHeight = useBookmarkPageStore((state) => state.actionBarHeight)
const { data, status } = useAuthenticatedQuery(["bookmarks", selectedBookmarkId], () =>
const { data, status } = useAuthenticatedQuery(["bookmarks", `${selectedBookmarkId}.html`], () =>
fetchApi(`/bookmark/${selectedBookmarkId}`, {
headers: {
Accept: "text/html",
@@ -511,23 +516,6 @@ function BookmarkPreviewFrame() {
}).then((res) => res.text()),
)
function injectCss(event: React.SyntheticEvent<HTMLIFrameElement, Element>) {
const lightCssLink = document.createElement("link")
lightCssLink.rel = "stylesheet"
lightCssLink.href = sakuraCssSrc
lightCssLink.media = "screen"
const darkCssLink = document.createElement("link")
darkCssLink.rel = "stylesheet"
darkCssLink.href = sakuraDarkCssSrc
darkCssLink.media = "screen and (prefers-color-scheme: dark)"
if (event.currentTarget.contentDocument) {
event.currentTarget.contentDocument.head.appendChild(lightCssLink)
event.currentTarget.contentDocument.head.appendChild(darkCssLink)
}
}
switch (status) {
case "pending":
return (
@@ -537,7 +525,13 @@ function BookmarkPreviewFrame() {
)
case "success":
return (
<iframe className="w-full h-full" style={{ paddingBottom: actionBarHeight }} srcDoc={data} onLoad={injectCss} />
<iframe
key="preview-iframe"
title="asd"
className={clsx("w-full h-full")}
style={{ paddingBottom: actionBarHeight }}
srcDoc={data}
/>
)
default:

View File

@@ -0,0 +1,36 @@
import { useEffect, useState } from "react"
enum ColorScheme {
Light = "Light",
Dark = "Dark",
}
const initialColorScheme = window.matchMedia?.("(prefers-color-scheme: dark)").matches
? ColorScheme.Dark
: ColorScheme.Light
function useColorScheme() {
const [colorScheme, setColorScheme] = useState(initialColorScheme)
useEffect(() => {
if (!window.matchMedia) {
return
}
function onMediaChange(this: MediaQueryList) {
setColorScheme(this.matches ? ColorScheme.Dark : ColorScheme.Light)
}
const l = window.matchMedia("(prefers-color-scheme: dark)")
onMediaChange.call(l)
l.addEventListener("change", onMediaChange)
return () => {
l.removeEventListener("change", onMediaChange)
}
}, [])
return colorScheme
}
export { ColorScheme, useColorScheme }

View File

@@ -1,4 +1,5 @@
@import "tailwindcss";
@plugin "@tailwindcss/typography";
:root {
font-family: monospace;