diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 73ac9db..9cc28e6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,4 +16,3 @@ jobs: - run: bun lint - run: bun test - run: bun export:bundle - - run: bun export:options diff --git a/.gitignore b/.gitignore index a4b2812..0e7d370 100644 --- a/.gitignore +++ b/.gitignore @@ -3,8 +3,6 @@ coverage node_modules *.tsbuildinfo -.eslintcache -.next # Artifacts # ############# @@ -20,5 +18,4 @@ node_modules /scripts /target /pkg -/images -/favicon.ico \ No newline at end of file +/images \ No newline at end of file diff --git a/biome.json b/biome.json index 118230c..95cd9b9 100644 --- a/biome.json +++ b/biome.json @@ -8,7 +8,7 @@ "files": { "includes": [ "src/*.ts", - "pages/*.tsx", + "src/*.tsx", "components/*.tsx", "*.{json,config.js}", "*.html" diff --git a/bun.lockb b/bun.lockb index ca8201c..08f943e 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/pages/index.tsx b/components/options-page.tsx similarity index 93% rename from pages/index.tsx rename to components/options-page.tsx index 640997e..5746963 100644 --- a/pages/index.tsx +++ b/components/options-page.tsx @@ -1,4 +1,3 @@ -// NOTE import from cjs here due to the way that nextjs handles internal es6 modules import styled from "@emotion/styled"; import ContentPasteIcon from "@mui/icons-material/ContentPaste"; import Alert, { type AlertColor } from "@mui/material/Alert"; @@ -18,13 +17,6 @@ import TextField from "@mui/material/TextField"; import Tooltip from "@mui/material/Tooltip"; import Typography from "@mui/material/Typography"; import { marked } from "marked"; -import { - EB_Garamond, - Noto_Sans, - Noto_Sans_Mono, - Noto_Serif, -} from "next/font/google"; -import Head from "next/head"; import { type ChangeEvent, type ReactElement, @@ -54,14 +46,7 @@ import { FaXmark, } from "react-icons/fa6"; import { register } from "rmapi-js"; -import ButtonSelection from "../components/button-selection"; -import CheckboxSelection from "../components/checkbox-selection"; -import FormControlLabel from "../components/form-control-label"; -import LeftRight from "../components/left-right"; -import RadioSelection from "../components/radio-selection"; -import Right from "../components/right"; -import Section from "../components/section"; -import StaticImage from "../components/static-image"; +import repubPlain from "../public/repub-plain.svg"; import { toMhtml } from "../src/mhtml"; import { defaultOptions, @@ -74,23 +59,13 @@ import { import { render } from "../src/render"; import { uploadEpub, uploadPdf } from "../src/upload"; import { sleep } from "../src/utils"; - -const ebGaramond = EB_Garamond({ - weight: "400", - subsets: ["latin"], -}); -const notoSans = Noto_Sans({ - weight: "400", - subsets: ["latin"], -}); -const notoSerif = Noto_Serif({ - weight: "400", - subsets: ["latin"], -}); -const notoMono = Noto_Sans_Mono({ - weight: "400", - subsets: ["latin"], -}); +import ButtonSelection from "./button-selection"; +import CheckboxSelection from "./checkbox-selection"; +import FormControlLabel from "./form-control-label"; +import LeftRight from "./left-right"; +import RadioSelection from "./radio-selection"; +import Right from "./right"; +import Section from "./section"; const theme = createTheme({ palette: { @@ -109,7 +84,6 @@ const unknownOpts: Partial = Object.fromEntries( async function getToken(code: string, authHost: string): Promise { // This is for testing in dev mode - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (window.chrome?.runtime?.id) { return await register(code, { authHost }); } else { @@ -252,7 +226,6 @@ function FileUpload({
- + repub , }, @@ -1056,65 +1021,55 @@ function FontNameSelector({ }} selections={[ { - // eslint-disable-next-line spellcheck/spell-checker val: "EB Garamond", icon: ( EB Garamond ), }, { - // eslint-disable-next-line spellcheck/spell-checker val: "Noto Sans", icon: ( Noto Sans ), }, { - // eslint-disable-next-line spellcheck/spell-checker val: "Noto Serif", icon: ( Noto Serif ), }, { - // eslint-disable-next-line spellcheck/spell-checker val: "Noto Mono", icon: ( Noto Mono ), }, { - // eslint-disable-next-line spellcheck/spell-checker val: "Noto Sans UI", icon: ( Noto Sans UI @@ -1291,7 +1246,6 @@ function ApiUrlsSection({ // check permissions for each non-default URL individually useEffect(() => { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!globalThis.chrome?.permissions) return; let stale = false; // deduplicate origins so we only call contains once per unique origin @@ -1470,11 +1424,6 @@ export default function OptionsPage(): ReactElement { return ( - - reMarkable ePub Options - {/* eslint-disable-next-line spellcheck/spell-checker */} - - - {/* eslint-disable-next-line spellcheck/spell-checker */} diff --git a/components/static-image.tsx b/components/static-image.tsx deleted file mode 100644 index 70bcd9e..0000000 --- a/components/static-image.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import Image, { type ImageLoaderProps, type ImageProps } from "next/image"; -import type { ReactElement } from "react"; - -function staticLoader({ src }: ImageLoaderProps): string { - return src; -} - -interface StaticImageProps extends ImageProps { - alt: string; - loader?: never; - unoptimized?: never; -} - -export default function StaticImage({ - alt, - ...props -}: StaticImageProps): ReactElement { - return {alt}; -} diff --git a/manifest.json b/manifest.json index a3ca96d..817ada0 100644 --- a/manifest.json +++ b/manifest.json @@ -19,7 +19,7 @@ "https://eu.tectonic.remarkable.com/" ], "optional_host_permissions": ["https://*/"], - "options_page": "out/index.html", + "options_page": "out/options.html", "action": { "default_title": "convert page to epub" }, diff --git a/next.config.js b/next.config.js deleted file mode 100644 index 7f77735..0000000 --- a/next.config.js +++ /dev/null @@ -1,6 +0,0 @@ -// This allows the assets to be reached by chrome -export default { - assetPrefix: process.env.NODE_ENV === "production" ? "/out" : "/", - images: { loader: "custom" }, - output: "export", -}; diff --git a/options.html b/options.html new file mode 100644 index 0000000..d2b99b3 --- /dev/null +++ b/options.html @@ -0,0 +1,23 @@ + + + + + + reMarkable ePub Options + + + + +
+ + + diff --git a/package.json b/package.json index 6b5e8f6..9da566c 100644 --- a/package.json +++ b/package.json @@ -8,24 +8,26 @@ "type": "module", "scripts": { "cli": "bun run src/cli.ts", - "dev": "next dev", + "dev": "bun ./options.html", "fmt": "biome format --write", "lint": "tsc && biome check", - "export:images": "mkdir -p images && <<< $'16\n32\n48\n128' xargs -I@ rsvg-convert -w @ -h @ public/repub.svg -o images/repub_@.png && magick images/repub_*.png favicon.ico", - "export:bundle": "bun build src/background.ts src/offscreen.ts src/popup.ts --outdir . --sourcemap=linked", - "export:options": "next build", - "export:pack": "zip -r --filesync repub.zip background.js background.js.map favicon.ico images/*.png manifest.json offscreen.html popup.html popup.js popup.js.map offscreen.js offscreen.js.map out", - "export": "bun export:images && bun export:bundle && bun export:options && bun export:pack", + "export:images": "mkdir -p images && <<< $'16\n32\n48\n128' xargs -I@ rsvg-convert -w @ -h @ public/repub.svg -o images/repub_@.png", + "export:bundle": "bun build src/background.ts src/offscreen.ts src/popup.ts --outdir . --sourcemap=linked && bun build ./options.html --outdir out --sourcemap=linked", + "export:pack": "zip -r --filesync repub.zip background.js background.js.map images/*.png manifest.json offscreen.html popup.html popup.js popup.js.map offscreen.js offscreen.js.map out", + "export": "bun export:images && bun export:bundle && bun export:pack", "pack": "bun lint && bun test --coverage && bun export && publint" }, "devDependencies": { "@biomejs/biome": "^2.4.15", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", + "@fontsource/eb-garamond": "^5.2.7", + "@fontsource/noto-sans": "^5.2.10", + "@fontsource/noto-sans-mono": "^5.2.10", + "@fontsource/noto-serif": "^5.2.9", "@mozilla/readability": "^0.6.0", "@mui/icons-material": "^9.0.1", "@mui/material": "^9.0.1", - "@next/eslint-plugin-next": "^16.2.6", "@types/base64-js": "^1.5.0", "@types/bun": "^1.3.14", "@types/chrome": "^0.1.42", @@ -39,7 +41,6 @@ "leven": "^4.1.0", "marked": "^18.0.3", "mhtml-stream": "^2.0.2", - "next": "^16.2.6", "publint": "^0.3.21", "react": "^19.2.6", "react-dom": "^19.2.6", diff --git a/pages/_app.ts b/pages/_app.ts deleted file mode 100644 index cc247fd..0000000 --- a/pages/_app.ts +++ /dev/null @@ -1,3 +0,0 @@ -import "../styles.css"; -import OptionsPage from "."; -export default OptionsPage; diff --git a/src/alter.ts b/src/alter.ts index 9ec80ad..b9a8d3c 100644 --- a/src/alter.ts +++ b/src/alter.ts @@ -26,7 +26,6 @@ export function exactMatch(assetData: Map): UrlMatcher { }; } -// eslint-disable-next-line spellcheck/spell-checker /** * looks for close matches * @@ -145,7 +144,6 @@ class Walker { const rep = `${encoded}`; let url = this.svgs.get(rep); if (url === undefined) { - // eslint-disable-next-line spellcheck/spell-checker url = `inlinesvg://${this.svgs.size}.svg`; this.svgs.set(rep, url); } @@ -217,7 +215,6 @@ ${this.options.tableCss}`; const blob = await canvas.convertToBlob({ type: "image/png" }); const bytes = await blob.arrayBuffer(); - // eslint-disable-next-line spellcheck/spell-checker const url = `tableimage://${this.pngs.length}.png`; this.pngs.push([url, new Uint8Array(bytes)]); diff --git a/src/cli.ts b/src/cli.ts index 663f903..b2e8ccc 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -78,7 +78,6 @@ global.Image = dom.window["Image"] as typeof Image; type: "string", }) .option("img-sim-thresh", { - // eslint-disable-next-line spellcheck/spell-checker describe: "how similar image urls need to be to use them", type: "number", default: defaultOptions.imageHrefSimilarityThreshold, @@ -94,9 +93,7 @@ global.Image = dom.window["Image"] as typeof Image; type: "boolean", default: defaultOptions.filterLinks, }) - // eslint-disable-next-line spellcheck/spell-checker .option("filter-iframes", { - // eslint-disable-next-line spellcheck/spell-checker describe: "filter iframes from generated results", type: "boolean", default: defaultOptions.filterIframes, diff --git a/src/globals.d.ts b/src/globals.d.ts new file mode 100644 index 0000000..9432dff --- /dev/null +++ b/src/globals.d.ts @@ -0,0 +1,6 @@ +declare module "*.css"; + +declare module "*.svg" { + const src: string; + export default src; +} diff --git a/src/image.ts b/src/image.ts index ccefd24..2d3a0ac 100644 --- a/src/image.ts +++ b/src/image.ts @@ -37,11 +37,9 @@ export async function brighten( // create canvas, write to it, and brighten it const canvas = new OffscreenCanvas(width, height); const ctx = canvas.getContext("2d")!; - /* eslint-disable spellcheck/spell-checker */ ctx.filter = ` brightness(${brightness * 100}%) grayscale(${+grayscale * 100}%)`; - /* eslint-enable spellcheck/spell-checker */ ctx.drawImage(bitmap, 0, 0, width, height); // export result diff --git a/src/lib.ts b/src/lib.ts index 3ac395f..7cc9337 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -3,7 +3,6 @@ import { epub, type ImageData, type ImageMime } from "./epub"; import type { EpubOptions } from "./options"; import { parse } from "./parse"; -// eslint-disable-next-line spellcheck/spell-checker const remarkableCss = ` p { margin-top: 1em; diff --git a/src/mhtml.ts b/src/mhtml.ts index 9c71d87..78f4601 100644 --- a/src/mhtml.ts +++ b/src/mhtml.ts @@ -1,4 +1,3 @@ -/* eslint-disable spellcheck/spell-checker */ import { fromByteArray } from "base64-js"; import { v4 as uuidv4 } from "uuid"; diff --git a/src/options-main.tsx b/src/options-main.tsx new file mode 100644 index 0000000..59a2a3a --- /dev/null +++ b/src/options-main.tsx @@ -0,0 +1,9 @@ +import "@fontsource/eb-garamond/latin-400.css"; +import "@fontsource/noto-sans/latin-400.css"; +import "@fontsource/noto-serif/latin-400.css"; +import "@fontsource/noto-sans-mono/latin-400.css"; +import { createRoot } from "react-dom/client"; +import OptionsPage from "../components/options-page"; + +const container = document.getElementById("root")!; +createRoot(container).render(); diff --git a/src/options.ts b/src/options.ts index f81bb09..f6a4d6f 100644 --- a/src/options.ts +++ b/src/options.ts @@ -64,7 +64,6 @@ export interface UploadOptions { lineHeight: number; tags: string; textAlignment: "left" | "justify"; - // eslint-disable-next-line spellcheck/spell-checker viewBackgroundFilter: "off" | "fullpage" | null; authHost: string; syncHost: string; @@ -114,7 +113,6 @@ export const defaultOptions: Options = { // Upload // // ------ // coverPageNumber: -1, - // eslint-disable-next-line spellcheck/spell-checker fontName: "EB Garamond", margins: 125, textScale: 1, @@ -134,7 +132,6 @@ export const defaultOptions: Options = { }; export async function getOptions({ - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition storage = globalThis.chrome?.storage?.local ?? mockStorage, }: { storage?: Storage; @@ -148,7 +145,6 @@ export type SetOptions = (options: Partial) => void; export async function setOptions( opts: Partial, { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition storage = globalThis.chrome?.storage?.local ?? mockStorage, }: { storage?: Storage } = {}, ): Promise { diff --git a/src/parse.ts b/src/parse.ts index 644c6f4..e9bbd3f 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -17,7 +17,6 @@ export interface ParsedWebpage { readonly assets: AsyncIterableIterator; } -// eslint-disable-next-line @typescript-eslint/require-await async function* asIterable( data: Uint8Array, ): AsyncIterableIterator { diff --git a/src/utils.spec.ts b/src/utils.spec.ts index b0998e5..0a7cf4d 100644 --- a/src/utils.spec.ts +++ b/src/utils.spec.ts @@ -20,7 +20,6 @@ async function mySleep(seconds: number): Promise { test("timeout()", async () => { expect(await timeout(mySleep(1), 10)).toBeNull(); - // eslint-disable-next-line @typescript-eslint/await-thenable,@typescript-eslint/no-confusing-void-expression await expect(timeout(mySleep(10), 1)).rejects.toThrow("timeout"); }); diff --git a/styles.css b/styles.css deleted file mode 100644 index c806edb..0000000 --- a/styles.css +++ /dev/null @@ -1,8 +0,0 @@ -html { - overflow-y: scroll; - background-color: rgb(250, 246, 240); -} - -body { - margin: 0; -} diff --git a/tsconfig.json b/tsconfig.json index 9c6d155..b137afe 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,7 @@ "incremental": true, "target": "esnext", "moduleResolution": "bundler", - "types": ["chrome", "bun", "node", "next"], + "types": ["chrome", "bun", "node"], "noEmit": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, @@ -17,20 +17,8 @@ "noUncheckedIndexedAccess": true, "noImplicitOverride": true, "noPropertyAccessFromIndexSignature": true, - "skipLibCheck": true, - "plugins": [ - { - "name": "next" - } - ] + "skipLibCheck": true }, - "include": [ - "src", - "content", - "pages", - "components", - "next-env.d.ts", - ".next/types/**/*.ts" - ], + "include": ["src", "components"], "exclude": ["node_modules"] }