A Memo on Creating a News Links Page in Docusaurus
This article serves as a memorandum on the implementation of the "News Page," which lists domestic and international news sites on this website.
Key topics covered in this article:
- Docusaurus i18n features (
<Translate>,translateAPI) - 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 fromcode.jsonusing theidas a key.src/pages/news.tsximport Translate from '@docusaurus/Translate';
<h1>
<Translate id="news.page.heading">γγ₯γΌγΉ</Translate>
</h1> -
Translation outside of JSX: The
translateAPI is used for translating strings outside of JSX tags, such as in component props.src/pages/news.tsximport { translate } from '@docusaurus/Translate';
<Layout
title={translate({
id: 'news.page.title',
message: 'γγ₯γΌγΉδΈθ¦§', // Default text
})}
/>
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.
-
NewsSiteCardComponent: 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...
} -
SectionHeadingComponent: A custom component that allows for dynamically specifying heading levels likeh2orh3via theasprop.
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.
This single line achieves a flexible responsive design without complex media queries.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;
}
UI/UX Improvementsβ
A rich and accessible UI was pursued by combining standard HTML features with React's state management.
-
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. -
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
onErrorevent of theimgtag is used to detect image loading failures. If an error occurs, an index managed byuseStateis 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.
- Multiple API Sources: A list of favicon APIs (Google and DuckDuckGo) is used in order of priority.
-
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.
- TypeScript Docs
- Google S2 Favicon API (Note: Although not officially documented, it is widely used.)
- MDN:
<img>loading attribute - MDN:
<details>element - MDN: CSS Grid Layout