Reading Mode
Relevant source files
The following files were used as context for generating this wiki page:
Reading Mode is a feature designed to provide a simplified, clutter-free, and reader-friendly view of archived web pages. It leverages Mozilla's @mozilla/readability library to parse the original HTML of a saved page, extracting the primary article content and stripping away extraneous elements like ads, navigation bars, and sidebars. This functionality is available in two distinct parts of the project: the main web application for viewing archives and within the browser extension's page editor.
In the web application, Reading Mode is presented as a user-toggleable option, allowing a seamless switch between the full-fidelity iframe view and the simplified reader view. In the extension's editor, it's implemented as a "Format Page" feature that permanently restructures the page's HTML for readability.
Web Application Implementation
In the web front-end, Reading Mode is implemented as a React component that is conditionally rendered based on application state.
Sources: packages/web/src/pages/(layout)/page.[slug].tsx, packages/web/src/components/readability-page-content.tsx
Component Architecture
The feature is primarily handled by two components: ArchivePage and ReadabilityPageContent.
ArchivePage(page.[slug].tsx): This is the main page component for viewing a single archived page. It is responsible for fetching the page's raw HTML content and managing the view state. It uses areadModeboolean from a sharedAppContextto decide whether to render the page in Reading Mode or the default Iframe Mode.ReadabilityPageContent: This component is dedicated to rendering the Reading Mode view. It receives the raw HTML of the page as a prop, processes it using theReadabilitylibrary, and displays the extracted article content.
The following diagram illustrates the relationship between these components.
Data Flow and State Management
The process of displaying a page in Reading Mode follows a clear data and state flow, initiated by the user.
- A user navigates to an archived page (
/page/:slug). - The
ArchivePagecomponent fetches the full HTML content from the API endpoint/api/pages/content. - The
readModestate, managed byAppContext, determines the initial view. - A UI button allows the user to toggle the
readModestate by callingsetReadMode(!readMode). - When
readModeistrue, the fetchedpageHtmlis passed to theReadabilityPageContentcomponent. - When
readModeisfalse, anIframePageContentcomponent is rendered instead, displaying the original, unaltered page.
This flow is visualized in the sequence diagram below.
Rendering and Styling
The ReadabilityPageContent component is where the HTML processing occurs.
- It instantiates
Readabilitywith a newDOMParserdocument created from thepageHtmlstring prop. - It calls the
.parse()method to extract the article. - The resulting
article.content(a string of clean HTML) is then set as theinnerHTMLof adivelement using a ReactrefanduseEffect.
The styling of the rendered content is handled by Tailwind CSS's typography plugin (@tailwindcss/typography), which is applied via the prose and dark:prose-invert classes.
Sources: packages/web/src/components/readability-page-content.tsx:9-20, packages/web/tailwind.config.js:46
The Readability.parse() method returns an object with several useful properties. The key ones used are:
| Property | Description | Source File |
|---|---|---|
title | The title of the article. | packages/web/src/components/readability-page-content.tsx:10, 20 |
content | The processed HTML content of the article. | packages/web/src/components/readability-page-content.tsx:10, 16 |
excerpt | A short summary or description of the article. | packages/web/src/components/readability-page-content.tsx:10, 21 |
Browser Extension Editor Implementation
The browser extension's page editor includes a similar "format page" capability, which also uses Readability but with a different implementation approach.
Sources: packages/plugin/lib/single-file-extension-editor.js
Page Formatting Feature
Within the editor, the formatPage function provides the Reading Mode functionality. Unlike the web app's non-destructive toggle, this function modifies the document's structure directly.
- The current
documentis cloned to allow for an "undo" operation. new Readability(document, ...).parse()is called on the live document.- The entire
document.bodyis replaced with thearticle.contentreturned by Readability. - A large, self-contained block of CSS (
STYLE_FORMATTED_PAGE) is injected into the document's<head>to style the new content. - The
cancelFormatPagefunction can be called to restore the document from the clone made in step 1.
The flow of this process is as follows:
Editor Styling
The styling for the editor's reading mode is defined in the STYLE_FORMATTED_PAGE constant. This comprehensive stylesheet includes rules for:
- Layout and typography (
--content-width,--line-height). - Multiple color schemes to match user preference.
- Styling for headers, links, blockquotes, and other common article elements.
The available color schemes are:
| Class Name | Description |
|---|---|
(default) | The standard light theme. |
.sepia | A sepia-toned theme for easier reading. |
.dark | A dark theme for low-light environments. |
.hcm | A high-contrast mode for accessibility. |
Sources: packages/plugin/lib/single-file-extension-editor.js:1189-1250
User Interface
The primary user interaction for this feature in the web application is a toggle button.
| UI Text | i18n Key | Description |
|---|---|---|
| "open Read mode" | open-read-mode | Shown when the page is in Iframe Mode. |
| "open Iframe mode" | open-iframe-mode | Shown when the page is already in Reading Mode. |
This button's onClick event handler updates the readMode state in the global AppContext, triggering a re-render to switch between the IframePageContent and ReadabilityPageContent components.
Sources: packages/web/src/pages/(layout)/page.[slug].tsx:101-107, packages/web/src/assets/locales/en/translation.json:76-77
Summary
Reading Mode is a crucial feature for enhancing the consumption of archived web content. It is implemented consistently using Mozilla's Readability library across both the web application and the browser extension. The web app provides a flexible, non-destructive toggle for users viewing archives, while the extension's editor offers a more permanent formatting option. Both implementations prioritize a clean, focused reading experience through dedicated styling.