Skip to main content

A Memo on Creating a News Links Page in Docusaurus

If this site helped you, please support us with a star! 🌟
Star on GitHub

This article serves as a memorandum on the implementation of the "News Page," which lists domestic and international news sites on this website.

info

Key topics covered in this article:

  • Docusaurus i18n features (<Translate>, translate API)
  • React component design, including dynamic favicon fetching
  • Scoped styling with CSS Modules
  • Responsive design with CSS Grid Layout
  • Accessible UI using the HTML <details> tag

Page Purpose and Feature Overview​

The purpose of this page is to create an environment for quickly accessing reliable news sources as a personal information-gathering hub.

  • Categorization: News sites are categorized into sections like "General & Economy" and "Technology," with each category being collapsible using the HTML <details> tag.
  • Multilingual Support (i18n): Leveraging Docusaurus's internationalization features, all text on the page can be switched between Japanese and English.
  • Direct Links to Sections: Anchor links are provided for each category heading, allowing direct URL sharing for specific sections.
  • Responsive Card Layout: A CSS Grid layout is used to optimize the display for various screen sizes.

Implementation Details​

This feature was implemented as a React component at src/pages/news.tsx, with styling handled by CSS Modules (news.module.css).

Multilingual Support (i18n)​

The <Translate> component and translate API provided by Docusaurus were used to separate markup from translation content.

  • Translation within JSX: The <Translate> component fetches the corresponding translated text from code.json using the id as a key.

    src/pages/news.tsx
    import Translate from '@docusaurus/Translate';

    <h1>
    <Translate id="news.page.heading">ニγƒ₯γƒΌγ‚Ή</Translate>
    </h1>
  • Translation outside of JSX: The translate API is used for translating strings outside of JSX tags, such as in component props.

    src/pages/news.tsx
    import { translate } from '@docusaurus/Translate';

    <Layout
    title={translate({
    id: 'news.page.title',
    message: 'ニγƒ₯ース一覧', // Default text
    })}
    />
Centralized Management of Translation Data

This system centralizes all translation data in i18n/{locale}/code.json, streamlining text management and translation work.

Component Design​

Page elements were componentized by function to improve reusability and readability.

  • NewsSiteCard Component: A reusable card component that not only accepts site information as props but also encapsulates the logic for dynamically fetching and displaying the site's favicon.

    src/components/NewsSiteCard/index.tsx (excerpt)
    export default function NewsSiteCard({ href, title, description }: Props) {
    const domain = new URL(href).hostname;
    // ...favicon fetching logic...
    }
  • SectionHeading Component: A custom component that allows for dynamically specifying heading levels like h2 or h3 via the as prop.

Styling (CSS Modules & Grid Layout)​

CSS Modules were adopted to manage styles on a per-component basis, preventing global CSS pollution.

  • Responsive Grid Layout: CSS Grid was used for the card list layout.
    src/pages/news.module.css
    .cardGrid {
    display: grid;
    /* Set min column width to 300px and auto-adjust column count */
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 1rem;
    }
    This single line achieves a flexible responsive design without complex media queries.

UI/UX Improvements​

A rich and accessible UI was pursued by combining standard HTML features with React's state management.

  1. Accordion UI with <details>: The category collapse/expand functionality is implemented with the standard HTML <details> and <summary> tags. This achieves an accessible, keyboard-navigable UI without any JavaScript.

  2. Dynamic Favicons and Fallback Handling: To enhance the visual identity of each site, favicons are displayed dynamically. A robust fallback mechanism was implemented to handle API instability or cases where a favicon does not exist.

    • Multiple API Sources: A list of favicon APIs (Google and DuckDuckGo) is used in order of priority.
      const faviconSources = [
      `https://www.google.com/s2/favicons?domain=${domain}&sz=128`,
      `https://icons.duckduckgo.com/ip3/${domain}.ico`,
      ];
    • Error Handling: The onError event of the img tag is used to detect image loading failures. If an error occurs, an index managed by useState is updated to try the next API source.
      const [sourceIndex, setSourceIndex] = useState(0);

      const handleError = () => {
      // If there's a next source, update the index
      if (sourceIndex < faviconSources.length - 1) {
      setSourceIndex(sourceIndex + 1);
      } else {
      // If all fail, switch to the default icon
      setUseDefaultIcon(true);
      }
      };
    • Default Icon as a Last Resort: A default icon, defined as an inline SVG within the component, is displayed if all API fetches fail, ensuring UI integrity.
  3. Performance Considerations: The loading="lazy" attribute was added to favicon images to leverage the browser's native lazy loading. This defers the loading of off-screen images, improving initial page load speed.

Further Reading
If this site helped you, please support us with a star! 🌟
Star on GitHub