From f4da592bfbc8a66cf16e69cb46c2be8941192913 Mon Sep 17 00:00:00 2001 From: Justin Burris <713795+justinbburris@users.noreply.github.com> Date: Thu, 24 Apr 2025 02:24:01 -0400 Subject: [PATCH] Implement documentation site with dark/light theme support (#9736) --- .clang-format | 2 + .github/workflows/code_style_check.yml | 5 + README.md | 8 +- docs/.gitignore | 8 + docs/DEVELOPMENT.md | 10 +- docs/GRAPHICAL_ASSETS.md | 16 +- docs/Gemfile.dev | 3 + docs/INSTALL.md | 128 +-- docs/PRIVACY_POLICY.md | 4 +- docs/README.md | 23 +- docs/README_PSV.md | 4 +- docs/README_android.md | 4 +- docs/README_cmake.md | 2 +- docs/README_emscripten.md | 12 +- docs/README_switch.md | 8 +- docs/TRANSLATION.md | 26 +- docs/WEBSITE_LOCAL_DEV.md | 175 ++++ docs/_config.yml | 7 +- docs/_layouts/default.html | 84 ++ docs/_sass/_dark-theme.scss | 19 + docs/_sass/_layout.scss | 644 ++++++++++++ docs/_sass/_light-theme.scss | 19 + docs/assets/css/style.scss | 6 + docs/assets/js/accessibility.js | 178 ++++ docs/assets/js/code-copy.js | 108 ++ docs/assets/js/heading-copy.js | 150 +++ docs/assets/js/templates.js | 49 + docs/assets/js/theme-toggle.js | 121 +++ docs/images/favicon.ico | Bin 0 -> 4286 bytes docs/package-lock.json | 1266 +++++++++++++++++++++++ docs/package.json | 12 + script/macos/Brewfile.dev_tools | 20 + script/tools/check_code_format.sh | 4 +- script/tools/check_copyright_headers.sh | 4 +- 34 files changed, 2973 insertions(+), 156 deletions(-) create mode 100644 docs/.gitignore create mode 100644 docs/Gemfile.dev create mode 100644 docs/WEBSITE_LOCAL_DEV.md create mode 100644 docs/_layouts/default.html create mode 100644 docs/_sass/_dark-theme.scss create mode 100644 docs/_sass/_layout.scss create mode 100644 docs/_sass/_light-theme.scss create mode 100644 docs/assets/css/style.scss create mode 100644 docs/assets/js/accessibility.js create mode 100644 docs/assets/js/code-copy.js create mode 100644 docs/assets/js/heading-copy.js create mode 100644 docs/assets/js/templates.js create mode 100644 docs/assets/js/theme-toggle.js create mode 100644 docs/images/favicon.ico create mode 100644 docs/package-lock.json create mode 100644 docs/package.json create mode 100644 script/macos/Brewfile.dev_tools diff --git a/.clang-format b/.clang-format index 28447e401..70f111241 100644 --- a/.clang-format +++ b/.clang-format @@ -91,3 +91,5 @@ UseTab: Never Language: Cpp --- Language: Java +--- +Language: JavaScript diff --git a/.github/workflows/code_style_check.yml b/.github/workflows/code_style_check.yml index 0a4866e8a..3dae60406 100644 --- a/.github/workflows/code_style_check.yml +++ b/.github/workflows/code_style_check.yml @@ -34,3 +34,8 @@ jobs: (echo "Please update the date in the LegalCopyright entry!" && false) - name: Check format of markdown files uses: DavidAnson/markdownlint-cli2-action@v19 + - name: Check format of HTML and CSS files + uses: creyD/prettier_action@v4.3 + with: + dry: true + prettier_options: --write docs/**/*.{html,scss} diff --git a/README.md b/README.md index 68f8279c7..aca25756f 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ You can find a complete list of all of our changes and enhancements in [**its ow Screenshot of the castle screen

-## Download and install +## Download and Install Please follow the [**installation guide**](docs/INSTALL.md) to download and install fheroes2. @@ -40,7 +40,11 @@ Initially, the project was developed on [**sourceforge**](https://sourceforge.ne This repository is a place for everyone. If you want to contribute, please read more [**here**](https://github.com/ihhub/fheroes2/wiki/F.A.Q.#q-how-can-i-contribute-to-the-project). -To build the project from source, please follow [**this guide**](docs/DEVELOPMENT.md). +To build the project from source, please follow +[**this guide**](docs/DEVELOPMENT.md). + +To build the website from source, please follow +[**this guide**](docs/WEBSITE_LOCAL_DEV.md). [![Build Status](https://github.com/ihhub/fheroes2/actions/workflows/push.yml/badge.svg)](https://github.com/ihhub/fheroes2/actions) [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=ihhub_fheroes2&metric=bugs)](https://sonarcloud.io/dashboard?id=ihhub_fheroes2) diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 000000000..9ada8715b --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,8 @@ +_site + +node_modules + +# Gemfile +Gemfile +Gemfile.lock +Gemfile.dev.lock diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 9d483447b..2b80d0e2e 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -1,6 +1,6 @@ -# [**fheroes2**](README.md) build and contribution guide +# [fheroes2](README.md) build and contribution guide -## Build +## Building the fheroes2 Project Please follow the instructions below to be able to build the project from source: @@ -51,6 +51,12 @@ If you would like to run this project in a web browser please follow the instruc If you would like to build the project using CMake please follow the instructions on [**this page**](README_cmake.md). +## Building the front end website + +We host the website on Github pages, which is a highly customized version of the +Jekyll static site engine. The instructions for developing the website can be +found in the [**website local dev**](WEBSITE_LOCAL_DEV.md) guide. + ## Contribution We welcome and appreciate any help, even if it is a tiny text or code change. Please read our diff --git a/docs/GRAPHICAL_ASSETS.md b/docs/GRAPHICAL_ASSETS.md index dc33e8148..703c1102c 100644 --- a/docs/GRAPHICAL_ASSETS.md +++ b/docs/GRAPHICAL_ASSETS.md @@ -1,4 +1,4 @@ -# [**fheroes2**](README.md) graphical artist guide +# [fheroes2](README.md) Graphical Artist Guide The original game has its graphical assets stored in the `HEROES2.agg` file and potentially the `HEROES2X.agg` file if the expansion pack The Price of Loyalty is present. These two AGG files are located in the `DATA` folder of the original Heroes 2 installation. @@ -10,15 +10,15 @@ New assets that the fheroes2 project adds to the game are included in the `files This guide is designed for Linux, MacOS and Windows users. The source files to these tools are available in the project's repository. -## Where to get the tools +## Where to Get the Tools -You can download the precompiled tools for your operating system (OS) of choice here: -[Windows 32-bit](https://github.com/ihhub/fheroes2/releases/download/fheroes2-windows-x86-SDL2/fheroes2_tools_windows_x86_SDL2.zip) +You can download the precompiled tools for your operating system (OS) of choice here: +[Windows 32-bit](https://github.com/ihhub/fheroes2/releases/download/fheroes2-windows-x86-SDL2/fheroes2_tools_windows_x86_SDL2.zip) [Windows 64-bit](https://github.com/ihhub/fheroes2/releases/download/fheroes2-windows-x64-SDL2/fheroes2_tools_windows_x64_SDL2.zip) [MacOS](https://github.com/ihhub/fheroes2/releases/download/fheroes2-osx-sdl2_dev/fheroes2_tools_macos_x86-64_SDL2.zip) -[Linux Ubuntu 64-bit](https://github.com/ihhub/fheroes2/releases/download/fheroes2-linux-sdl2_dev/fheroes2_tools_ubuntu_x86-64_SDL2.zip) +[Linux Ubuntu 64-bit](https://github.com/ihhub/fheroes2/releases/download/fheroes2-linux-sdl2_dev/fheroes2_tools_ubuntu_x86-64_SDL2.zip) [Linux Ubuntu ARM 64-bit](https://github.com/ihhub/fheroes2/releases/download/fheroes2-linux-arm-sdl2_dev/fheroes2_tools_ubuntu_arm64_SDL2.zip) Here is a list and short description of the various graphical artist tools: @@ -42,7 +42,7 @@ the top-left corner on a tile. Use these colors only if the animation is a requi * 231, 232, 233, 234, 235 * 238, 239, 240, 241 -## How to use the tools to extract the images +## How to Use the Tools to Extract the Images Place the `HEROES2.agg` and optionally the `HEROES2X.agg` files in the same folder as you extracted the tools to. Then run the script called `extract_agg`. This will create two folders: `agg` and `icn`. Both of them have a subdirectory named `HEROES2`, @@ -55,7 +55,7 @@ Meanwhile, the folder named `icn` contains the PNG-converted graphical assets. T ICN they were stored in, e.g. the folder `apanel` came from the ICN `apanel.icn`. The `icn` folder is in other words the most relevant one for graphical artists. -## Where is help needed +## Where is Help Needed We have labelled and tracked some issues that need help from graphical artists. Issues that require changes of the original art can be found [here](https://github.com/ihhub/fheroes2/issues?q=is%3Aopen+is%3Aissue+label%3A"original+assets"). @@ -64,7 +64,7 @@ New art tasks can be found [here](https://github.com/ihhub/fheroes2/issues?q=is% NOTE! Before starting to work on an issue make sure to check if someone isn't already assigned to it by looking at the relevant place within the issue. Also notify the fheroes2 team that you wish to work on the issue. This is to avoid duplicate work. -## The work process +## The Work Process 1. Choose the item you are going to work on and notify the fheroes2 team to avoid duplicate work. 2. Present a prototype / complete enough work in your opinion of your work. diff --git a/docs/Gemfile.dev b/docs/Gemfile.dev new file mode 100644 index 000000000..0c8671cde --- /dev/null +++ b/docs/Gemfile.dev @@ -0,0 +1,3 @@ +source "https://rubygems.org" + +gem "github-pages", group: :jekyll_plugins diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 2b45169ff..3e3208b53 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -1,4 +1,4 @@ -# [**fheroes2**](README.md) installation guide +# [fheroes2](README.md) Installation Guide ## Requirements @@ -33,58 +33,40 @@ Precompiled binaries of the release version are currently available for the foll Alternatively, you can download the precompiled binaries of the latest commit (snapshot) [**here**](#snapshots-latest-builds). - - ## Windows - - -### Windows installer +### Windows Installer * Download one of the following Windows installer packages: - * [**Windows x64 (64-bit)**](https://github.com/ihhub/fheroes2/releases/latest/download/fheroes2_windows_x64_SDL2_installer.exe) - * [**Windows x86 (32-bit)**](https://github.com/ihhub/fheroes2/releases/latest/download/fheroes2_windows_x86_SDL2_installer.exe) - * After downloading the installer, launch it and follow the instructions. - * During the installation process, you will be prompted to extract game resources from the original game (select this option if you already have a legally purchased copy of the original game installed), or download the demo version of the original game and extract game resources from it (you can also do this later by clicking the appropriate shortcut in the program's group in the Windows Start menu). - * If you purchased a copy of the original game only after installing fheroes2, you can run the `Extract game resources from the original distribution of HoMM2` shortcut in the program's group in the Windows Start menu. This script will try to perform an automatic search for an existing installation of the original game and extract all the necessary resource files. If it can't find an existing installation, you will be prompted to enter the location of the original game manually. - * As an alternative to the previous step, you can manually copy the subdirectories `ANIM`, `DATA`, `MAPS` and `MUSIC` (some of them may be missing depending on the version of the original game) from the original game directory to the fheroes2 installation directory. - - -### Windows ZIP archive +### Windows ZIP Archive * Download one of the following Windows ZIP archives: - * [**Windows x64 (64-bit)**](https://github.com/ihhub/fheroes2/releases/latest/download/fheroes2_windows_x64_SDL2.zip) - * [**Windows x86 (32-bit)**](https://github.com/ihhub/fheroes2/releases/latest/download/fheroes2_windows_x86_SDL2.zip) - * After downloading the ZIP archive, extract it to a suitable directory of your choice. - * If you have a legally purchased copy of the original game, run the `extract_homm2_resources.bat` script supplied in the ZIP archive. This script will try to perform an automatic search for an existing installation of the original game and extract all the necessary resource files. If it can't find an existing installation, you will be prompted to enter the location of the original game manually. - * As an alternative to the previous step, you can manually copy the subdirectories `ANIM`, `DATA`, `MAPS` and `MUSIC` (some of them may be missing depending on the version of the original game) from the original game directory to the fheroes2 installation directory. - * If you don't have a legally purchased copy of the original game, you can download and install the demo version of the original game by running the `download_demo_version.bat` script supplied in the ZIP archive. -#### Troubleshooting missing Microsoft Visual C++ DLLs +#### Troubleshooting Missing Microsoft Visual C++ DLLs If you see complaints about missing DLLs when running fheroes2, then you may need to install the Microsoft Visual C++ redistributable package. @@ -95,12 +77,8 @@ You can download it using the following URLs: | For 64-bit x64 fheroes2 builds | [**https://aka.ms/vs/17/release/vc_redist.x64.exe**](https://aka.ms/vs/17/release/vc_redist.x64.exe) | | for 32-bit x86 fheroes2 builds | [**https://aka.ms/vs/17/release/vc_redist.x86.exe**](https://aka.ms/vs/17/release/vc_redist.x86.exe) | - - ## macOS - - ### Homebrew on macOS If you are using [**Homebrew**](https://brew.sh/), you can install the game by running the following command: @@ -111,8 +89,6 @@ brew install fheroes2 Follow the [**instructions below**](#gathering-game-resources) to gather resources necessary for fheroes2 to function as expected. - - ### MacPorts If you are using [**MacPorts**](https://www.macports.org/), you can install the game by running the following command: @@ -125,23 +101,18 @@ Then follow the instructions on the screen. Follow the [**instructions below**](#gathering-game-resources) to gather resources necessary for fheroes2 to function as expected. - - -### macOS ZIP archive +### macOS ZIP Archive * Download the [**macOS ZIP archive**](https://github.com/ihhub/fheroes2/releases/latest/download/fheroes2_macos_x86-64_SDL2.zip). Currently only x86-64 binaries are provided. If you use a machine with an Apple Silicon chip, you should choose another installation method (using [**MacPorts**](#macports) or [**Homebrew**](#homebrew-on-macos)), or [**build the project from source**](DEVELOPMENT.md#macos-and-linux). - * After downloading the ZIP archive, extract it to a suitable directory of your choice and then run `brew bundle` from the `script/macos` subdirectory. This will install the SDL libraries required to run the game. Follow the [**instructions below**](#gathering-game-resources) to gather resources necessary for fheroes2 to function as expected. - - -### macOS native app +### macOS Native App * Install the required dependencies using the provided Brewfile: @@ -157,16 +128,13 @@ make FHEROES2_MACOS_APP_BUNDLE=ON Follow the [**instructions below**](#gathering-game-resources) to gather resources necessary for fheroes2 to function as expected. - - -### Gathering game resources +### Gathering Game Resources Once you obtain the fheroes2 executable using any of the options above, you should follow these steps to load in the correct resources: * If you have a legally purchased copy of the original game in a self-extracting Windows executable (such as from GOG), you can utilize [`innoextract`](https://constexpr.org/innoextract/#use) to extract files out of the exe without having to use Wine/Windows emulation software on your *UNIX-based machine. - * If you have a legally purchased copy of the original game, run the extract resources script which will prompt you to enter the location of the original game, and will extract all the necessary resource files. The script can be run from the following paths depending on how you installed fheroes2: @@ -193,12 +161,8 @@ Once you obtain the fheroes2 executable using any of the options above, you shou | If you built from source using the [**macOS native app**](#macos-native-app) method | `script/demo/download_demo_version_for_app_bundle.sh` | | All other cases | `script/demo/download_demo_version.sh` | - - ## Linux - - ### Flatpak If you are using [**Flatpak**](https://flatpak.org) and [**Flathub**](https://flathub.org), you can install the game by running the @@ -227,13 +191,11 @@ The recommended option requires the Heroes of Might and Magic II installer file For the manual installation you have to copy the subdirectories `ANIM`, `DATA`, `MAPS` and `MUSIC` from the original game or demo directory to the `~/.var/app/io.github.ihhub.Fheroes2/data/fheroes2` directory. The destination folder will be opened when this option is selected. - - -### Gentoo package +### Gentoo Package If you are using [**Gentoo**](https://gentoo.org), you can install the game using package manager. There are several options: -#### GOG version +#### GOG Version If you purchased the game from GOG, add `games-strategy/homm2-gold-gog GOG-EULA` line to your `/etc/portage/package.license`, then use the following command: @@ -246,7 +208,7 @@ and if it's there, it will unpack everything to the correct places and pull `gam USE-flag `flac` determines whether the game will use FLAC music or OGG music. -#### Demo version +#### Demo Version You can install the demo version for free by adding `games-strategy/homm2-demo HoMM2-Demo` line to your `/etc/portage/package.license`, then using the following command: @@ -254,7 +216,7 @@ You can install the demo version for free by adding `games-strategy/homm2-demo H sudo emerge -av games-strategy/homm2-demo ``` -#### Another legal installation +#### Another Legal Installation If you installed the game from original CD, use the following commands: @@ -265,8 +227,6 @@ sudo emerge -av games-engines/fheroes2 The second command (Note: run it without root) will ask you where your data files are. - - ### Homebrew on Linux If you are using [**Homebrew**](https://brew.sh/), you can install the game by running the following command: @@ -280,14 +240,12 @@ be missing depending on the version of the original game) from the original game `~/.local/share/fheroes2`) directory. Otherwise, you can download and install the demo version of the original game by running the `/usr/share/fheroes2/download_demo_version.sh` script. - - -### AUR package +### AUR Package If you are using Arch Linux or compatible distribution, you can install [**fheroes2 package**](https://aur.archlinux.org/packages/fheroes2) from AUR (Arch User Repository). -#### Install using AUR helper +#### Install Using AUR Helper If you use one of AUR helpers, e.g. `yay`, you can install the game by running the following command: @@ -295,7 +253,7 @@ If you use one of AUR helpers, e.g. `yay`, you can install the game by running t yay -S aur/fheroes2 ``` -#### Install using the official guide +#### Install Using the Official Guide Follow the [**official guide**](https://wiki.archlinux.org/title/Arch_User_Repository#Installing_and_upgrading_packages). One of possible command sets: @@ -306,8 +264,6 @@ cd fheroes2 makepkg -si ``` - - ### Debian and Ubuntu fheroes2 is available from `contrib` repositories for Debian (since 13) and Ubuntu (since 24.04). You can install it by running: @@ -318,7 +274,7 @@ apt install fheroes2 These distributions may not provide the latest version of the game due to their release cycle. -#### Game resources +#### Game Resources To play the game you need the original game resources. You can install them to per-user paths (`man fheroes2` for more info, or you can install them to the system-wide path (`/usr/share/games/fheroes2`) with `game-data-packager` program (since v70). @@ -331,87 +287,61 @@ apt install ./homm2-data__all.deb You can get more info about resource packaging by running `game-data-packager heroes2 --help` - - -### Linux ZIP archive +### Linux ZIP Archive * Download one of the following Linux ZIP archives: - * [**Linux x86-64**](https://github.com/ihhub/fheroes2/releases/latest/download/fheroes2_ubuntu_x86-64_SDL2.zip) - * [**Linux ARM64**](https://github.com/ihhub/fheroes2/releases/latest/download/fheroes2_ubuntu_arm64_SDL2.zip) - * After downloading the ZIP archive, extract it to a suitable directory of your choice. Then you will need to install the SDL libraries required to run the game. The installation procedure depends on the Linux distribution you are using: - * **Debian-based**: run the script `install_sdl2.sh` from the `script/linux` subdirectory. - * **Pacman-based (e.g. Arch Linux)**: run the following command: `sudo pacman -S sdl2 sdl2_mixer`. - * **RedHat-based**: for RPM-based distributions (such as Fedora or RedHat) use the commands `sudo yum install SDL*` or `sudo dnf install SDL*`. - * **openSUSE**: openSUSE supports the One-Click-Install using the `SDL_mixer.ymp` file from the `script/linux` subdirectory. - * **Gentoo**: run the following command: `emerge --ask media-libs/sdl2-mixer`. - * After all dependencies are installed, run the `extract_homm2_resources.sh` script supplied in the ZIP archive if you have a legally purchased copy of the original game. You will be prompted to enter the location of the original game, and the script will extract all the necessary resource files. - * As an alternative to the previous step, you can manually copy the subdirectories `ANIM`, `DATA`, `MAPS` and `MUSIC` (some of them may be missing depending on the version of the original game) from the original game directory to the fheroes2 installation directory. - * If you don't have a legally purchased copy of the original game, you can download and install the demo version of the original game by running the `download_demo_version.sh` script supplied in the ZIP archive. - - ## Android * Install the fheroes2 app from [**Google Play**](https://play.google.com/store/apps/details?id=org.fheroes2) or download the [**Android ZIP archive**](https://github.com/ihhub/fheroes2/releases/latest/download/fheroes2_android.zip). - * Follow the [**instructions**](README_android.md). - - ## PlayStation Vita **Please note**: you need to be running custom firmware for it to work. * Download the [**PlayStation Vita ZIP archive**](https://github.com/ihhub/fheroes2/releases/latest/download/fheroes2_psv.zip). - * Follow the [**instructions**](README_PSV.md). - - ## Nintendo Switch **Please note**: you need to be running custom firmware for it to work. * Download the [**Nintendo Switch ZIP archive**](https://github.com/ihhub/fheroes2/releases/latest/download/fheroes2_switch.zip). - * Follow the [**instructions**](README_switch.md). - +## Snapshots (Latest Builds) -## Snapshots (latest builds) +You can download the precompiled binaries of the latest commit (snapshot) + +| Platform Version | Release | +|------------------|-----------------------------------------------------------------------------------------------------------| +| Windows x64 SDL2 | [fheroes2-windows-x64-SDL2](https://github.com/ihhub/fheroes2/releases/tag/fheroes2-windows-x64-SDL2) | +| Windows x86 SDL2 | [fheroes2-windows-x86-SDL2](https://github.com/ihhub/fheroes2/releases/tag/fheroes2-windows-x86-SDL2) | +| macOS x86-64 | [fheroes2-osx-sdl2_dev](https://github.com/ihhub/fheroes2/releases/tag/fheroes2-osx-sdl2_dev) | +| Ubuntu x86-64 | [fheroes2-linux-sdl2_dev](https://github.com/ihhub/fheroes2/releases/tag/fheroes2-linux-sdl2_dev) | +| Ubuntu ARM | [fheroes2-linux-arm-sdl2_dev](https://github.com/ihhub/fheroes2/releases/tag/fheroes2-linux-arm-sdl2_dev) | +| Android | [fheroes2-android](https://github.com/ihhub/fheroes2/releases/tag/fheroes2-android) | +| PlayStation Vita | [fheroes2-psv-sdl2_dev](https://github.com/ihhub/fheroes2/releases/tag/fheroes2-psv-sdl2_dev) | +| Nintendo Switch | [fheroes2-switch-sdl2_dev](https://github.com/ihhub/fheroes2/releases/tag/fheroes2-switch-sdl2_dev) | -You can download the precompiled binaries of the latest commit (snapshot) for -**Windows** ( -[**x64 SDL2**](https://github.com/ihhub/fheroes2/releases/tag/fheroes2-windows-x64-SDL2) and -[**x86 SDL2**](https://github.com/ihhub/fheroes2/releases/tag/fheroes2-windows-x86-SDL2) -), -**macOS x86-64** ( -[**SDL2**](https://github.com/ihhub/fheroes2/releases/tag/fheroes2-osx-sdl2_dev) -), -**Ubuntu** ( -[**x86-64 SDL2**](https://github.com/ihhub/fheroes2/releases/tag/fheroes2-linux-sdl2_dev) and -[**ARM64 SDL2**](https://github.com/ihhub/fheroes2/releases/tag/fheroes2-linux-arm-sdl2_dev) -), -[**Android**](https://github.com/ihhub/fheroes2/releases/tag/fheroes2-android), -[**PlayStation Vita**](https://github.com/ihhub/fheroes2/releases/tag/fheroes2-psv-sdl2_dev) and -[**Nintendo Switch**](https://github.com/ihhub/fheroes2/releases/tag/fheroes2-switch-sdl2_dev). **These binaries incorporate all the latest changes, but also all the latest bugs, and are mainly intended for developers.** **DON'T EXPECT THEM TO WORK PROPERLY.** diff --git a/docs/PRIVACY_POLICY.md b/docs/PRIVACY_POLICY.md index 6c10e6066..6d8df3c3a 100644 --- a/docs/PRIVACY_POLICY.md +++ b/docs/PRIVACY_POLICY.md @@ -1,4 +1,4 @@ -# [**fheroes2**](README.md) privacy policy +# [fheroes2](README.md) Privacy Policy **fheroes2** is provided at no cost and is intended for use as is. This document is used to inform regarding our policies with the collection, @@ -12,7 +12,7 @@ information in any of its official GitHub and Google Play Store releases. The project does not contain any library or programming module from third-party suppliers which collects sensitive personal information from its users. -## Contact information +## Contact Information If you have any questions or concerns about any of the matters in relation to this Privacy Policy then there are several ways of contacting us: diff --git a/docs/README.md b/docs/README.md index 9168bd27f..83567f84f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -8,16 +8,19 @@ and user interface improvements), breathing new life into one of the most addict You can find a complete list of all of our changes and enhancements in [**its own wiki page**](https://github.com/ihhub/fheroes2/wiki/Features-and-enhancements-of-the-project). -

- Screenshot of the world map -

+ +
+
+ Screenshot of the world map +
+
+ Screenshot of the battle screen + Screenshot of the castle screen +
+
+ -

- Screenshot of the battle screen - Screenshot of the castle screen -

- -## Download and install +## Download and Install Please follow the [**installation guide**](INSTALL.md) to download and install fheroes2. @@ -69,6 +72,6 @@ We also have a [**Discord**](https://discord.gg/xF85vbZ) server to discuss the d [![VK](https://img.shields.io/badge/VK-blue.svg)](https://vk.com/fheroes2) [![Discord](https://img.shields.io/discord/733093692860137523.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/xF85vbZ) -## FAQ +## Frequently Asked Questions (FAQ) You can find answers to the most commonly asked questions on our [**F.A.Q. page**](https://github.com/ihhub/fheroes2/wiki/F.A.Q.). diff --git a/docs/README_PSV.md b/docs/README_PSV.md index 0e0d1eea9..3e8c12ef0 100644 --- a/docs/README_PSV.md +++ b/docs/README_PSV.md @@ -1,4 +1,4 @@ -# PlayStation Vita port of [**fheroes2**](README.md) project +# PlayStation Vita Port of [fheroes2](README.md) Project ## Install @@ -54,7 +54,7 @@ Text input is done with D-Pad. * Up - Previous character * R1, L1 - Switch current character between uppercase/lowercase -## Vita specific options +## Vita Specific Options Pointer movement speed can be changed with 'gamepad_pointer_speed' parameter in "ux0:data/fheroes2/fheroes2.cfg". diff --git a/docs/README_android.md b/docs/README_android.md index 670a98d03..c0e6a8aa9 100644 --- a/docs/README_android.md +++ b/docs/README_android.md @@ -1,4 +1,4 @@ -# Android port of [**fheroes2**](README.md) project +# Android Port of [fheroes2](README.md) Project ## Installation @@ -40,7 +40,7 @@ To make it easier to select the angle of attack on touchscreens, you can "draw" intend to attack from, to the cell occupied by the enemy unit. Next, you should remove your finger from the screen, double-check your planned attack, and then confirm the action by touching the target cell with your finger again. -## Android specific notes +## Android Specific Notes Fullscreen is enabled by default. To have the info bar with the clock visible you can disable fullscreen mode within the main menu settings under "Graphics". diff --git a/docs/README_cmake.md b/docs/README_cmake.md index 9a1774862..a8acab189 100644 --- a/docs/README_cmake.md +++ b/docs/README_cmake.md @@ -60,7 +60,7 @@ cmake --build build --config Release After building, executable can be found in `build\Release` directory. -## Using Demo data +## Using Demo Data CMake project allows to download and install original HoMM II Demo files which used by fheroes2 project. To do this please add `-DGET_HOMM2_DEMO=ON` to configuration options. For example: diff --git a/docs/README_emscripten.md b/docs/README_emscripten.md index 6599def66..589de81b8 100644 --- a/docs/README_emscripten.md +++ b/docs/README_emscripten.md @@ -1,6 +1,6 @@ -# Emscripten (Wasm) port of [**fheroes2**](README.md) project +# Emscripten (Wasm) Port of [fheroes2](README.md) Project -## Current status of this port +## Current Status of this Port Please note that this port is currently still **experimental**. You may experience various problems, crashes, or it not even working at all in particular browsers. @@ -27,7 +27,7 @@ If you do not want to use Docker, then you will need to install all the prerequi emmake make -f Makefile.emscripten ``` -### Building with additional parameters +### Building with Additional Parameters If you want to specify some additional ad hoc build parameters, you can use the appropriate environment variables for this. For example, the following command: @@ -37,9 +37,9 @@ FHEROES2_WITH_THREADS=ON LDFLAGS="-sMODULARIZE -sEXPORTED_RUNTIME_METHODS=run -s will build a WebAssembly binary with multithreading support, as well as with additional parameters for creating a module. -## Running the Wasm port on a web server +## Running the Wasm Port on a Web Server -### Configuring the web server +### Configuring the Web Server Emscripten uses web workers along with `SharedArrayBuffer` to support multithreading. `SharedArrayBuffer` usage is usually protected by Cross Origin Opener Policy (COOP) and Cross Origin Embedder Policy (COEP) HTTP headers, and the web server should send these headers as part of its response to a request for resources related to the Wasm @@ -54,7 +54,7 @@ Please see the following link for details: -### Copying necessary files +### Copying Necessary Files After the build is completed, copy the following files to the appropriate directory on your website: diff --git a/docs/README_switch.md b/docs/README_switch.md index f1500d674..317984e13 100644 --- a/docs/README_switch.md +++ b/docs/README_switch.md @@ -1,8 +1,8 @@ -# Nintendo Switch port of [**fheroes2**](README.md) project +# Nintendo Switch Port of [fheroes2](README.md) Project It's a homebrew app, so you need to be running custom firmware for it to work. -## BUILDING +## Building You will need to install the [devkitPro](https://devkitpro.org/) toolchain. Make sure to include the following package: @@ -12,7 +12,7 @@ libnx switch-sdl2_mixer After installation run `make -f Makefile.switch -j 2` command to build the package. -## SETUP +## Setup You will need a copy of the official game to run this port. @@ -41,7 +41,7 @@ Generally, you will need game resources from the localized version of HoMM2 in o the first run, the game should auto-detect the game data you have and offer to choose a language you'd like to use. English is always available. -## RUNNING +## Running This build of fheroes2 was tested on 12.0.3|AMS M.19.4|S (FAT32). exFAT is not recommended. USB mice and keyboards connected via an OTG adapter are supported. diff --git a/docs/TRANSLATION.md b/docs/TRANSLATION.md index 7211ad215..e6fb8447d 100644 --- a/docs/TRANSLATION.md +++ b/docs/TRANSLATION.md @@ -1,9 +1,9 @@ -# [**fheroes2**](README.md) translation guide +# [fheroes2](README.md) Translation Guide This project uses portable object (PO) files to handle localization in various languages. The PO files are located in the `files/lang` subdirectory of the project source tree. The current instruction is designed for Linux, MacOS and Windows users. -## Current status +## Current Status ![Belarusian](https://img.shields.io/endpoint?url=https://ihhub.github.io/fheroes2/json/lang_be.json) ![Bulgarian](https://img.shields.io/endpoint?url=https://ihhub.github.io/fheroes2/json/lang_bg.json) @@ -27,7 +27,7 @@ subdirectory of the project source tree. The current instruction is designed for ![Ukrainian](https://img.shields.io/endpoint?url=https://ihhub.github.io/fheroes2/json/lang_uk.json) ![Vietnamese](https://img.shields.io/endpoint?url=https://ihhub.github.io/fheroes2/json/lang_vi.json) -## Adding new translations/localizations +## Adding New Translations/Localizations If you want to add a new localization, you will first need to add it to the `SupportedLanguage` list/enumeration in the source code. Afterwards, a new PO file for it will need to be added. It will have to be named according to the ISO standard's two-character @@ -35,30 +35,30 @@ language abbreviations. Then to have font support, you will have to specify what the language to the font generation code found in `src/fheroes2/gui/ui_font.cpp`. If a compatible font encoding has not currently been implemented, then code for that will need to be written. -## Editing translations - Before you start +## Editing Translations - Before You Start Before starting, you will have to set up the necessary environment: fork the fheroes2 repository and install an application used for translating. When you have your own fork of fheroes2 you should create a branch. At this point you can start translating. After you finish your work, and you are ready to share it, you will have to prepare a pull request. -### Forking the fheroes2 repository +### Forking the fheroes2 Repository A fork is your copy of the fheroes2 repository. It gives you a safe environment to prepare and test your changes. You can read here how to [**create a fork**](https://docs.github.com/en/get-started/quickstart/fork-a-repo). -### Translation editing software +### Translation Editing Software We encourage you to use [**poedit**](https://poedit.net/) or [**gtranslator**](https://wiki.gnome.org/Apps/Gtranslator) to edit translations. Currently all implemented languages adhere to a standardized font encoding/charset. -## Editing translations - For the first time or again +## Editing Translations - For the First Time or Again -### Syncing your fork +### Syncing Your Fork Before you start working on the first or next translation, make sure that your fork has all the recent changes from the fheroes2 repo. To do this, [**sync your fork**](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork). -### Creating a branch +### Creating a Branch Next you will set up an environment for working on your translation, in addition to testing and sharing your changes. Read more [**about branches**](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-branches). @@ -66,7 +66,7 @@ Read more [**about branches**](https://docs.github.com/en/pull-requests/collabor To create a branch, please follow GitHub's instructions on [**creating a branch within your repo**](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-and-deleting-branches-within-your-repository). -### Submitting translations +### Submitting Translations Finally you will use your translation software of choice to make changes to the translation. All original translatable strings are located in the source code of the project. If you need to clarify where this string is being used you can search for it. @@ -76,7 +76,7 @@ The string below, for example, can be translated in PO files: _( "Are you sure you want to quit?" ) ``` -### Testing your changes +### Testing Your Changes Once the translation files have been modified, for Linux/MacOS run the `make` command below in the `files/lang` subdirectory to create machine object (MO) binary files which can be used by the fheroes2 engine. @@ -105,7 +105,7 @@ set to. For example, for German you will have to set font encoding to CP1252, while for Russian this would be CP1251. Later when submitting a pull request with your changes, you will have to save the PO file in UTF-8 encoding because this is what Github supports. -### Sharing your translation work +### Sharing Your Translation Work When you are satisfied with your work, you can proceed with sharing it. The first step is to commit your work into the branch you made of your own fheroes2 fork. Then, create a pull request that proposes to introduce your changes into the fheroes2 repository. @@ -136,7 +136,7 @@ example creature names or castle buildings. -## Updating PO templates and translatable strings in PO files +## Updating PO Templates and Translatable Strings in PO Files Currently all PO files are automatically updated with new strings after each commit that brings changes to the ingame text. If for whatever reason you still need to update strings locally, this can be achieved by running the command below in `src/dist/fheroes2` to generate a new portable object diff --git a/docs/WEBSITE_LOCAL_DEV.md b/docs/WEBSITE_LOCAL_DEV.md new file mode 100644 index 000000000..2f989d34d --- /dev/null +++ b/docs/WEBSITE_LOCAL_DEV.md @@ -0,0 +1,175 @@ +# Website Local Documentation Development Guide + +This guide explains how to set up and run the documentation site locally for +development purposes. + +## Prerequisites + +* Ruby (version 2.7.0 or higher) + +* Bundler +* Git +* Node/npm +* A GitHub account with a fork of the fheroes2 repository + +### macOS Users + +If you're on macOS, you can install the required development tools using the +provided Brewfile: + +```bash +# Install the development tools using brew bundle +brew bundle --file=script/macos/Brewfile.dev_tools +``` + +This will install the necessary tools to assist with formatting and for linting +source files. + +## Setting Up Local Development Environment + +1. Clone your fork of the repository: + + ```bash + git clone https://github.com//fheroes2.git + cd fheroes2/docs + ``` + +2. Copy the development Gemfile to enable local development: + + ```bash + cp Gemfile.dev Gemfile + ``` + + > **Note** + > While the gem in this file may eventually be deprecated, it's currently the + > simplest way to enable local development of the GitHub Pages site. As such, + > the Gemfile should not be committed into the repo. + +3. Install the required Ruby dependencies: + + ```bash + bundle install + ``` + +4. Install the npm dev packages: + + ```bash + npm install + ``` + +5. Build the site locally: (Optional) + + ```bash + bundle exec jekyll build + ``` + +6. To preview the site locally with live reload: + + ```bash + bundle exec jekyll serve + ``` + + This will start a local server, typically at `http://localhost:4000` + +## Making Changes + +1. Create a new branch for your documentation changes: + + ```bash + git checkout -b docs/your-feature-name + ``` + +2. Make your changes to the documentation files in the `docs` directory. + +3. Test your changes locally using the serve command mentioned above. + +4. Verify your markdown file changes using the project's linting tools: + + > **Note** + > We use formatting/linting tools to ensure consistent formatting and quality + > across all markdown files. + + ```bash + cd docs + # Run the linter on all Markdown files in the docs directory + npm run lint-md "*.md" + # Or have the linter attempt to format automatically + npm run format-md "*.md" + ``` + + This will check your Markdown files against our style rules and highlight any + issues that need to be fixed. + +5. Format HTML, CSS, and JavaScript files using the provided npm scripts: + + ```bash + # Format HTML and CSS files + npm run format-html-css + + # Format JavaScript files + npm run format-js + ``` + +6. Commit your changes: + + ```bash + git add . + git commit -m "docs: your descriptive commit message" + ``` + +7. Push your branch to your fork: + + ```bash + git push origin docs/your-feature-name + ``` + +## Verifying Site Changes in Fork + +For the most accurate verification of your documentation changes, follow these +steps: + +1. Push your branch to your fork: + + ```bash + git push origin docs/your-feature-name + ``` + +2. Set up GitHub Pages in your fork by following the +[official GitHub Pages documentation](https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site#publishing-from-a-branch). +Make sure to: + + * Configure the source to deploy from your feature branch + * Set the folder to `/docs` + +3. Wait for GitHub Pages to build and deploy your site. This may take a few +minutes. You can monitor the progress in the "Actions" tab of your repository. + +4. Once deployed, you can preview your changes at `https://.github.io/fheroes2/` + +5. Review your changes in the preview environment to ensure: + + * All links work correctly + * Images are displayed properly + * The layout is consistent with the main site + * No broken references or missing assets + +6. After verifying everything looks correct in your fork's GitHub Pages, create +a Pull Request (PR) from your fork's branch to the main fheroes2 repository for +final review and deployment. + +## Common Issues and Solutions + +* If you encounter Ruby version conflicts, make sure you're using a compatible +version. You can use tools like `rbenv` or `rvm` to manage Ruby versions. +* If the site doesn't build, check the Jekyll build logs for specific error +messages. +* If images aren't displaying, ensure they're placed in the correct directory +(`docs/images/`) and referenced correctly in your markdown files. + +## Additional Resources + +* [Jekyll Documentation](https://jekyllrb.com/docs/) +* [GitHub Pages Documentation](https://docs.github.com/en/pages) +* [GitHub Pages Quickstart Guide](https://docs.github.com/en/pages/quickstart#introduction) +* [Deploying from a branch in GitHub Pages](https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site#choosing-a-publishing-source) +* [Markdown Guide](https://www.markdownguide.org/) diff --git a/docs/_config.yml b/docs/_config.yml index e8b995b95..ade470e80 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1 +1,6 @@ -theme: jekyll-theme-merlot +description: A recreation of the Heroes of Might and Magic II game engine. + +favicon: /_includes/favicon.ico + +sass: + style: compressed diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html new file mode 100644 index 000000000..f271106ac --- /dev/null +++ b/docs/_layouts/default.html @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + {% seo %} + + + + +
+
+ +
+
+

+ {{ site.title | default: site.github.repository_name }} +

+

+ A recreation of the Heroes of Might and Magic II game + engine. +

+
+ +
{{ content }}
+ + +
+ + diff --git a/docs/_sass/_dark-theme.scss b/docs/_sass/_dark-theme.scss new file mode 100644 index 000000000..31666d6d6 --- /dev/null +++ b/docs/_sass/_dark-theme.scss @@ -0,0 +1,19 @@ +$dark: ( + primary-color: #c0c0c0, + header-color: #e4c814, + secondary-color: #480a0a, + page-color: #989898, + text-color: #e0e0e0, + background-color: #383838, + border-color: #480a0a, + highlight-color: #800080, + code-background-color: #2a2a2a, + inverse-text-color: #2c1810, + inverse-background-color: #f5deb3, + inverse-border-color: #8b4513, + inverse-primary-color: #8b4513, + border-radius: 5px, + body-text-shadow: 2px 2px 2px #383838, + header-text-shadow: -2px 3px 1px darken(#a42da4, 10%), + table-text-color: #e0e0e0, +); diff --git a/docs/_sass/_layout.scss b/docs/_sass/_layout.scss new file mode 100644 index 000000000..7b712f4cd --- /dev/null +++ b/docs/_sass/_layout.scss @@ -0,0 +1,644 @@ +$mobile-width: 768px; +$tablet-width: 1024px; +$container-width: 1200px; +$hero-header-font: "Jacquard 24"; +$header-font: "Lancelot"; +$body-font: "Asul"; + +// Mixin for responsive table styles +@mixin responsive-table($theme-map) { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + margin: 1em auto; + + &.stack { + thead { + display: none; + } + + tr { + border-bottom: 0.125em solid rgba(map-get($theme-map, primary-color), 0.2); + margin-bottom: 1em; + + &:last-child { + border-bottom: none; + margin-bottom: 0; + } + } + + td { + text-align: right; + padding: 0.6em 1em; + border-bottom: 0.0625em solid + rgba(map-get($theme-map, primary-color), 0.1); + + &:before { + content: attr(data-label); + float: left; + font-family: $header-font, cursive; + color: map-get($theme-map, primary-color); + font-weight: 400; + } + + &:last-child { + border-bottom: none; + } + } + } +} + +// Mixin for responsive image showcase styles +@mixin responsive-image-showcase { + flex-direction: column; + + .row { + flex-direction: column; + gap: 1em; + } + + img.half-image { + width: 100%; + margin-bottom: 0; + } +} + +@mixin responsive-code-highlight($theme-map) { + .highlighter-rouge { + padding: 0; + background: none; + border: none; + + .highlight { + flex-direction: column; + align-items: stretch; + padding: 0; + + pre.highlight { + margin: 0; + -webkit-overflow-scrolling: touch; + padding: 0.5em 0.5em 0.5em 1em; + scrollbar-width: none; + border-radius: map-get($theme-map, border-radius); + + code { + font-size: 1em; + padding: 0; + } + } + + .copy-btn { + flex-grow: 1; + } + } + } + code.highlighter-rouge { + font-size: 0.6em; + word-wrap: break-word; + } +} + +@mixin themable($theme-name, $theme-map) { + [data-theme="#{$theme-name}"] { + // Global styles + body { + background: map-get($theme-map, background-color); + color: map-get($theme-map, text-color); + font-family: $body-font, sans-serif; + font-weight: 400; + font-style: normal; + line-height: 1.4; + margin: 0; + padding: 0; + } + + a { + color: map-get($theme-map, highlight-color); + text-decoration: none; + + &:hover { + color: lighten(map-get($theme-map, highlight-color), 5%); + } + } + + h1, + h2, + h3, + h4, + h5, + h6 { + color: map-get($theme-map, header-color); + font-weight: 400; + font-style: normal; + position: relative; + margin: 0; + line-height: 1.2em; + text-shadow: map-get($theme-map, header-text-shadow); + &:hover { + color: lighten(map-get($theme-map, header-color), 10%); + } + + .heading-link { + display: block; + position: relative; + -webkit-tap-highlight-color: transparent; + + &:hover { + color: map-get($theme-map, header-color); + + .heading-anchor { + opacity: 1; + } + } + } + } + + h1 a, + h2 a, + h3 a, + h4 a, + h5 a, + h6 a { + text-shadow: map-get($theme-map, header-text-shadow); + } + + h1 { + font-family: $hero-header-font, cursive; + margin: 0.3em 0; + font-size: 3em; + padding: 0; + border: none; + position: relative; + + a { + color: map-get($theme-map, header-color); + position: relative; + display: inline-block; + + &:hover { + color: lighten(map-get($theme-map, header-color), 10%); + } + } + } + + h2, + h3, + h4, + h5, + h6 { + font-family: $header-font, serif; + } + + h2 { + font-size: 2em; + } + + h3 { + font-size: 1.5em; + } + + h4 { + font-size: 1.2em; + } + + p { + margin-bottom: 1.2em; + } + + ol, + p, + table, + ul { + text-shadow: map-get($theme-map, body-text-shadow); + } + a { + text-shadow: none; + } + + code { + font-family: monospace; + background: none; + padding: 0; + } + + pre { + margin: 0; + padding: 0; + background: none; + } + + // Header styles + header { + text-align: center; + margin-bottom: 0; + border-bottom: 0.125em solid map-get($theme-map, secondary-color); + // text-shadow: 0.125em 0.125em 0.25em $primary-color; + + h1 { + font-size: 4em; + margin: 0; + padding: 0; + text-shadow: none; + border: none; + transform-style: preserve-3d; + transform: perspective(1000px) rotateX(3deg); + transition: transform 0.3s ease; + + &:hover { + transform: perspective(1000px) rotateX(0deg) translateY(-3px); + } + + a { + color: map-get($theme-map, header-color); + position: relative; + display: inline-block; + transform-style: preserve-3d; + + &:before { + content: attr(data-text); + position: absolute; + left: 0; + top: 0; + color: rgba(255, 255, 255, 0.3); + transform: translateZ(-20px); + filter: blur(2px); + } + + &:after { + content: attr(data-text); + position: absolute; + left: 0; + top: 0; + color: rgba(0, 0, 0, 0.3); + transform: translateZ(-10px); + filter: blur(1px); + } + + &:hover { + color: lighten(map-get($theme-map, header-color), 10%); + } + } + } + + h2 { + font-family: $body-font, sans-serif; + font-size: 1.5em; + margin: 0.625em 0; + border: none; + } + } + + ul { + padding-left: 1em; + } + + ol { + padding-left: 1em; + margin-top: revert; + margin-bottom: revert; + } + + li { + margin-bottom: 0.5em; + } + + // Footer styles + footer { + text-align: center; + margin-top: 40px; + padding: 20px; + background: rgba(map-get($theme-map, background-color), 0.3); + border-radius: map-get($theme-map, border-radius); + + p { + margin: 0; + } + } + + .shell { + max-width: $container-width; + padding: 0 1.25em 1.25em; + background: rgba(map-get($theme-map, page-color), 0.9); + box-shadow: 0 0 1.25em map-get($theme-map, border-color); + font-size: 1.6em; + } + + .image-showcase { + display: flex; + justify-content: space-between; + flex-wrap: wrap; + gap: 1em; + margin: 1em 0; + + .row { + display: flex; + justify-content: space-between; + width: 100%; + gap: 1em; + } + + img.full-image { + width: 100%; + height: auto; + } + + img.half-image { + width: calc(50% - 0.5em); + height: auto; + } + } + + // Button styles + .btn { + display: inline-block; + padding: 0.5em; + font-family: $header-font, cursive; + font-size: 1.1em; + text-align: center; + text-decoration: none; + border-radius: map-get($theme-map, border-radius); + cursor: pointer; + transition: all 0.3s ease; + border: 0.125em solid transparent; + box-shadow: 0 0.25em 0.5em rgba(0, 0, 0, 0.2); + position: relative; + overflow: hidden; + + &:hover { + transform: translateY(-2px); + box-shadow: 0 0.5em 1em rgba(0, 0, 0, 0.3); + } + + &:active { + transform: translateY(1px); + box-shadow: 0 0.125em 0.25em rgba(0, 0, 0, 0.2); + } + + // Primary button + &.btn-primary { + background: map-get($theme-map, primary-color); + color: map-get($theme-map, background-color); + border-color: map-get($theme-map, primary-color); + + &:hover { + background: darken(map-get($theme-map, primary-color), 10%); + } + } + + // Secondary button + &.btn-secondary { + background: map-get($theme-map, secondary-color); + color: map-get($theme-map, primary-color); + border-color: map-get($theme-map, secondary-color); + + &:hover { + background: darken(map-get($theme-map, secondary-color), 10%); + } + } + + // Outline button + &.btn-outline { + background: transparent; + color: map-get($theme-map, primary-color); + border-color: map-get($theme-map, primary-color); + + &:hover { + background: rgba(map-get($theme-map, primary-color), 0.1); + } + } + + // Disabled state + &:disabled, + &.disabled { + opacity: 0.6; + cursor: not-allowed; + pointer-events: none; + } + } + + .theme-toggle-container { + display: flex; + font-size: 0.5em; + justify-content: end; + margin: 1.25em 0em; + + .btn { + &.btn-primary { + color: map-get($theme-map, inverse-text-color); + background: map-get($theme-map, inverse-background-color); + border-color: map-get($theme-map, inverse-border-color); + + &:hover { + background: map-get($theme-map, inverse-primary-color); + } + } + } + } + + @media screen and (min-width: $tablet-width) { + .shell { + border: 0.125em solid map-get($theme-map, border-color); + border-radius: map-get($theme-map, border-radius); + margin: 1.25em; + } + + #main_content { + padding: 1.25em; + } + } + + @media screen and (min-width: $container-width) { + .shell { + margin: 1.25em auto; + } + } + + .highlighter-rouge { + background: rgba(map-get($theme-map, primary-color), 0.05); + padding: 0; + border-radius: map-get($theme-map, border-radius); + position: relative; + border: 0.0625em solid rgba(map-get($theme-map, primary-color), 0.1); + margin-bottom: 1.2em; + + .highlight { + padding: 0.7em; + scrollbar-width: none; + -webkit-overflow-scrolling: touch; + background: none; + position: relative; + overflow-x: auto; + display: flex; + justify-content: space-between; + gap: 1em; + align-items: center; + + pre.highlight { + background: rgba(map-get($theme-map, code-background-color), 0.5); + border-radius: map-get($theme-map, border-radius); + flex-grow: 1; + + code { + display: block; + white-space: pre; + padding: 0; + } + } + } + } + + code.highlighter-rouge { + padding: 0.5em; + font-size: 0.8em; + background: rgba(map-get($theme-map, code-background-color), 0.5); + } + + // Heading anchor links + .heading-anchor { + opacity: 0; + font-size: min(1em, 24px); + margin-left: 0.5em; + text-decoration: none; + vertical-align: middle; + transition: all 0.3s ease; + color: lighten(map-get($theme-map, header-color), 10%); + display: inline-block; + cursor: copy; + + &:hover { + opacity: 1 !important; + transform: scale(1.1); + } + } + + h1, + h2, + h3, + h4, + h5, + h6 { + &:hover .heading-anchor { + opacity: 1; + } + } + + table { + width: 100%; + border-collapse: separate; + border-spacing: 0; + margin: 1.5em 0; + background: darken(map-get($theme-map, primary-color), 20%); + border: 0.1em solid rgba(map-get($theme-map, secondary-color), 0.6); + border-radius: map-get($theme-map, border-radius); + overflow: hidden; + box-shadow: 0 0.125em 0.25em + rgba(map-get($theme-map, secondary-color), 0.1); + + th { + background: rgba(map-get($theme-map, background-color), 0.6); + color: map-get($theme-map, primary-color); + font-family: $header-font, cursive; + font-weight: 400; + padding: 1em; + text-align: left; + border-bottom: 0.125em solid + rgba(map-get($theme-map, secondary-color), 0.3); + font-size: 1.1em; + white-space: nowrap; + position: sticky; + top: 0; + z-index: 1; + backdrop-filter: blur(4px); + } + + td { + padding: 0.8em 1em; + border-bottom: 0.0625em solid + rgba(map-get($theme-map, primary-color), 0.1); + vertical-align: middle; + line-height: 1.4; + } + + tr { + color: map-get($theme-map, table-text-color); + } + tr:last-child td { + border-bottom: none; + } + + tr:hover { + background: rgba(map-get($theme-map, secondary-color), 0.05); + } + } + + // Portrait mobile styles + @media screen and (max-width: $mobile-width) and (orientation: portrait) { + @include responsive-code-highlight($theme-map); + + .heading-anchor { + display: none !important; + } + + .shell { + padding: 0.625em; + font-size: 2.5em; + } + + img.game-screenshot { + width: 100%; + height: auto; + } + + table { + @include responsive-table($theme-map); + display: block; + + &.stack { + tr { + display: block; + } + + td { + display: block; + } + } + } + + .image-showcase { + @include responsive-image-showcase; + } + } + + // Landscape mobile styles + @media screen and (max-width: $tablet-width) and (orientation: landscape) { + body { + font-size: 0.6em; + } + @include responsive-code-highlight($theme-map); + + .heading-anchor { + display: none !important; + } + + .shell { + padding: 0.625em; + font-size: 1.8em; + } + + img.game-screenshot { + width: 100%; + height: auto; + } + + table { + @include responsive-table($theme-map); + } + + .image-showcase { + @include responsive-image-showcase; + } + } + } +} + +@include themable(light, $light); +@include themable(dark, $dark); diff --git a/docs/_sass/_light-theme.scss b/docs/_sass/_light-theme.scss new file mode 100644 index 000000000..4ca34fbef --- /dev/null +++ b/docs/_sass/_light-theme.scss @@ -0,0 +1,19 @@ +$light: ( + primary-color: #8b4513, + header-color: #8b4513, + secondary-color: #daa520, + page-color: #fff, + text-color: #2c1810, + background-color: #f5deb3, + border-color: #8b4513, + highlight-color: #cd853f, + code-background-color: #e6e1da, + inverse-text-color: #e0e0e0, + inverse-background-color: #383838, + inverse-border-color: #c0c0c0, + inverse-primary-color: #c0c0c0, + border-radius: 10px, + body-text-shadow: none, + header-text-shadow: -1px 2px 1px #cd853f, + table-text-color: #fff, +); diff --git a/docs/assets/css/style.scss b/docs/assets/css/style.scss new file mode 100644 index 000000000..bbba2c0db --- /dev/null +++ b/docs/assets/css/style.scss @@ -0,0 +1,6 @@ +--- +--- + +@import "dark-theme"; +@import "light-theme"; +@import "layout"; diff --git a/docs/assets/js/accessibility.js b/docs/assets/js/accessibility.js new file mode 100644 index 000000000..a819a15de --- /dev/null +++ b/docs/assets/js/accessibility.js @@ -0,0 +1,178 @@ +/*************************************************************************** + * fheroes2: https://github.com/ihhub/fheroes2 * + * Copyright (C) 2025 * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +// Utility class for handling common accessibility features +class AccessibilityManager +{ + constructor() + { + this.liveRegion = this.createLiveRegion(); + } + + // Creates a live region for screen reader announcements + // The live region is a div element that is used to announce messages to + // screen readers. + // Returns: The live region element + createLiveRegion() + { + const liveRegion = document.createElement( 'div' ); + liveRegion.setAttribute( 'aria-live', 'assertive' ); + liveRegion.setAttribute( 'aria-atomic', 'true' ); + // This doesn't work as a CSS property, so we need to set it manually + liveRegion.style.cssText + = 'position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;'; + document.body.appendChild( liveRegion ); + return liveRegion; + } + + // Announces a message to screen readers + // Parameters: + // message - The message to announce + announce( message ) + { + // Clear the live region first + this.liveRegion.textContent = ''; + + // Force a reflow to ensure the announcement is triggered if the user + // triggers multiple times in a row. + void this.liveRegion.offsetHeight; + + // Set the new message + this.liveRegion.textContent = message; + + // Force another reflow to ensure the announcement is triggered + void this.liveRegion.offsetHeight; + } + + // Creates an accessible element (button or span) + // Parameters: + // options - An object containing the following properties: + // text - The element text + // ariaLabel - The ARIA label + // className - Additional CSS classes + // elementType - The element type ('button' or 'span') + // Returns: The accessible element + createAccessibleElement( options ) + { + const { text, ariaLabel, className = '', elementType = 'button' } = options; + + const element = document.createElement( elementType ); + element.textContent = text; + element.setAttribute( 'aria-label', ariaLabel ); + element.setAttribute( 'role', 'button' ); + element.setAttribute( 'tabindex', '0' ); + if ( className ) { + element.className = className; + } + return element; + } + + // Creates an accessible button element + // Parameters: + // options - An object containing the following properties: + // text - The button text + // ariaLabel - The ARIA label + // className - Additional CSS classes + // Returns: The button element + createAccessibleButton( options ) + { + return this.createAccessibleElement( {...options, elementType : 'button' } ); + } + + // Creates an accessible span element + // Parameters: + // options - An object containing the following properties: + // text - The span text + // ariaLabel - The ARIA label + // className - Additional CSS classes + // Returns: The span element + createAccessibleSpan( options ) + { + return this.createAccessibleElement( {...options, elementType : 'span' } ); + } + + // Updates element state with visual and screen reader feedback + // Parameters: + // options - An object containing the following properties: + // element - The element to update + // success - Whether the action was successful + // successMessage - Message for screen reader on success + // errorMessage - Message for screen reader on error + // successText - Text to show on element for success + // errorText - Text to show on element for error + // defaultText - Default element text + // resetDelay - Delay before resetting element (ms) + // isHtml - Whether the text contains HTML + updateElementState( options ) + { + const { element, success, successMessage, errorMessage, successText, errorText, defaultText, resetDelay = 2000, isHtml = false } = options; + + // Update visual state first + if ( success ) { + if ( isHtml ) { + element.innerHTML = successText; + } + else { + element.textContent = successText; + } + element.classList.add( 'success' ); + } + else { + if ( isHtml ) { + element.innerHTML = errorText; + } + else { + element.textContent = errorText; + } + element.classList.add( 'error' ); + } + + // Announce to screen reader after a short delay to ensure visual update is complete + setTimeout( () => { this.announce( success ? successMessage : errorMessage ); }, 50 ); + + // Reset element after delay + setTimeout( () => { + if ( isHtml ) { + element.innerHTML = defaultText; + } + else { + element.textContent = defaultText; + } + element.classList.remove( 'success', 'error' ); + }, resetDelay ); + } + + // Sets up keyboard event handling for an element + // Parameters: + // element - The element to add keyboard events to + // handler - The click handler function + setupKeyboardEvents( element, handler ) + { + element.addEventListener( 'keydown', ( event ) => { + if ( event.key === 'Enter' || event.key === ' ' ) { + event.preventDefault(); + handler( event ); + } + } ); + } +} + +// Export the accessibility manager +window.AccessibilityManager = AccessibilityManager; diff --git a/docs/assets/js/code-copy.js b/docs/assets/js/code-copy.js new file mode 100644 index 000000000..33547a57a --- /dev/null +++ b/docs/assets/js/code-copy.js @@ -0,0 +1,108 @@ +/*************************************************************************** + * fheroes2: https://github.com/ihhub/fheroes2 * + * Copyright (C) 2025 * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +// Class to handle code copy functionality +class CodeCopyManager +{ + constructor() + { + this.accessibility = new AccessibilityManager(); + + // Apply to all code blocks + document.querySelectorAll( "div.highlight" ).forEach( block => this.initializeCodeBlock( block ) ); + } + + // Creates a copy button using the template + // Returns: The button element + createCopyButton() + { + return this.accessibility.createAccessibleButton( { text : 'Copy', ariaLabel : 'Copy code to clipboard', className : 'btn btn-primary copy-btn' } ); + } + + // Updates the button appearance and announces success to screen readers + // Parameters: + // button - The button element + // success - Whether the copy was successful + // code - The code content that was copied + updateButtonState( button, success, code ) + { + // Truncate the code if it's too long + const truncatedCode = code.length > 50 ? `${code.substring( 0, 50 )}...` : code; + + this.accessibility.updateElementState( { + element : button, + success : success, + successMessage : `Code copied to clipboard: ${truncatedCode}`, + errorMessage : 'Failed to copy code to clipboard', + successText : 'Copied!', + errorText : 'Failed to copy', + defaultText : 'Copy', + resetDelay : 2000 + } ); + } + + // Handles the copy functionality for a code block + // Parameters: + // block - The code block element + // button - The copy button + handleCopyCode( block, button ) + { + try { + const code = block.querySelector( "pre" ).innerText; + navigator.clipboard.writeText( code ).then( () => { this.updateButtonState( button, true, code ); } ).catch( err => { + console.error( "Failed to copy code:", err ); + this.updateButtonState( button, false, code ); + } ); + } + catch ( err ) { + console.error( "Failed to copy code:", err ); + this.updateButtonState( button, false, '' ); + } + } + + // Sets up event listeners for a copy button + // Parameters: + // button - The copy button + // block - The code block element + setupEventListeners( button, block ) + { + // Click event handler + button.addEventListener( "click", () => this.handleCopyCode( block, button ) ); + + // Keyboard event handler + this.accessibility.setupKeyboardEvents( button, () => this.handleCopyCode( block, button ) ); + } + + // Initializes a code block with a copy button + // Parameters: + // block - The code block element + initializeCodeBlock( block ) + { + const button = this.createCopyButton(); + block.appendChild( button ); + this.setupEventListeners( button, block ); + } +} + +// Initialize when the DOM is fully loaded +document.addEventListener( "DOMContentLoaded", () => { + // Initialize the code copy manager + new CodeCopyManager(); +} ); diff --git a/docs/assets/js/heading-copy.js b/docs/assets/js/heading-copy.js new file mode 100644 index 000000000..72b2d47a5 --- /dev/null +++ b/docs/assets/js/heading-copy.js @@ -0,0 +1,150 @@ +/*************************************************************************** + * fheroes2: https://github.com/ihhub/fheroes2 * + * Copyright (C) 2025 * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +// Constants +const LINK_ICON = '🔗'; +const COPIED_ICON = ' - Copied'; +const ERROR_ICON = '❌'; +const RESET_DELAY = 2000; +const HEADING_SELECTORS = 'h2, h3, h4, h5, h6'; + +// Class to handle heading copy functionality +class HeadingCopyManager +{ + constructor( contentElement ) + { + this.content = contentElement; + this.accessibility = new AccessibilityManager(); + + // Apply to all headings + this.content.querySelectorAll( HEADING_SELECTORS ).forEach( heading => this.createHeadingLink( heading ) ); + } + + // Creates a unique ID for a heading based on its text content + // Parameters: + // text - The heading text + // Returns: A unique ID + generateHeadingId( text ) + { + return text.toLowerCase().replace( /[^a-z0-9]+/g, '-' ); + } + + // Creates a link icon element with proper accessibility attributes + // Returns: The icon element + createIconElement() + { + const icon = this.accessibility.createAccessibleSpan( { text : LINK_ICON, ariaLabel : 'Copy link to heading', className : 'heading-anchor' } ); + return icon; + } + + // Updates the icon appearance based on the copy result + // Parameters: + // icon - The icon element + // success - Whether the copy was successful + // headingText - The text of the heading + updateIconState( icon, success, headingText ) + { + this.accessibility.updateElementState( { + element : icon, + success : success, + successMessage : `Link to ${headingText} copied to clipboard`, + errorMessage : `Failed to copy link to ${headingText}`, + successText : COPIED_ICON, + errorText : ERROR_ICON, + defaultText : LINK_ICON, + resetDelay : RESET_DELAY, + isHtml : true // Use innerHTML for the heading icon + } ); + } + + // Handles the copy functionality for a heading + // Parameters: + // e - The event object + // heading - The heading element + // icon - The icon element + handleCopy( e, heading, icon ) + { + e.preventDefault(); + e.stopPropagation(); + + const url = new URL( window.location.href ); + url.hash = heading.id; + + try { + navigator.clipboard.writeText( url.toString() ) + .then( () => { + this.updateIconState( icon, true, heading.textContent ); + + // Update URL without scrolling + history.pushState( null, null, `#${heading.id}` ); + } ) + .catch( err => { + console.error( 'Failed to copy:', err ); + this.updateIconState( icon, false, heading.textContent ); + } ); + } + catch ( err ) { + console.error( 'Failed to copy:', err ); + this.updateIconState( icon, false, heading.textContent ); + } + } + + // Sets up event listeners for a heading icon + // Parameters: + // icon - The icon element + // heading - The heading element + setupEventListeners( icon, heading ) + { + // Add click event handler + icon.addEventListener( 'click', ( e ) => this.handleCopy( e, heading, icon ) ); + + // Add keyboard event handler + this.accessibility.setupKeyboardEvents( icon, ( e ) => this.handleCopy( e, heading, icon ) ); + } + + // Creates a heading link with proper accessibility attributes + // Parameters: + // heading - The heading element + createHeadingLink( heading ) + { + // Generate ID if needed + if ( !heading.id ) { + heading.id = this.generateHeadingId( heading.textContent ); + } + + // Create icon element + const icon = this.createIconElement(); + + // Add icon to the heading + heading.appendChild( icon ); + + // Set up event listeners + this.setupEventListeners( icon, heading ); + } +} + +// Initialize when the DOM is fully loaded +document.addEventListener( 'DOMContentLoaded', () => { + const content = document.querySelector( '#main_content' ); + if ( content ) { + // Initialize the heading copy manager + new HeadingCopyManager( content ); + } +} ); diff --git a/docs/assets/js/templates.js b/docs/assets/js/templates.js new file mode 100644 index 000000000..e494beffe --- /dev/null +++ b/docs/assets/js/templates.js @@ -0,0 +1,49 @@ +/*************************************************************************** + * fheroes2: https://github.com/ihhub/fheroes2 * + * Copyright (C) 2025 * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +/** + * HTML templates for the heading-copy and code-copy functionality + */ + +// Template for the live region +const liveRegionTemplate = ` +
+`; + +// Template for the heading anchor icon +const headingAnchorTemplate = ` +🔗 +`; + +// Template for the code copy button +const codeCopyButtonTemplate = ` + +`; + +// Export the templates +window.HeadingCopyTemplates = { + liveRegionTemplate, + headingAnchorTemplate +}; + +window.CodeCopyTemplates = { + liveRegionTemplate, + codeCopyButtonTemplate +}; diff --git a/docs/assets/js/theme-toggle.js b/docs/assets/js/theme-toggle.js new file mode 100644 index 000000000..32260ce58 --- /dev/null +++ b/docs/assets/js/theme-toggle.js @@ -0,0 +1,121 @@ +/*************************************************************************** + * fheroes2: https://github.com/ihhub/fheroes2 * + * Copyright (C) 2025 * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +// Theme toggle functionality +class ThemeManager +{ + constructor() + { + this.themeToggle = document.getElementById( "theme-toggle" ); + this.themeKey = "theme"; + this.darkTheme = "dark"; + this.lightTheme = "light"; + this.accessibility = window.AccessibilityManager ? new window.AccessibilityManager() : null; + + this.init(); + } + + init() + { + this.applySavedTheme(); + this.setupEventListeners(); + this.setupAccessibility(); + } + + setTheme( theme, saveToStorage = true ) + { + document.documentElement.setAttribute( "data-theme", theme ); + document.body.setAttribute( "data-theme", theme ); + + // Only save to localStorage if explicitly requested + if ( saveToStorage ) { + localStorage.setItem( this.themeKey, theme ); + } + + // Update button text and ARIA attributes + if ( this.themeToggle ) { + this.themeToggle.textContent = theme === this.darkTheme ? "☀️ Light Mode" : "🌙 Dark Mode"; + + // Update ARIA attributes + this.themeToggle.setAttribute( "aria-label", `Switch to ${theme === this.darkTheme ? this.lightTheme : this.darkTheme} mode` ); + this.themeToggle.setAttribute( "aria-pressed", theme === this.darkTheme ? "true" : "false" ); + + // Announce theme change if accessibility manager is available + if ( this.accessibility ) { + this.accessibility.announce( `${theme === this.darkTheme ? 'Dark' : 'Light'} mode activated` ); + } + } + } + + applySavedTheme() + { + const savedTheme = localStorage.getItem( this.themeKey ); + + if ( savedTheme ) { + this.setTheme( savedTheme ); + } + else { + // Check system preference but don't save it to localStorage + const prefersDark = window.matchMedia( "(prefers-color-scheme: dark)" ).matches; + this.setTheme( prefersDark ? this.darkTheme : this.lightTheme, false ); + } + } + + setupEventListeners() + { + // Add event listener to the toggle button + if ( this.themeToggle ) { + this.themeToggle.addEventListener( "click", () => { + const currentTheme = document.documentElement.getAttribute( "data-theme" ); + this.setTheme( currentTheme === this.darkTheme ? this.lightTheme : this.darkTheme ); + } ); + } + + // Listen for system theme changes + window.matchMedia( "(prefers-color-scheme: dark)" ).addEventListener( "change", ( e ) => { + // Only apply system preference if user hasn't manually set a preference + if ( !localStorage.getItem( this.themeKey ) ) { + this.setTheme( e.matches ? this.darkTheme : this.lightTheme, false ); + } + } ); + } + + setupAccessibility() + { + if ( this.themeToggle ) { + // Set initial ARIA attributes + const currentTheme = document.documentElement.getAttribute( "data-theme" ); + this.themeToggle.setAttribute( "aria-label", `Switch to ${currentTheme === this.darkTheme ? this.lightTheme : this.darkTheme} mode` ); + this.themeToggle.setAttribute( "aria-pressed", currentTheme === this.darkTheme ? "true" : "false" ); + + // Add keyboard event handling + this.themeToggle.addEventListener( "keydown", ( event ) => { + if ( event.key === "Enter" || event.key === " " ) { + event.preventDefault(); + const currentTheme = document.documentElement.getAttribute( "data-theme" ); + this.setTheme( currentTheme === this.darkTheme ? this.lightTheme : this.darkTheme ); + } + } ); + } + } +} + +// Initialize the theme manager when the DOM is loaded +document.addEventListener( "DOMContentLoaded", () => { new ThemeManager(); } ); diff --git a/docs/images/favicon.ico b/docs/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..0e668af38c3fe4c967a1495f8f62af449da7835f GIT binary patch literal 4286 zcmb_f30RX?x;`W(0TReU_JoiHvIjx{*+DRZY_fw0qAWo~aNi4xFrp|_MC^c7YTc@} zSVgU4tHru>YPEKHJAGQ)+H319owl~qJH0dd+)m$n5~efud3v9j+j~!*_s{eH|M}1R zeeXHn_nkwCAN^^y#Cs)21%yZmA!Z8th)kpKKKC{HPQ;zWPLIZC=w{r$P{)4 zCwop)*!tbawH+g80*XCtBrqtGzOz#BDE>d&6grrmB84KIlUh_4zH--zS%c4i)-rMy zs}5a4#h!CtS~ed%<6kh}L;M(1X+Mcy0M~2t|FyB{0A8Qch%_u$I=6kdd+V`3G;BM9 zysCxJ#%H19>`gRmJBHSwaTM=6|3z5$o>8VFE}wp*pn9Spzsdu+V=YfS4JLU4Qrh<^|QBJvOzIS)D;)cd9`=!h@h4dZ% zXZ#A?sp z`~$%X5Ky10u;#+sSa;<%1evQKOI;4-wAD}~HbJh|Lo8RKWyf9|{pbsL#;;=cJHN%c zQ&&;7>v_1E`!Rd{UgSUZ;wRiS{n4_W$BAf3_mA1&H7td1$?r?9?)pxyvtbI=m?w~e z7hQw;=U&5}J6}LsHwabcV^Gi708PeHsKdgc3O8ZL`ByPCaRVEVy?~77wGikX2(Xre z8D0uaVm%hpTxA|Uy#)Z_SY1EHZzQas99{Z?H)3*|z-Dv64Ge@ptVFQA3cBVY?7#Ol zQv1(9>28NMuNx6LYY}d;!5p80Ub-$LD;udE8c1a_nj^v>o!W??=tgjiWvE!b3%Lhh zew+2gX}Ns(G+~<}AGLu+Z(J;ybCI)f^*5oG1h83Cz~}RQ{DP<&NOCuz&RZYBmQxCYPKPj!1`4$f%H$S=BrX9rst!^4E77q3rH7$U zPZa8&d6md^op_X=Pj8Y0=G;B8MJuW1l1bkMe28SB5V__dX4 ze&rUT5;Ng&CBQ;+M1*}Rv?+B^C3zsFwIRq{fb`PEs6KGvbK%ny4%Lxs-}8HuqMac$ zE;PefWUqwKQ4V=%ICOfdtI-UL#fH?{MHqSSQzUs-BDj!8acmb~3LB!PVLS)6`u$T42JZls5=4dDs z^1u7f4-Q62;|f}nE?gj6$Nj}U&v^O0wQ-uno_|>pR|6uB1w-WqJE9ca$XWzPRzXJh z8yZb0jjM2&&1N6J&0K_sk zf}kKC+(k7g*mM3@Wc#>C^7tt)Ki#e}vSiMpx5Sa9AVMcyf756UErh?d%C`n(DlL>s z1ziJrL{J+n77HvkI~Hyo#2C#-$%{sPyx(){3pOJ(b2XG&3**Wjzq5Lu(@1yt_?5(uQ=p6~`%qxY0SPvPghYd(Oa)6f6WoYgNYvqwDK$`Q!(lMl zX&l(#NXy2dH$Onr{>v~GZl-#7!$hH<`4~c{uZB9c6>_Z&Qh6vsBuWGcr7+}|qT}3k z)b4xnGv1bCR@shmum2jt4_i+4; zJE$2x`*ld~vvKkPAHSBcg|(FbORm&F_m$*_V6ecDCxRVbO!rwe2zE6>Otsy7@g1C_ zbASG$Kj7B=|HPSlU*X`#Ut;gg+bCGJ0VS)t&~g4Ix~{y3?XTa#z-u3%cE__cE|;Uc z@A#h;{U_3ull%rhj@YA&srXZXNb^H(pDm2ZIic&4sZ2qDekSDEOK|kV&rrPM1Z?T~ zNGYs4;~4?+jeWT^+w zc=b2>`HL6Gou%J!_{vFsKL%J_A$U?f1e!<)j5EO1W`Ze+1>rj&im$}zyT608wU6dC znxiFR$Y^}a=zoYN3_^P}_(nT|!s5YFPlum89YmG_B1wSAn1!;f&pZskhlcL2WQlX|)W3a< zltn)SgXs@{4x7eSu&?HtW6}|yRfTC~EpXSYMM~vbICEN|au$IlbwQv_MoIUbnYU;R3s5Uc?y}L z$tFB&DXkPy9HurmRvca3XUbY~H>qk95-U3pJE!}BrF`S9u!8lEtFzY?^4+Vo%=DE( zq@X>J)bxaK8vC5eWh2XC+7Dc<+BWuIa|cg-tL{0Tqu%nI*MEN!sC2W$kr$Z)bA~gw zjb=o8>1YYO|z5GMA$LQ2s1Q;aEvA7= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/katex": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.7.tgz", + "integrity": "sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.1.0.tgz", + "integrity": "sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", + "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/katex": { + "version": "0.16.22", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.22.tgz", + "integrity": "sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==", + "dev": true, + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdownlint": { + "version": "0.37.4", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.37.4.tgz", + "integrity": "sha512-u00joA/syf3VhWh6/ybVFkib5Zpj2e5KB/cfCei8fkSRuums6nyisTWGqjTWIOFoFwuXoTBQQiqlB4qFKp8ncQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "markdown-it": "14.1.0", + "micromark": "4.0.1", + "micromark-core-commonmark": "2.0.2", + "micromark-extension-directive": "3.0.2", + "micromark-extension-gfm-autolink-literal": "2.1.0", + "micromark-extension-gfm-footnote": "2.1.0", + "micromark-extension-gfm-table": "2.1.0", + "micromark-extension-math": "3.1.0", + "micromark-util-types": "2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/DavidAnson" + } + }, + "node_modules/markdownlint-cli2": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/markdownlint-cli2/-/markdownlint-cli2-0.17.2.tgz", + "integrity": "sha512-XH06ZOi8wCrtOSSj3p8y3yJzwgzYOSa7lglNyS3fP05JPRzRGyjauBb5UvlLUSCGysMmULS1moxdRHHudV+g/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "globby": "14.0.2", + "js-yaml": "4.1.0", + "jsonc-parser": "3.3.1", + "markdownlint": "0.37.4", + "markdownlint-cli2-formatter-default": "0.0.5", + "micromatch": "4.0.8" + }, + "bin": { + "markdownlint-cli2": "markdownlint-cli2-bin.mjs" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/DavidAnson" + } + }, + "node_modules/markdownlint-cli2-formatter-default": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/markdownlint-cli2-formatter-default/-/markdownlint-cli2-formatter-default-0.0.5.tgz", + "integrity": "sha512-4XKTwQ5m1+Txo2kuQ3Jgpo/KmnG+X90dWt4acufg6HVGadTUG5hzHF/wssp9b5MBYOMCnZ9RMPaU//uHsszF8Q==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/DavidAnson" + }, + "peerDependencies": { + "markdownlint-cli2": ">=0.0.4" + } + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromark": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.1.tgz", + "integrity": "sha512-eBPdkcoCNvYcxQOAKAlceo5SNdzZWfF+FcSupREAzdAh9rRmE239CEQAiTwIgblwnoM8zzj35sZ5ZwvSEOF6Kw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.2.tgz", + "integrity": "sha512-FKjQKbxd1cibWMM1P9N+H8TwlgGgSkWZMmfuVucLCHaYqeSvJ0hFeHsIa65pA2nYbes0f8LDHPMrd9X7Ujxg9w==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-3.0.2.tgz", + "integrity": "sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "parse-entities": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.0.tgz", + "integrity": "sha512-Ub2ncQv+fwD70/l4ou27b4YzfNaCJOvyX4HxXU15m7mpYY+rjuWzsLIPZHJL253Z643RpbcP1oeIJlQ/SKW67g==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-math": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", + "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/katex": "^0.16.0", + "devlop": "^1.0.0", + "katex": "^0.16.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.1.tgz", + "integrity": "sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prettier": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 000000000..5319d20a0 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,12 @@ +{ + "devDependencies": { + "prettier": "3.5.3", + "markdownlint-cli2": "^0.17.2" + }, + "scripts": { + "format-html-css": "prettier --write **/*.{html,scss}", + "format-js": "find . -name \"*.js\" -exec clang-format -i {} \\;", + "lint-md": "npx markdownlint-cli2 --no-globs --config ../.markdownlint-cli2.jsonc", + "format-md": "npx markdownlint-cli2 --fix --no-globs --config ../.markdownlint-cli2.jsonc" + } +} diff --git a/script/macos/Brewfile.dev_tools b/script/macos/Brewfile.dev_tools new file mode 100644 index 000000000..dff3c334b --- /dev/null +++ b/script/macos/Brewfile.dev_tools @@ -0,0 +1,20 @@ +# fheroes2: https://github.com/ihhub/fheroes2 +# Copyright (C) 2025 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +brew "innoextract" +brew "clang-format" diff --git a/script/tools/check_code_format.sh b/script/tools/check_code_format.sh index a051b030a..90e0a2d90 100644 --- a/script/tools/check_code_format.sh +++ b/script/tools/check_code_format.sh @@ -2,7 +2,7 @@ ########################################################################### # fheroes2: https://github.com/ihhub/fheroes2 # -# Copyright (C) 2021 - 2024 # +# Copyright (C) 2021 - 2025 # # # # Copyright 2018 Google LLC # # # @@ -29,7 +29,7 @@ set -e -o pipefail -FILES_TO_CHECK=$(git diff --name-only HEAD^ | (grep -E ".*\.(cpp|cc|c\+\+|cxx|c|h|hpp|java)$" || true) \ +FILES_TO_CHECK=$(git diff --name-only HEAD^ | (grep -E ".*\.(cpp|cc|c\+\+|cxx|c|h|hpp|java|js)$" || true) \ | (grep -v "^src/thirdparty/.*/.*" || true)) if [ -z "$FILES_TO_CHECK" ]; then diff --git a/script/tools/check_copyright_headers.sh b/script/tools/check_copyright_headers.sh index 5146d1850..990ee2635 100644 --- a/script/tools/check_copyright_headers.sh +++ b/script/tools/check_copyright_headers.sh @@ -2,7 +2,7 @@ ########################################################################### # fheroes2: https://github.com/ihhub/fheroes2 # -# Copyright (C) 2022 - 2024 # +# Copyright (C) 2022 - 2025 # # # # This program is free software; you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # @@ -30,7 +30,7 @@ set -e -o pipefail SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}") HEADERS_DIR="$SCRIPT_DIR/copyright_headers" -C_LIKE_FILES_TO_CHECK=$(git diff --name-only HEAD^ | (grep -E ".*\.(cpp|cc|c\+\+|cxx|c|h|hpp|java|rc)$" || true) \ +C_LIKE_FILES_TO_CHECK=$(git diff --name-only HEAD^ | (grep -E ".*\.(cpp|cc|c\+\+|cxx|c|h|hpp|java|rc|js)$" || true) \ | (grep -v "^src/thirdparty/.*/.*" || true)) SCRIPT_FILES_TO_CHECK=$(git diff --name-only HEAD^ | (grep -E ".*(\.(sh|py|ps1)|CMakeLists.txt|Makefile[^/]*|Android.mk|Application.mk)$" || true) \ | (grep -v "^src/thirdparty/.*/.*" || true))