Zakhar Timoshenko 142ec97959 feat: add Open Graph image generation and SEO metadata
- Introduced `PageSeo` component for managing page metadata for social sharing.
- Created Open Graph image templates using SVG and static fonts for better visual representation.
- Implemented service alert management with functions to check active alerts and format route numbers.
- Added utility functions for generating and watching alert validity.
- Developed a script to generate Open Graph images dynamically based on page content.
- Included tests for service alert functionalities to ensure correctness and reliability.
2026-10-05 13:02:06 +03:00
2024-03-20 00:12:01 +03:00
2026-10-02 20:31:49 +03:00
2026-10-02 20:31:49 +03:00
2026-10-02 20:31:49 +03:00
2026-10-02 20:31:49 +03:00
2026-10-02 20:31:49 +03:00
2026-10-02 20:31:49 +03:00
2024-03-20 00:12:01 +03:00
2026-10-02 20:31:49 +03:00
2024-03-20 00:12:01 +03:00
2026-10-02 20:31:49 +03:00
2026-10-02 20:31:49 +03:00
2026-10-02 20:31:49 +03:00

RideBus landing

Development

Use Node.js 24 or newer. Install dependencies with yarn install --immutable, then run yarn dev.

Next departures

Copy .env.example to .env.local and configure RIDEBUS_API_KEY with an authorized RideBus API key. The default API address is https://api.ridebus.by/; override it with RIDEBUS_API_BASE_URL if needed. Restart the server after changing environment variables.

The server route /api/departures reads the city catalogue, stops for the selected city, and ETA for the selected stop. Only normalized public fields reach the browser. The API key stays on the server. Cities are cached for one hour, stops for five minutes, and departures for 30 seconds; concurrent requests share the same upstream request.

Departure times use scheduledTime. Historical delay is removed from the ETA countdown, so the board consistently displays timetable information. The board refreshes every 30 seconds while the tab is visible and shows an unavailable state when the API connection has not been configured. It never substitutes sample data.

The city and stop menus use the landing’s custom menu style. Long catalogues have search and a bounded scroll area. Stops with the same name share one menu entry; direction chips retain their separate stop IDs and use the API’s stop description. Countdown labels show hours and minutes. Menus support keyboard navigation and Escape, and interface animations respect reduced-motion preferences. The homepage FAQ explains the timetable and links to the contribution page.

On touchscreens, opening a menu does not automatically focus search or bring up the keyboard. Tapping search keeps the menu open as the visible viewport changes. Keyboard navigation scrolls only the options, and search text is at least 16px to avoid input zoom on iOS.

For Docker Compose, supply RIDEBUS_API_KEY and optionally RIDEBUS_API_BASE_URL through the shell environment or a local .env file. Environment files are excluded from the image build context. Do not commit credentials.

Server deployment

Run the landing as a separate Compose project alongside the API and admin panel:

cp .env.example .env
# Set RIDEBUS_API_KEY in .env without committing the file.
chmod 600 .env
docker compose config --quiet
docker compose up -d --build --wait
docker compose ps

The service publishes port 3000 by default. Point the existing reverse proxy for ridebus.by at the server or LXC container's IP and port 3000. TLS is handled by that proxy. Compose does not require Traefik or an existing Docker network.

Set RIDEBUS_PORT in .env to use a different port. Set RIDEBUS_BIND_ADDRESS to restrict the listening address; its default is 0.0.0.0 so a reverse proxy in a separate LXC container can reach the site.

The image runs the Next.js standalone server as the node user, includes an HTTP health check, and receives the API key only at runtime. Updates use docker compose up -d --build --wait from the landing's directory. This only updates the ridebus-landing project.

Open Graph images

yarn dev and yarn build generate eight 1200 × 630 PNG images before starting Next.js: one for each of the home, contribution, privacy and terms pages in English and Russian. To regenerate only the images, run yarn generate:og (or npm run generate:og).

Output is written to public/images/og/{page}-{locale}.png and is excluded from Git. The Docker build generates and copies it into the standalone image. Each page supplies its own canonical URL, localized Open Graph tags and Twitter large-image card; the image URLs use the production origin https://ridebus.by.

Edit the page copy and routes in lib/social.mjs, and the layout in lib/og-template.mjs. The template reuses the landing's bus logo, stars, rounded cards, blue and purple palette, and Manrope/Caveat typography. Local fonts include Latin and Cyrillic characters, so image generation needs no external requests or browser. Font sources and licenses are in assets/fonts/og/.

In-page anchors such as /#download use the homepage preview: crawlers do not request the fragment, so separate previews apply to actual page URLs.

Checks

yarn test
yarn typecheck
yarn lint
yarn build
Description
No description provided
Readme 8.1 MiB
Languages
TypeScript 62.7%
SCSS 21.5%
JavaScript 12.8%
GLSL 1.7%
CSS 1%
Other 0.3%