diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index f2fa31594ad..56d82e0519a 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -109,41 +109,6 @@ jobs: run: php monorepo/scripts/tests/${{ matrix.script }}.php - build-hydefront-assets: - - runs-on: ubuntu-latest - needs: run-smoke-tests - - steps: - - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - cache: 'npm' - - - name: Install Node.js dependencies - working-directory: 'packages/hydefront' - run: npm ci - - - name: Build assets for production - working-directory: 'packages/hydefront' - run: npm run prod - - - name: Upload artifacts - uses: actions/upload-artifact@v4 - with: - name: 'hydefront' - path: 'packages/hydefront/dist' - - - name: Commit changes - uses: EndBug/add-and-commit@v9 - with: - add: 'packages/hydefront/dist' - message: 'Compile HydeFront assets for production' - new_branch: compile-hydefront - - build-tailwindcss: runs-on: ubuntu-latest @@ -164,7 +129,7 @@ jobs: run: sed -i 's/\.\/vendor\/hyde\/framework\/resources\/views\/\*\*\/\*\.blade\.php/\.\/packages\/framework\/resources\/views\/\*\*\/\*\.blade\.php/' tailwind.config.js - name: Build assets for production - run: npm run prod + run: npm run build - name: Copy compiled app.css file to HydeFront dist folder run: cp _media/app.css packages/hydefront/dist/app.css diff --git a/.github/workflows/end-to-end-tests.yml b/.github/workflows/end-to-end-tests.yml index 057ae4a1e76..2ec8a249556 100644 --- a/.github/workflows/end-to-end-tests.yml +++ b/.github/workflows/end-to-end-tests.yml @@ -30,7 +30,7 @@ jobs: run: vendor/bin/pest --stop-on-failure - name: Prepare the Environment - run: echo -e "APP_URL=http://localhost:8080 \nDUSK_ENABLED=true\nSERVER_DASHBOARD=false" > .env + run: echo -e "APP_URL=http://localhost:8080 \nDUSK_ENABLED=true\nSERVER_DASHBOARD=false\nSERVER_SAVE_PREVIEW=true" > .env - name: Upgrade Chrome Driver run: php hyde dusk:chrome-driver `/opt/google/chrome/chrome --version | cut -d " " -f3 | cut -d "." -f1` diff --git a/.github/workflows/matrix-tests.yml b/.github/workflows/matrix-tests.yml index ff1f7cdaf14..481bedf5e20 100644 --- a/.github/workflows/matrix-tests.yml +++ b/.github/workflows/matrix-tests.yml @@ -2,7 +2,7 @@ name: Matrix Tests on: pull_request: - branches: [ "master" ] + branches: [ "master", "2.x-dev" ] paths: - 'app/**' - 'packages/**' diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 91eaf200989..096406ad18d 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -2,7 +2,7 @@ name: 🔎 Static Analysis on: pull_request: - branches: [ "master" ] + branches: [ "master", "2.x-dev" ] jobs: diff --git a/.phpstorm.meta.php b/.phpstorm.meta.php index e5e3acca117..db6c871a9b6 100644 --- a/.phpstorm.meta.php +++ b/.phpstorm.meta.php @@ -3,5 +3,7 @@ namespace PHPSTORM_META { override(\app(0), map([ 'hyde' => \Hyde\Foundation\HydeKernel::class, + 'navigation.main' => \Hyde\Framework\Features\Navigation\MainNavigationMenu::class, + 'navigation.sidebar' => \Hyde\Framework\Features\Navigation\DocumentationSidebar::class, ])); } diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 9300bb0087a..7ad10418a8b 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,4 +1,4 @@ -## [Unreleased] - YYYY-MM-DD +## [v2-dev] - YYYY-MM-DD ### About @@ -10,52 +10,652 @@ This serves two purposes: 2. At release time, you can move the Unreleased section changes into a new release version section. ### Added -- Updated the `HydeKernel` array representation to include the Hyde version in https://github.com/hydephp/develop/pull/1786 -- Registered the `cache:clear` command to make it easier to clear the cache in https://github.com/hydephp/develop/pull/1881 -- Added a new `Hyperlinks::isRemote()` helper method to check if a URL is remote in https://github.com/hydephp/develop/pull/1882 -- All page types now support the `description` front matter field (used in page metadata) in https://github.com/hydephp/develop/pull/1884 -- Added a new `Filesystem::findFiles()` method to find files in a directory in https://github.com/hydephp/develop/pull/2064 -- Added `webp` to the list of default media extensions in https://github.com/hydephp/framework/pull/663 -- Added a new slug generation helper to improve internationalization support in https://github.com/hydephp/develop/pull/2070 + +- You can now specify sidebar item priorities by adding a numeric prefix to doc umentation page source file names in https://github.com/hydephp/develop/pull/1709 +- Added support for resolving dynamic links to source files in Markdown documents in https://github.com/hydephp/develop/pull/1590 +- Added a new `\Hyde\Framework\Actions\PreBuildTasks\TransferMediaAssets` build task handle media assets transfers for site builds. +- Added a new `\Hyde\Framework\Exceptions\ParseException` exception class to handle parsing exceptions in data collection files in https://github.com/hydephp/develop/pull/1732 +- Added a new `\Hyde\Framework\Exceptions\InvalidConfigurationException` exception class to handle invalid configuration exceptions in https://github.com/hydephp/develop/pull/1799 +- The `\Hyde\Facades\Features` class is no longer marked as internal, and is now thus part of the public API. +- Added support for setting `booting()` and `booted()` callbacks in `HydeExtension` classes, allowing extension developers to hook into the kernel boot process more easily in https://github.com/hydephp/develop/pull/1847 +- Added support for setting custom navigation items in the YAML configuration in https://github.com/hydephp/develop/pull/1818 +- Added support for setting extra attributes for navigation items in https://github.com/hydephp/develop/pull/1824 +- Added support for setting the blog post publishing date as a prefix in the source file name in https://github.com/hydephp/develop/pull/2000 +- Introduced a new navigation config builder class to simplify navigation configuration in https://github.com/hydephp/develop/pull/1827 +- You can now add custom posts to the blog post feed component when including it directly in https://github.com/hydephp/develop/pull/1893 +- Added a `Feature::fromName()` enum helper in https://github.com/hydephp/develop/pull/1895 +- Added environment variable support for saving previews in https://github.com/hydephp/develop/pull/1996 +- Added support for specifying features in the YAML configuration in https://github.com/hydephp/develop/pull/1896 +- Added Vite as a build tool in https://github.com/hydephp/develop/pull/2010 +- **Added a new consolidated Asset API to better handle media files.** + - Added several new fluent methods to the `MediaFile` class, like `getLink()`, `getLength()`, `getMimeType()`, etc. + - Added new `HydeFront` facade to handle CDN links and Tailwind config injection. + - Added method `Asset::exists()` has to check if a media file exists. + - Added a `Hyde::assets()` method to get all media file instances in the site. +- Added new `npm run build` command for compiling frontend assets with Vite +- Added a Vite HMR support for the realtime compiler in https://github.com/hydephp/develop/pull/2016 +- Added Vite facade in https://github.com/hydephp/develop/pull/2016 +- Added a custom Blade-based heading renderer for Markdown conversions in https://github.com/hydephp/develop/pull/2047 +- The `publish:views` command is now interactive for Unix-like systems in https://github.com/hydephp/develop/pull/2062 ### Changed -- Changed the `Hyde` facade to use a `@mixin` annotation instead of single method annotations in https://github.com/hydephp/develop/pull/1919 -- Updated the `Serializable` trait to provide a default automatic `toArray` method in https://github.com/hydephp/develop/pull/1791 -- Updated the `PostAuthor` class's `name` property to fall back to the `username` property if the `name` property is not set in https://github.com/hydephp/develop/pull/1794 -- Removed the nullable type hint from the `PostAuthor` class's `name` property as it is now always set in https://github.com/hydephp/develop/pull/1794 -- Improved the accessibility of the heading permalinks feature in https://github.com/hydephp/develop/pull/1803 -- The `torchlight:install` command is now hidden from the command list as it's already installed in https://github.com/hydephp/develop/pull/1879 -- Updated the home page fallback link in the 404 template to lead to the site root in https://github.com/hydephp/develop/pull/1880 (fixes https://github.com/hydephp/develop/issues/1781) -- Normalized remote URL checks so that protocol relative URLs `//` are consistently considered to be remote in all places in https://github.com/hydephp/develop/pull/1882 (fixes https://github.com/hydephp/develop/issues/1788) -- Page slugs are now generated using our automatically internationalizing slug generator to transliterate input to ASCII in https://github.com/hydephp/develop/pull/2070 -- Replaced internal usages of glob functions with our improved file finder in https://github.com/hydephp/develop/pull/2064 -- Updated to HydeFront v3.4 in https://github.com/hydephp/develop/pull/1803 -- Realtime Compiler: Virtual routes are now managed through the service container in https://github.com/hydephp/develop/pull/1858 -- Realtime Compiler: Improved the dashboard layout in https://github.com/hydephp/develop/pull/1866 -- Realtime Compiler: Shorten the realtime compiler server start message from "Press Ctrl+C to stop" to "Use Ctrl+C to stop" to better fit 80 column terminals in https://github.com/hydephp/develop/pull/2017 + +- **Breaking:** The internals of the navigation system has been rewritten into a new Navigation API. This change is breaking for custom navigation implementations. For more information, see below. +- **Breaking:** The `hyde.features` configuration format has changed to use Enums instead of static method calls. For more information, see below. +- **Breaking:** Renamed class `DataCollections` to `DataCollection`. For more information, see below. +- **Breaking:** The `hyde.authors` config setting should now be keyed by the usernames. For more information, see below. +- **Breaking:** The `Author::create()` method now returns an array instead of a `PostAuthor` instance. For more information, see below. +- **Breaking:** The `Author::get()` method now returns `null` if an author is not found, rather than creating a new instance. For more information, see below. +- **Breaking:** The custom navigation item configuration now uses array inputs instead of the previous format. For more information, see the upgrade guide below. +- **Breaking:** Renamed the `hyde.navigation.subdirectories` configuration option to `hyde.navigation.subdirectory_display`. +- **Breaking:** Renamed the `hyde.enable_cache_busting` configuration option to `hyde.cache_busting` in https://github.com/hydephp/develop/pull/1980 +- Medium: The `route` function will now throw a `RouteNotFoundException` if the route does not exist in https://github.com/hydephp/develop/pull/1741 +- Minor: Navigation menu items are now no longer filtered by duplicates (meaning two items with the same label can now exist in the same menu) in https://github.com/hydephp/develop/pull/1573 +- Minor: Due to changes in the navigation system, it is possible that existing configuration files will need to be adjusted in order for menus to look the same (in terms of ordering etc.) +- Minor: The documentation article component now supports disabling the semantic rendering using a falsy value in https://github.com/hydephp/develop/pull/1566 +- Minor: Changed the default build task message to make it more concise in https://github.com/hydephp/develop/pull/1659 +- Minor: Data collection files are now validated for syntax errors during discovery in https://github.com/hydephp/develop/pull/1732 +- Minor: Methods in the `Includes` facade now return `HtmlString` objects instead of `string` in https://github.com/hydephp/develop/pull/1738. For more information, see below. +- Minor: `Includes::path()` and `Includes::get()` methods now normalize paths to be basenames to match the behavior of the other include methods in https://github.com/hydephp/develop/pull/1738. This means that nested directories are no longer supported, as you should use a data collection for that. +- Minor: The `processing_time_ms` attribute in the `sitemap.xml` file has now been removed in https://github.com/hydephp/develop/pull/1744 +- Minor: Updated the `Hyde::url()` helper throw a `BadMethodCallException` instead `BaseUrlNotSetException` when no site URL is set and no path was provided to the method in https://github.com/hydephp/develop/pull/1760 and https://github.com/hydephp/develop/pull/1890 +- Minor: Updated the blog post layout and post feed component to use the `BlogPosting` Schema.org type instead of `Article` in https://github.com/hydephp/develop/pull/1887 +- Updated default configuration to no longer save previewed pages in https://github.com/hydephp/develop/pull/1995 +- Added more rich markup data to blog post components in https://github.com/hydephp/develop/pull/1888 (Note that this inevitably changes the HTML output of the blog post components, and that any customized templates will need to be republished to reflect these changes) +- Overhauled the blog post author feature in https://github.com/hydephp/develop/pull/1782 +- Improved the sitemap data generation to be smarter and more dynamic in https://github.com/hydephp/develop/pull/1744 +- Skipped build tasks will now exit with an exit code of 3 instead of 0 in https://github.com/hydephp/develop/pull/1749 +- The `hasFeature` method on the Hyde facade and HydeKernel now only accepts a Feature enum value instead of a string for its parameter. +- Changed how the documentation search is generated, to be an `InMemoryPage` instead of a post-build task. +- Media asset files are now copied using the new build task instead of the deprecated `BuildService::transferMediaAssets()` method. +- Calling the `Include::path()` method will no longer create the includes directory in https://github.com/hydephp/develop/pull/1707 +- Calling the `DataCollection` methods will no longer create the data collections directory in https://github.com/hydephp/develop/pull/1732 +- Markdown includes are now converted to HTML using the custom HydePHP Markdown service, meaning they now support full GFM spec and custom Hyde features like colored blockquotes and code block filepath labels in https://github.com/hydephp/develop/pull/1738 +- Markdown returned from includes are now trimmed of trailing whitespace and newlines in https://github.com/hydephp/develop/pull/1738 +- Reorganized and cleaned up the navigation and sidebar documentation for improved clarity. +- Moved the sidebar documentation to the documentation pages section for better organization. +- The build command now groups together all `InMemoryPage` instances under one progress bar group in https://github.com/hydephp/develop/pull/1897 +- The `Markdown::render()` method will now always render Markdown using the custom HydePHP Markdown service (thus getting smart features like our Markdown processors) in https://github.com/hydephp/develop/pull/1900 +- Improved how the `MarkdownService` class is accessed, by binding it into the service container, in https://github.com/hydephp/develop/pull/1922 +- Improved the media asset transfer build task to have better output in https://github.com/hydephp/develop/pull/1904 +- The full page documentation search now generates it's heading using smarter natural language processing based on the configured sidebar header in https://github.com/hydephp/develop/pull/2032 +- Moved Blade view `hyde::pages.documentation-search` to `hyde::pages.docs.search` in https://github.com/hydephp/develop/pull/2033 +- **Many MediaFile related helpers have been changed or completely rewritten** to provide a simplified API for interacting with media files. + - **Note:** For most end users, the changes will have minimal direct impact, but if you have custom code that interacts with media files, you may need to update it. + - The `Asset` facade has been restructured to be more scoped and easier to use, splitting out a separate `HydeFront` facade and inlining the `AssetService` class. + - All asset retrieval methods now return a `MediaFile` instance, which can be fluently interacted with, or cast to a string to get the link (which was the previous behavior). + - The `Hyde::asset()` method and `asset()` function now return `MediaFile` instances instead of strings, and will throw an exception if the asset does not exist. + - Renamed method `Asset::hasMediaFile` to `Asset::exists` in https://github.com/hydephp/develop/pull/1957 + - Renamed method `MediaFile::getContentLength` to `MediaFile::getLength` in https://github.com/hydephp/develop/pull/1904 + - Replaced method `Hyde::mediaPath` with `MediaFile::sourcePath` in https://github.com/hydephp/develop/pull/1911 + - Replaced method `Hyde::siteMediaPath` with `MediaFile::outputPath` in https://github.com/hydephp/develop/pull/1911 + - We will now throw an exception if you try to get a media file that does not exist in order to prevent missing assets from going unnoticed in https://github.com/hydephp/develop/pull/1932 +- **MediaFile performance improvements:** + - Media assets are now cached in the HydeKernel, giving a massive performance boost and making it easier to access the instances in https://github.com/hydephp/develop/pull/1917 + - Media file metadata is now lazy loaded and then cached in memory, providing performance improvements for files that may not be used in a build in https://github.com/hydephp/develop/pull/1933 + - We now use the much faster `CRC32` hashing algorithm instead of `MD5` for cache busting keys in https://github.com/hydephp/develop/pull/1918 +- **Replaced Laravel Mix with Vite for frontend asset compilation** in https://github.com/hydephp/develop/pull/2010 + - **Breaking:** You must now use `npm run build` to compile your assets, instead of `npm run prod` + - Bundled assets are now compiled directly into the `_media` folder, and will not be copied to the `_site/media` folder by the NPM command in https://github.com/hydephp/develop/pull/2011 +- The realtime compiler now only serves assets from the media source directory (`_media`), and no longer checks the site output directory (`_site/media`) in https://github.com/hydephp/develop/pull/2012 +- **Breaking:** Replaced `--run-dev` and `--run-prod` build command flags with a single `--run-vite` flag that uses Vite to build assets in https://github.com/hydephp/develop/pull/2013 +- Moved the Vite build step to run before the site build to prevent duplicate media asset transfers in https://github.com/hydephp/develop/pull/2013 +- Ported the HydeSearch plugin used for the documentation search to be an Alpine.js implementation in https://github.com/hydephp/develop/pull/2029 + - Renamed Blade component `hyde::components.docs.search-widget` to `hyde::components.docs.search-modal` in https://github.com/hydephp/develop/pull/2029 + - Added support for customizing the search implementation by creating a `resources/js/HydeSearch.js` file in https://github.com/hydephp/develop/pull/2031 +- Normalized default Tailwind Typography Prose code block styles to match Torchlight's theme, ensuring consistent styling across Markdown and Torchlight code blocks in https://github.com/hydephp/develop/pull/2036. +- Extracted CSS component partials in HydeFront in https://github.com/hydephp/develop/pull/2038 +- Replaced HydeFront styles with Tailwind in https://github.com/hydephp/develop/pull/2024 +- Markdown headings are now compiled using our custom Blade-based heading renderer in https://github.com/hydephp/develop/pull/2047 + - The `id` attributes for heading permalinks have been moved from the anchor to the heading element in https://github.com/hydephp/develop/pull/2052 +- Colored Markdown blockquotes are now rendered using Blade and TailwindCSS, this change is not visible in the rendered result, but the HTML output has changed in https://github.com/hydephp/develop/pull/2056 ### Deprecated -- The `PostAuthor::getName()` method is now deprecated and will be removed in v2. (use `$author->name` instead) in https://github.com/hydephp/develop/pull/1794 -- Deprecated the `FeaturedImage::isRemote()` method in favor of the new `Hyperlinks::isRemote()` method in https://github.com/hydephp/develop/pull/1882 -- Deprecated the `Hyde::mediaLink()` method in favor of the `Hyde::asset()` method in https://github.com/hydephp/develop/pull/1993 + +- for soon-to-be removed features. ### Removed -- for now removed features. + +- Breaking: Removed the build task `\Hyde\Framework\Actions\PostBuildTasks\GenerateSearch` (see upgrade guide below) +- Breaking: Removed the deprecated `\Hyde\Framework\Services\BuildService::transferMediaAssets()` method (see upgrade guide below) +- Breaking: Removed the `DocumentationPage::getTableOfContents()` method as we now use Blade to generate the table of contents in https://github.com/hydephp/develop/pull/2045 +- Breaking: Removed the `DocumentationPage::hasTableOfContents()` method as it is now unused by the framework in https://github.com/hydephp/develop/pull/2006 +- Removed the deprecated global `unslash()` function, replaced with the namespaced `\Hyde\unslash()` function in https://github.com/hydephp/develop/pull/1754 +- Removed the deprecated `BaseUrlNotSetException` class, with the `Hyde::url()` helper now throwing `BadMethodCallException` if no base URL is set in https://github.com/hydephp/develop/pull/1760 +- Removed: The deprecated `PostAuthor::getName()` method is now removed (use `$author->name`) in https://github.com/hydephp/develop/pull/1782 +- Internal: Removed the internal `DocumentationSearchPage::generate()` method as it was unused in https://github.com/hydephp/develop/pull/1569 +- Removed the deprecated `FeaturedImage::isRemote()` method in https://github.com/hydephp/develop/pull/1883. Use `Hyperlinks::isRemote()` instead. +- **With the new Asset API, a few features had to be moved/removed:** + - `AssetService` class has been removed (was merged into the `Asset` facade) in https://github.com/hydephp/develop/pull/1908 + - Removed HydeFront methods from the `Asset` facade (moved to the new HydeFront facade) in https://github.com/hydephp/develop/pull/1907 + - The config options `hyde.hydefront_version` and `hyde.hydefront_cdn_url` have been removed in https://github.com/hydephp/develop/pull/1909 (as changing these could lead to incompatible asset versions, defeating the feature's purpose) + - Removed `Hyde::mediaLink()` method replaced by `Hyde::asset()` in https://github.com/hydephp/develop/pull/1932 + - Removed `Hyde::mediaPath()` method replaced by `MediaFile::sourcePath()` in https://github.com/hydephp/develop/pull/1911 + - Removed `Hyde::siteMediaPath()` method replaced by `MediaFile::outputPath()` in https://github.com/hydephp/develop/pull/1911 +- Removed Laravel Mix as a dependency in https://github.com/hydephp/develop/pull/2010 (replaced with Vite) +- **Breaking:** Removed `npm run prod` command (replaced with `npm run build`) +- Removed CDN include for the HydeSearch plugin replaced by Alpine.js implementation in https://github.com/hydephp/develop/pull/2029 + - This also removes the `` and `` Blade components, replaced by the new `` component. +- Removed the `.torchlight-enabled` CSS class in https://github.com/hydephp/develop/pull/2036. +- Removed The `hyde.css` file from HydeFront in https://github.com/hydephp/develop/pull/2037 as all styles were refactored to Tailwind in https://github.com/hydephp/develop/pull/2024. +- Removed the `MarkdownService::withPermalinks` method in https://github.com/hydephp/develop/pull/2047 +- Removed the `MarkdownService::canEnablePermalinks` method in https://github.com/hydephp/develop/pull/2047 ### Fixed -- Fixed Tailwind content paths for nested Blade pages in https://github.com/hydephp/develop/pull/2042 + - Added missing collection key types in Hyde facade method annotations in https://github.com/hydephp/develop/pull/1784 -- Fixed heading permalinks button text showing in Google Search previews https://github.com/hydephp/develop/issues/1801 in https://github.com/hydephp/develop/pull/1803 -- Fixed routing issues with nested 404 pages where an index page does not exist https://github.com/hydephp/develop/issues/1781 in https://github.com/hydephp/develop/pull/1880 -- Fixed URL metadata for blog posts not using customized post output directories in https://github.com/hydephp/develop/pull/1889 -- Fixed lacking support for logographic slug generation https://github.com/hydephp/hyde/issues/269 in https://github.com/hydephp/develop/pull/2070 -- Improved printed documentation views in https://github.com/hydephp/develop/pull/2005 -- Fixed "BuildService finding non-existent files to copy in Debian" https://github.com/hydephp/framework/issues/662 in https://github.com/hydephp/develop/pull/2064 -- Fixed "Undefined constant `Hyde\Foundation\Kernel\GLOB_BRACE`" https://github.com/hydephp/hyde/issues/270 in https://github.com/hydephp/develop/pull/2064 -- Realtime Compiler: Updated the exception handler to match HTTP exception codes when sending error responses in https://github.com/hydephp/develop/pull/1853 -- Realtime Compiler: Improved routing for nested index pages in https://github.com/hydephp/develop/pull/1852 -- Realtime Compiler: Improved the dashboard https://github.com/hydephp/develop/pull/1866 fixing https://github.com/hydephp/realtime-compiler/issues/22 and https://github.com/hydephp/realtime-compiler/issues/29 -- Realtime Compiler: Fixed support for serving media assets in subdirectories https://github.com/hydephp/realtime-compiler/issues/26 in https://github.com/hydephp/develop/pull/1872 +- The `app.js` file will now only be compiled if it has scripts in https://github.com/hydephp/develop/pull/2028 ### Security + - in case of vulnerabilities. + +### Package updates + +#### Realtime Compiler + +- Simplified the asset file locator to only serve files from the media source directory in https://github.com/hydephp/develop/pull/2012 +- Added Vite HMR support in https://github.com/hydephp/develop/pull/2016 + +#### HydeFront + +- Removed all Sass styles after porting everything to Tailwind in https://github.com/hydephp/develop/pull/2024 +- Removed the `hyde.css` file in https://github.com/hydephp/develop/pull/2037 as all its styles were refactored to Tailwind in https://github.com/hydephp/develop/pull/2024 +- Extracted CSS component partials in https://github.com/hydephp/develop/pull/2038 + +### Upgrade Guide + +Please see the "Breaking changes & upgrade guide" section below for more information. + +## Breaking changes & upgrade guide + + + +Please read through this section to ensure your site upgrades smoothly. + +## Before you start + +Before you start, please upgrade your application to at least HydePHP v1.6 as that version contains helpers to make the upgrade process easier. + +## High impact + +### Navigation system rewrite + +The navigation system has been rewritten into a new Navigation API. This change is breaking for custom navigation implementations, see more down below. + +For most users, the only impact will be that configuration files need to be updated to use the new configuration format. Due to the internal changes, +it's also possible that menu items will be in a slightly different order than before, depending on your setup. Please verify that your site's menus +look as expected after upgrading, and adjust the configuration files if necessary, before deploying to production. + +### Navigation and sidebar configuration changes + +The navigation and sidebar configuration files have been updated to use the new Navigation API. +This means that you will need to update your configuration files to use the new format. + +The easiest way to upgrade is to publish updated configuration files (`hyde.php` and `docs.php`) and copy over your customizations. + +The following configuration entries have been updated: + +- Changed configuration option `docs.sidebar_order` to `docs.sidebar.order` in https://github.com/hydephp/develop/pull/1583 +- Upgrade path: Move the `sidebar_order` option's array in the `config/docs.php` file into the `sidebar` array in the same file. + +- Changed configuration option `docs.table_of_contents` to `docs.sidebar.table_of_contents` in https://github.com/hydephp/develop/pull/1584 +- Upgrade path: Move the `table_of_contents` option's array in the `config/docs.php` file into the `sidebar` array in the same file. + +### Features configuration changes + +The `hyde.features` configuration format has changed to use Enums instead of static method calls. This change is breaking as it will require you to update your `config/hyde.php` file. + +#### Instead of + +```php +// filepath: config/hyde.php + +'features' => [ + // Page Modules + Features::htmlPages(), + Features::markdownPosts(), + Features::bladePages(), + Features::markdownPages(), + Features::documentationPages(), + + // Frontend Features + Features::darkmode(), + Features::documentationSearch(), + + // Integrations + Features::torchlight(), +], +``` + +#### Use instead + +```php +// filepath: config/hyde.php + +'features' => [ + // Page Modules + Feature::HtmlPages, + Feature::MarkdownPosts, + Feature::BladePages, + Feature::MarkdownPages, + Feature::DocumentationPages, + + // Frontend Features + Feature::Darkmode, + Feature::DocumentationSearch, + + // Integrations + Feature::Torchlight, +], +``` + +Of course, if you have disabled any of the features, do not include them in the new array. + +## General impact + +### Post Author changes + +This release makes major improvements to the usability and design of the blog post author feature. + +Here is the full list of changes: + +- Breaking: The `hyde.authors` config setting must now be keyed by the usernames, instead of providing the username in the author facade constructor. +- Breaking: The `Author::create()` method now returns an array instead of a `PostAuthor` instance. This only affects custom code that uses the `Author` facade. +- Breaking: The `Author::get()` method now returns `null` if an author is not found, rather than creating a new instance. This only affects custom code that uses the `Author` facade. +- Removed: The deprecated `PostAuthor::getName()` method has been removed (use `$author->name` instead). +- Changed: Author usernames are now automatically normalized (converted to lowercase and spaces replaced with underscores in order to ensure URL routability). +- Changed: If an author display name is not provided, it is now intelligently generated from the username. +- Feature: Authors can now be set in the YAML configuration. +- Feature: Added a `$author->getPosts()` method to get all of an author's posts. +- Feature: Authors now support custom biographies, avatars, and social media links. Note that these are not currently used in any of the default templates, but you can use them in your custom views. +- The collection of site authors is now stored in the HydeKernel, meaning authors can be accessed through `Hyde::authors()`. +- The `PostAuthor` class is now Arrayable and JsonSerializable. + +#### Upgrade guide: + +1. Update your `config/hyde.php` file to use the new author configuration format: + + ```php + 'authors' => [ + 'username' => Author::create( + name: 'Display Name', + website: 'https://example.com', + bio: 'Author bio', + avatar: 'avatar.png', + socials: ['twitter' => '@username'] + ), + ], + ``` + +2. Review and update any code that uses the `Author` facade: + +- The `create()` method now returns an array instead of a `PostAuthor` instance. +- The `get()` method may return `null`, so handle this case in your code. + +3. Check your blog post front matter and ensure that `author` fields match the new username keys in your configuration. + +4. If you have custom templates that use author data, update them to: + +- Optional: Feel free to use the new available fields: `bio`, `avatar`, and `socials`. +- Account for usernames now being lowercase with underscores which may lead to changed HTML or URL paths. + +5. If you were relying on `Author::get()` to create new authors on the fly, update your code to handle `null` returns or create authors explicitly. + +For more information, see https://github.com/hydephp/develop/pull/1782 and https://github.com/hydephp/develop/pull/1798 + +### Documentation search page changes + +The documentation search page and search index have been changed to be generated as `InMemoryPages` instead of a post-build task. + +The main impact noticeable to most users by this is the implicit changes, like the pages showing up in the dashboard and route list command. + +In case you have customized the `GenerateSearch` post-build task you may, depending on what you were trying to do, +want to adapt your code to interact with the new `InMemoryPage`, which is generated in the `HydeCoreExtension` class. + +For more information, see https://github.com/hydephp/develop/pull/1498. + +## Medium impact + +### Features class method renames + +The following methods in the `Features` class have been renamed to follow a more consistent naming convention: + +- `Features::enabled()` has been renamed to `Features::has()` +- `Features::sitemap()` has been renamed to `Features::hasSitemap()` +- `Features::rss()` has been renamed to `Features::hasRss()` + +Note that this class was previously marked as internal in v1, but the change is logged here in case it was used in configuration files or custom code. + +### Asset API Changes + +#### Overview + +For most end users, the changes to the Asset API in HydePHP 2.x will have minimal direct impact. However, if you have custom code that interacts with media files, you may need to update it. + +The most important thing to note is that all asset retrieval methods now return a `MediaFile` instance, which can be fluently interacted with, or cast to a string to get the link (which was the previous behavior). + +#### Side effects to consider + +Regardless of if you need to make changes to your code, there are a few side effects to consider: + +- All cache busting keys will have changed since we changed the hashing algorithm from `MD5` to `CRC32`. +- Media file getters now return MediaFile instances instead of strings. But these can still be used the same way in Blade `{{ }}` tags, as they can be cast to strings. +- Due to the internal normalizations, we will consistently use cache busting keys and use qualified paths when site URLs are set. +- An exception will be thrown if you try to get a media file that does not exist in order to prevent missing assets from going unnoticed. + +These side effects should not have any negative impact on your site, but may cause the generated HTML to look slightly different. + +#### Impact on Your Code + +If you are using strict type declarations, you may need to update your code to expect a `MediaFile` instance instead of a string path; or you should cast the `MediaFile` instance to a string when needed. + +Most changes were made in https://github.com/hydephp/develop/pull/1904 which contains extra information and the reasoning behind the changes. + +#### Updating Your Code + +Once you have determined that you need to update your code, here are the steps you should take: + +1. Update calls to renamed methods: + + ```php + // Replace this: With this: + Hyde::mediaLink('image.png') => Hyde::asset('image.png'); + Asset::mediaLink('image.png') => Asset::get('image.png'); + Asset::hasMediaFile('image.png') => Asset::exists('image.png'); + Asset::cdnLink('app.css') => HydeFront::cdnLink('app.css'); + Asset::injectTailwindConfig() => HydeFront::injectTailwindConfig(); + FeaturedImage::isRemote($source) => Hyperlinks::isRemote($source); + ``` + +2. Rename the option `hyde.enable_cache_busting` to `hyde.cache_busting` in your configuration file. + +3. Remove any references to `hyde.hydefront_version` and `hyde.hydefront_cdn_url` in your config files as these options have been removed. + +4. If you were using `AssetService` directly, refactor your code to use the new `Asset` facade, `MediaFile` class, or `HydeFront` facade as appropriate. + +These changes simplify the Asset API and provide more robust handling of media files. The new `MediaFile` class offers additional functionality for working with assets. + +## Low impact + +### Navigation internal changes + +The navigation system has been rewritten into a new Navigation API. This change is breaking for custom navigation implementations. + +If you have previously in your custom code done any of the following, or similar, you will need to adapt your code to use the new Navigation API: + +- Created custom navigation menus or Blade components +- Extended or called the navigation related classes directly +- Customized the navigation system in any way beyond the standard configuration + +#### Upgrade guide + +Due to the scope of the rewrite, the easiest and fastest way to upgrade your code is to recreate it using the new Navigation API. + +- For a full comparison of the changes, you may see the PR that introduced the new API: https://github.com/hydephp/develop/pull/1568/files +- For information on how to use the new Navigation API, see the documentation: https://hydephp.com/docs/2.x/navigation-api +- If you use DataCollections, you should read the upgrade path below as there are breaking changes to the DataCollection API. + +### HTML ID changes + +Some HTML IDs have been renamed to follow a more consistent naming convention. + +If you have used any of the following selectors in custom code you wrote yourself, you will need to update to use the new changed IDs. + +#### https://github.com/hydephp/develop/pull/1622 + +- Rename HTML ID `#searchMenu` to `#search-menu` +- Rename HTML ID `#searchMenuButton` to `#search-menu-button` +- Rename HTML ID `#searchMenuButtonMobile` to `#search-menu-button-mobile` + +### New documentation search implementation + +As the new documentation search implementation brings changes to their code API you may need to adapt your code +according to the information below in case you wrote custom code that interacted with these parts of the codebase. + +- The `GenerateSearch` post-build task has been removed. If you have previously extended or customized this class, + you will need to adapt your code, as the search index files are now handled implicitly during the standard build process, + as the search pages are now added to the kernel page and route collection. (https://github.com/hydephp/develop/pull/1498) + +- If your site has a custom documentation search page, for example `_docs/search.md` or `_pages/docs/search.blade.php`, + that page will no longer be built when using the specific `build:search` command. It will, of course, + be built using the standard `build` command. https://github.com/hydephp/develop/commit/82dc71f4a0e7b6be7a9f8d822fbebe39d2289ced + +- In the highly unlikely event your site customizes any of the search pages by replacing them in the kernel route collection, + you would now need to do that in the kernel page collection due to the search pages being generated earlier in the lifecycle. + https://github.com/hydephp/develop/commit/82dc71f4a0e7b6be7a9f8d822fbebe39d2289ced + +### Media asset transfer implementation changes + +The internals of how media asset files are copied during the build process have been changed. For most users, this change +has no impact. However, if you have previously extended this method, or called it directly from your custom code, +you will need to adapt your code to use the new `TransferMediaAssets` build task. + +For example, if you triggered the media transfer with a build service method call, use the new build task instead: + +```php +(new BuildService)->transferMediaAssets(); + +(new TransferMediaAssets())->run(); +``` + +### Includes facade changes + +The following methods in the `Includes` facade now return `HtmlString` objects instead of `string`: + +- `Includes::html()` +- `Includes::blade()` +- `Includes::markdown()` + +- This means that you no longer need to use `{!! !!}` to render the output of these methods in Blade templates, instead just use `{{ }}`. +- If you have used the return value of these methods in custom code, you may need to adjust your code to work with the new return type. + +For more information, see the RFC that proposed this change: https://github.com/hydephp/develop/issues/1734 +The RFC was implemented in https://github.com/hydephp/develop/pull/1738 + +#### Remember to escape output if necessary + +**Note:** Remember that this means that includes are **no longer escaped** by default, so make sure to escape the output if necessary, for example if the content is user-generated. + +- (Use `{{ e(Includes::html('foo')) }}` instead of `{{ Includes::html('foo') }}` to escape the output, matching the previous behavior.) + +### DataCollection API changes + +The DataCollection feature has been reworked to improve the developer experience and make it more consistent with the rest of the API. + +Unfortunately, this means that existing setups may need to be adjusted to work with the new API. + +#### Upgrade guide + +- The `DataCollections` class has been renamed to `DataCollection`. If you have used the `DataCollections` class in your code, you will need to update your code to use the new class name. + +#### Changes + +- Calling the `DataCollection` methods will no longer create the data collections directory automatically. +- The `DataCollection` class now validates the syntax of all data collection files during discovery, and throws a `ParseException` if the syntax is invalid. + +#### Issues that may arise + +If you start getting a `ParseException` when using the `DataCollection` class, it may be due to malformed data collection files. +Starting from this version, we validate the syntax of JSON and YAML in data files during discovery, including any front matter in Markdown data files. +We do this to help you catch errors early. See https://github.com/hydephp/develop/issues/1736 for more information. + +For example, an empty or malformed JSON file will now throw an exception like this: + +```php +\Hyde\Framework\Exceptions\ParseException: Invalid JSON in file: 'foo/baz.json' (Syntax error) +``` + +In order to normalize the thrown exceptions, we now rethrow the `ParseException` from `Symfony/Yaml` as our custom `ParseException` to match the JSON and Markdown validation. +Additionally, an exception will be thrown if a data file is empty, as this is unlikely to be intentional. Markdown files can have an empty body if front matter is present. + +### Removal of `FeaturedImage::isRemote()` method + +The `FeaturedImage::isRemote()` method has been removed in v2.0. This method was deprecated in v1.8.0 and has now been completely removed. + +#### Upgrade guide + +If you were using `FeaturedImage::isRemote()` in your code, you should replace it with `Hyperlinks::isRemote()`. Here's how to update your code: + +```php +// Old code +FeaturedImage::isRemote($source); + +// New code +use Hyde\Foundation\Kernel\Hyperlinks; + +Hyperlinks::isRemote($source); +``` + +This change was implemented in https://github.com/hydephp/develop/pull/1883. Make sure to update any instances of `FeaturedImage::isRemote()` in your codebase to ensure compatibility with HydePHP v2.0. + +## New Asset System + +### Abstract + +The new asset system is a complete rewrite of the HydeFront asset handling system, replacing Laravel Mix with Vite, and favouring Blade-based components with Tailwind classes over CSS partials and custom stylesheets. + +### Enhancements + +- **Replaced Laravel Mix with Vite for frontend asset compilation.** ([#2010], [#2011], [#2012], [#2013], [#2016], [#2021]) + - Bundled assets are now compiled directly into the `_media` folder. + - The realtime compiler now only serves assets from the media source directory (`_media`). + - Added a new `npm run build` command for compiling frontend assets with Vite. + - Added Vite facade for Blade templates. + - Added Vite Hot Module Replacement (HMR) support to the realtime compiler. + - Build command now uses Vite to compile assets when the `--run-vite` flag is passed. + +- **Improved HydeFront integration.** ([#2024], [#2029], [#2031], [#2036], [#2037], [#2038], [#2039]) + - HydeFront styles are now refactored into Tailwind. + - HydeFront now acts as a component library with granular Tailwind styles in `app.css`. + - HydeSearch plugin ported to Alpine.js, improving performance and customizability. + - Normalized Tailwind Typography Prose code block styles to match Torchlight. + - Extracted CSS component partials in HydeFront. + - Removed `hyde.css` from HydeFront, as all styles are now included in `app.css`. + +- **Implemented a custom Blade-based heading renderer for Markdown.** ([#2047], [#2052]) + - Improves permalink handling and customization options. + - `id` attributes for heading permalinks have been moved from the anchor to the heading element. +- **Colored Markdown blockquotes are now rendered using Blade and Tailwind CSS.** ([#2056]) +- The `app.js` file will now only be compiled if it has scripts. ([#2028]) + + +### Breaking Changes + +- Replaced Laravel Mix with Vite. ([#2010]) + - You must now use `npm run build` to compile your assets, instead of `npm run prod`. +- Removed `--run-dev` and `--run-prod` build command flags, replaced by `--run-vite`. ([#2013]) +- Removed `DocumentationPage::getTableOfContents()` method. Table of contents are now generated using a Blade component. ([#2045]) +- Removed `hyde.css` from HydeFront, requiring recompilation of assets if you were extending it. ([#2037]) +- Changed how HydeFront is included in projects. Instead of separate `hyde.css` and `app.css`, all styles are now in `app.css`. ([#2024]) + + +### Removals + +- Removed Laravel Mix as a dependency. ([#2010]) +- Removed `npm run prod` command. ([#2010]) +- Removed CDN include for HydeSearch plugin. ([#2029]) +- Removed the `` and `` Blade components, replaced by ``. ([#2029]) +- Removed the `.torchlight-enabled` CSS class. ([#2036]) +- Removed the `MarkdownService::withPermalinks` and `MarkdownService::canEnablePermalinks` methods. ([#2047]) + + +### Blade-based table of contents generator + +The way we generate table of contents for documentation pages have been changed from a helper method to a Blade component. + +This new system is much easier to customize and style, and is up to 40 times faster than the old system. + +See https://github.com/hydephp/develop/pull/2045 for more information. + +#### Scope + +The likelihood of impact is low, but if any of the following are true, you may need to update your code: + +- If you have used the `Hyde\Framework\Actions\GeneratesTableOfContents` class in custom code, you will likely need to update that code for the rewritten class. +- If you have published the `resources/views/components/docs/sidebar-item.blade.php` component, you will need to update it to call the new component instead of the old generator rendering. +- If you have called the now removed `getTableOfContents` method of the `DocumentationPage` class in custom code, you will need to update that usage as to possibly call the new Blade component directly, depending on your use case. +- If you have called the now removed `hasTableOfContents` method of the `DocumentationPage` class in custom code you will need to replace the method call with `Config::getBool('docs.sidebar.table_of_contents.enabled', true)` + +#### Changes +- Adds a new `resources/views/components/docs/table-of-contents.blade.php` component containing the structure and styles for the table of contents +- Rewrites the `GeneratesTableOfContents` class to use a custom implementation instead of using CommonMark +- The `execute` method of the `GeneratesTableOfContents` class now returns an array of data, instead of a string of HTML. This data should be fed into the new component +- Removed the `table-of-contents.css` file as styles are now made using Tailwind +- Removed the `heading-permalinks.css` file as styles are now made using Tailwind +- Removed the `blockquotes.css` file as styles are now made using Tailwind + +## New features + + + +### Navigation configuration changes + +The custom navigation item configuration format has been updated to use array inputs. This change allows for more flexibility and consistency in defining navigation items. + +#### Old format: + +```php +'navigation' => [ + 'custom_items' => [ + 'Custom Item' => '/custom-page', + ], +], +``` + +#### New format: + +```php +'navigation' => [ + 'custom_items' => [ + ['label' => 'Custom Item', 'destination' => '/custom-page'], + ], +], +``` + +Additionally, the `hyde.navigation.subdirectories` configuration option has been renamed to `hyde.navigation.subdirectory_display`. Update your configuration files accordingly. + +### YAML configuration for navigation items + +You can now set custom navigation items directly in your YAML configuration files. This provides an alternative to defining them in the PHP configuration files. + +Example: + +```yaml +navigation: + custom_items: + - label: Custom Item + destination: /custom-page +``` + +### Extra attributes for navigation items + +Navigation items now support extra attributes, allowing you to add custom data or styling to your navigation elements. You can set these attributes in both PHP and YAML configurations. + +Example in PHP: + +```php +'navigation' => [ + 'custom_items' => [ + [ + 'label' => 'Custom Item', + 'destination' => '/custom-page', + 'attributes' => ['class' => 'special-link', 'target' => '_blank'], + ], + ], +], +``` + +Example in YAML: + +```yaml +navigation: + custom_items: + - label: Custom Item + destination: /custom-page + attributes: + class: special-link + target: _blank +``` + +These changes provide more flexibility and control over your site's navigation structure. Make sure to update your configuration files and any custom code that interacts with navigation items to align with these new formats and features. diff --git a/_ide_helper.php b/_ide_helper.php index 7d868d7bbb5..88203364b33 100644 --- a/_ide_helper.php +++ b/_ide_helper.php @@ -22,20 +22,25 @@ /** @var string $routeKey The route key for the page being compiled/previewed */ $routeKey = \Hyde\Support\Facades\Render::getRouteKey(); +// Variables available only to some page types + +/** @var \Hyde\Framework\Features\Navigation\DocumentationSidebar $sidebar */ +$sidebar = app('navigation.sidebar'); + // Facades (aliased in app/config.php) /** @mixin \Hyde\Foundation\HydeKernel */ class Hyde extends \Hyde\Hyde {} class Site extends \Hyde\Facades\Site {} class Meta extends \Hyde\Facades\Meta {} -/** @mixin \Hyde\Framework\Services\AssetService */ class Asset extends \Hyde\Facades\Asset {} class Author extends \Hyde\Facades\Author {} class Features extends \Hyde\Facades\Features {} class Config extends \Hyde\Facades\Config {} +class Vite extends \Hyde\Facades\Vite {} /** @mixin \Illuminate\Filesystem\Filesystem */ class Filesystem extends \Hyde\Facades\Filesystem {} -class DataCollections extends \Hyde\Support\DataCollections {} +class DataCollection extends \Hyde\Support\DataCollection {} class Includes extends \Hyde\Support\Includes {} /** @mixin \Hyde\Foundation\Kernel\RouteCollection */ class Routes extends \Hyde\Foundation\Facades\Routes {} diff --git a/_media/app.css b/_media/app.css index e18eeec73b8..fa7fcb7bb09 100644 --- a/_media/app.css +++ b/_media/app.css @@ -1,4 +1 @@ -/*! HydeFront v3.4.1 | MIT License | https://hydephp.com*/.hyde-search-context{margin-bottom:10px}.hyde-search-results{margin-top:1.25em;max-height:60vh;overflow-y:auto}#search-status{margin-top:0}#sidebar-toggle{display:inline-block;height:2rem;position:relative;width:2rem}#sidebar-toggle span.icon-bar{background-color:#000;display:block;height:2.375px;left:5.5px;position:absolute;transition:all .3s ease-out;width:20px}#sidebar-toggle span.icon-bar:first-child{top:9px}#sidebar-toggle span.icon-bar:nth-child(2),#sidebar-toggle span.icon-bar:nth-child(3){top:15px;transform-origin:center}#sidebar-toggle span.icon-bar:last-child{top:21px}#sidebar-toggle.active span.icon-bar:first-child{opacity:0}#sidebar-toggle.active span.icon-bar:nth-child(2){transform:rotate(45deg)}#sidebar-toggle.active span.icon-bar:nth-child(3){transform:rotate(-45deg)}#sidebar-toggle.active span.icon-bar:last-child{opacity:0}.dark #sidebar-toggle span.icon-bar{background-color:#fff;height:2px}.table-of-contents{padding-bottom:.75rem}.table-of-contents>li{margin-bottom:.35rem;margin-top:.15rem}.table-of-contents ul{padding-left:.5rem}.table-of-contents a{display:block;margin-left:-2rem;opacity:.825;padding-left:2rem}.table-of-contents a:before{content:"#";font-size:75%;margin-right:4px;opacity:.5;transition:opacity .3s ease-in-out}.table-of-contents a:hover{background-color:hsla(0,0%,50%,.2);opacity:1;transition:opacity,background .3s ease-in-out}.table-of-contents a:hover:before{opacity:1}#hyde-docs .prose h1,#hyde-docs .prose h2,#hyde-docs .prose h3,#hyde-docs .prose h4,#hyde-docs .prose h5,#hyde-docs .prose h6{width:-moz-fit-content;width:fit-content}#hyde-docs .prose h1:focus .heading-permalink,#hyde-docs .prose h1:hover .heading-permalink,#hyde-docs .prose h2:focus .heading-permalink,#hyde-docs .prose h2:hover .heading-permalink,#hyde-docs .prose h3:focus .heading-permalink,#hyde-docs .prose h3:hover .heading-permalink,#hyde-docs .prose h4:focus .heading-permalink,#hyde-docs .prose h4:hover .heading-permalink,#hyde-docs .prose h5:focus .heading-permalink,#hyde-docs .prose h5:hover .heading-permalink,#hyde-docs .prose h6:focus .heading-permalink,#hyde-docs .prose h6:hover .heading-permalink{filter:grayscale(100%);opacity:.75;transition:opacity .1s ease-out}#hyde-docs .prose h1 .heading-permalink,#hyde-docs .prose h2 .heading-permalink,#hyde-docs .prose h3 .heading-permalink,#hyde-docs .prose h4 .heading-permalink,#hyde-docs .prose h5 .heading-permalink,#hyde-docs .prose h6 .heading-permalink{margin-left:.25rem;opacity:0;padding:0 .25rem;scroll-margin:1rem;transition:opacity .3s ease}#hyde-docs .prose h1 .heading-permalink:before,#hyde-docs .prose h2 .heading-permalink:before,#hyde-docs .prose h3 .heading-permalink:before,#hyde-docs .prose h4 .heading-permalink:before,#hyde-docs .prose h5 .heading-permalink:before,#hyde-docs .prose h6 .heading-permalink:before{content:"#"}#hyde-docs .prose h1 .heading-permalink:focus,#hyde-docs .prose h1 .heading-permalink:hover,#hyde-docs .prose h2 .heading-permalink:focus,#hyde-docs .prose h2 .heading-permalink:hover,#hyde-docs .prose h3 .heading-permalink:focus,#hyde-docs .prose h3 .heading-permalink:hover,#hyde-docs .prose h4 .heading-permalink:focus,#hyde-docs .prose h4 .heading-permalink:hover,#hyde-docs .prose h5 .heading-permalink:focus,#hyde-docs .prose h5 .heading-permalink:hover,#hyde-docs .prose h6 .heading-permalink:focus,#hyde-docs .prose h6 .heading-permalink:hover{filter:unset;opacity:1}html{scroll-behavior:smooth}.torchlight-enabled pre{border-radius:.25rem;margin-bottom:1rem;margin-top:1rem;overflow-x:auto;padding:0}.torchlight-enabled pre code.torchlight{display:block;min-width:-moz-max-content;min-width:max-content;padding-bottom:1rem;padding-top:1rem}.torchlight-enabled pre code.torchlight .line{padding-left:1rem;padding-right:1rem}.torchlight-enabled pre code.torchlight .line-number,.torchlight-enabled pre code.torchlight .summary-caret{margin-right:1rem}.prose blockquote.info{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity,1))}.prose blockquote.success{--tw-border-opacity:1;border-color:rgb(34 197 94/var(--tw-border-opacity,1))}.prose blockquote.warning{--tw-border-opacity:1;border-color:rgb(245 158 11/var(--tw-border-opacity,1))}.prose blockquote.danger{--tw-border-opacity:1;border-color:rgb(220 38 38/var(--tw-border-opacity,1))}code{max-width:80vw;overflow-x:auto;vertical-align:top;word-break:break-all}pre code{display:block;max-width:unset}pre>code>.filepath{float:right;opacity:.5;position:relative;right:.25rem;top:-.25rem;transition:opacity .25s}pre>code>.filepath:hover{opacity:1}.torchlight-enabled pre>code>.filepath{right:1rem}@media screen and (max-width:767px){pre>code>.filepath{display:none}}@media screen and (min-width:768px){[x-cloak].x-uncloak-md{display:revert!important}}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start} -*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: } - -/*! tailwindcss v3.4.15 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}:host,html{-webkit-text-size-adjust:100%;font-feature-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-variation-settings:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-feature-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em;font-variation-settings:normal}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{font-feature-settings:inherit;color:inherit;font-family:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;letter-spacing:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.prose{color:var(--tw-prose-body);max-width:96ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-bottom:1.2em;margin-top:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:#5956eb;font-weight:500;text-decoration:none}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)):hover{color:#4f46e5}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-bottom:1.25em;margin-top:1.25em;padding-inline-start:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-bottom:1.25em;margin-top:1.25em;padding-inline-start:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-counters);font-weight:400}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-bottom:3em;margin-top:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:#80808020;border-inline-start-color:var(--tw-prose-quote-borders);border-inline-start-width:.25rem;border-left-color:#d1d5db;color:unset;font-style:unset;font-weight:500;line-height:1.25em;margin-bottom:1em;margin-top:1em;padding-bottom:.25em;padding-inline-start:1em;padding-left:.75em;padding-top:.25em;quotes:"\201C""\201D""\2018""\2019"}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)) p{margin-bottom:.25em;margin-top:.25em;padding-right:.25em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)) p:before{content:unset}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)) p:after{content:unset}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-size:2.25em;font-weight:800;line-height:1.1111111;margin-bottom:.8888889em;margin-top:0}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:900}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.5em;font-weight:700;line-height:1.3333333;margin-bottom:.75em;margin-top:1.5em}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:800}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.25em;font-weight:600;line-height:1.6;margin-bottom:.6em;margin-top:1.6em}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;line-height:1.5;margin-bottom:.5em;margin-top:1.5em}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-bottom:2em;margin-top:2em}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:.3125rem;box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows)/10%),0 3px 0 rgb(var(--tw-prose-kbd-shadows)/10%);color:var(--tw-prose-kbd);font-family:inherit;font-size:.875em;font-weight:500;padding-inline-end:.375em;padding-bottom:.1875em;padding-top:.1875em;padding-inline-start:.375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:#80808033;border-radius:4px;color:var(--tw-prose-code);font-size:.875em;font-weight:600;font:unset;margin-left:-2px;margin-right:1px;padding-left:4px;padding-right:4px}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:unset}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:unset}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:var(--tw-prose-pre-bg);border-radius:.375rem;color:var(--tw-prose-pre-code);font-size:.875em;font-weight:400;line-height:1.7142857;margin-bottom:1.7142857em;margin-top:1.7142857em;overflow-x:auto;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-top:.8571429em;padding-inline-start:1.1428571em}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)) code{font-family:Fira Code Regular,Consolas,Monospace,Courier New}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-radius:0;border-width:0;color:inherit;font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;padding:0}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em;line-height:1.7142857;margin-bottom:2em;margin-top:2em;table-layout:auto;width:100%}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-color:var(--tw-prose-th-borders);border-bottom-width:1px}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em;vertical-align:bottom}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-color:var(--tw-prose-td-borders);border-bottom-width:1px}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-color:var(--tw-prose-th-borders);border-top-width:1px}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-kbd:#111827;--tw-prose-kbd-shadows:17 24 39;--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:255 255 255;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:rgba(0,0,0,.5);--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.5em}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.5em;margin-top:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-top:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.sr-only{clip:rect(0,0,0,0);border-width:0;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.visible{visibility:visible}.invisible{visibility:hidden}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.-left-64{left:-16rem}.bottom-0{bottom:0}.bottom-4{bottom:1rem}.left-0{left:0}.left-80{left:20rem}.right-0{right:0}.right-4{right:1rem}.top-0{top:0}.top-16{top:4rem}.top-4{top:1rem}.top-auto{top:auto}.z-10{z-index:10}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.float-right{float:right}.float-left{float:left}.m-2{margin:.5rem}.m-8{margin:2rem}.-mx-4{margin-left:-1rem;margin-right:-1rem}.mx-0{margin-left:0;margin-right:0}.mx-3{margin-left:.75rem;margin-right:.75rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-8{margin-left:2rem;margin-right:2rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0{margin-bottom:0;margin-top:0}.my-1{margin-bottom:.25rem;margin-top:.25rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-3{margin-bottom:.75rem;margin-top:.75rem}.my-4{margin-bottom:1rem;margin-top:1rem}.my-8{margin-bottom:2rem;margin-top:2rem}.my-auto{margin-bottom:auto;margin-top:auto}.-mb-2{margin-bottom:-.5rem}.-ml-2{margin-left:-.5rem}.-ml-4{margin-left:-1rem}.-ml-6{margin-left:-1.5rem}.-ml-8{margin-left:-2rem}.mb-0{margin-bottom:0}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-8{margin-bottom:2rem}.ml-4{margin-left:1rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-4{margin-right:1rem}.mr-auto{margin-right:auto}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-8{margin-top:2rem}.mt-auto{margin-top:auto}.block{display:block}.inline{display:inline}.flex{display:flex}.contents{display:contents}.hidden{display:none}.h-0{height:0}.h-1{height:.25rem}.h-16{height:4rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-8{height:2rem}.h-auto{height:auto}.h-full{height:100%}.h-screen{height:100vh}.max-h-\[75vh\]{max-height:75vh}.min-h-\[300px\]{min-height:300px}.min-h-\[calc\(100vh_-_4rem\)\]{min-height:calc(100vh - 4rem)}.min-h-screen{min-height:100vh}.w-1{width:.25rem}.w-16{width:4rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-\[70ch\]{width:70ch}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-screen{width:100vw}.max-w-3xl{max-width:48rem}.max-w-7xl{max-width:80rem}.max-w-\[1000px\]{max-width:1000px}.max-w-full{max-width:100%}.max-w-lg{max-width:32rem}.max-w-sm{max-width:24rem}.max-w-xs{max-width:20rem}.flex-shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-auto{cursor:auto}.cursor-pointer{cursor:pointer}.list-none{list-style-type:none}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-hidden{overflow-y:hidden}.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border-2{border-width:2px}.border-4{border-width:4px}.border-y{border-top-width:1px}.border-b,.border-y{border-bottom-width:1px}.border-b-4{border-bottom-width:4px}.border-l-4{border-left-width:4px}.border-l-\[0\.325rem\]{border-left-width:.325rem}.border-t{border-top-width:1px}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity,1))}.border-indigo-400{--tw-border-opacity:1;border-color:rgb(129 140 248/var(--tw-border-opacity,1))}.border-indigo-500{--tw-border-opacity:1;border-color:rgb(89 86 235/var(--tw-border-opacity,1))}.border-transparent{border-color:transparent}.border-yellow-400{--tw-border-opacity:1;border-color:rgb(250 204 21/var(--tw-border-opacity,1))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity,1))}.bg-black\/5{background-color:rgba(0,0,0,.05)}.bg-black\/50{background-color:rgba(0,0,0,.5)}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity,1))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.bg-cover{background-size:cover}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.bg-no-repeat{background-repeat:no-repeat}.fill-black{fill:#000}.fill-current{fill:currentColor}.p-12{padding:3rem}.p-2{padding:.5rem}.p-4{padding:1rem}.px-0{padding-left:0;padding-right:0}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0{padding-bottom:0;padding-top:0}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-12{padding-bottom:3rem;padding-top:3rem}.py-16{padding-bottom:4rem;padding-top:4rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-24{padding-bottom:6rem;padding-top:6rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.py-32{padding-bottom:8rem;padding-top:8rem}.py-4{padding-bottom:1rem;padding-top:1rem}.py-8{padding-bottom:2rem;padding-top:2rem}.pb-12{padding-bottom:3rem}.pb-3{padding-bottom:.75rem}.pl-2{padding-left:.5rem}.pl-4{padding-left:1rem}.pl-5{padding-left:1.25rem}.pl-8{padding-left:2rem}.pt-3{padding-top:.75rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.font-sans{font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-5xl{font-size:3rem;line-height:1}.text-\[90\%\]{font-size:90%}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.font-black{font-weight:900}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-light{font-weight:300}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-10{line-height:2.5rem}.leading-4{line-height:1rem}.leading-8{line-height:2rem}.leading-normal{line-height:1.5}.leading-relaxed{line-height:1.625}.tracking-normal{letter-spacing:0}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity,1))}.text-gray-100{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity,1))}.text-gray-200{--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity,1))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.text-indigo-500{--tw-text-opacity:1;color:rgb(89 86 235/var(--tw-text-opacity,1))}.text-indigo-600{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity,1))}.text-transparent{color:transparent}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-50{opacity:.5}.opacity-75{opacity:.75}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.drop-shadow-2xl{--tw-drop-shadow:drop-shadow(0 25px 25px rgba(0,0,0,.15));filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-all{transition-duration:.15s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-colors{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-300{transition-duration:.3s}.duration-75{transition-duration:75ms}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}[x-cloak]{display:none!important}.dark\:prose-invert:is(.dark *){--tw-prose-body:var(--tw-prose-invert-body);--tw-prose-headings:var(--tw-prose-invert-headings);--tw-prose-lead:var(--tw-prose-invert-lead);--tw-prose-links:var(--tw-prose-invert-links);--tw-prose-bold:var(--tw-prose-invert-bold);--tw-prose-counters:var(--tw-prose-invert-counters);--tw-prose-bullets:var(--tw-prose-invert-bullets);--tw-prose-hr:var(--tw-prose-invert-hr);--tw-prose-quotes:var(--tw-prose-invert-quotes);--tw-prose-quote-borders:var(--tw-prose-invert-quote-borders);--tw-prose-captions:var(--tw-prose-invert-captions);--tw-prose-kbd:var(--tw-prose-invert-kbd);--tw-prose-kbd-shadows:var(--tw-prose-invert-kbd-shadows);--tw-prose-code:var(--tw-prose-invert-code);--tw-prose-pre-code:var(--tw-prose-invert-pre-code);--tw-prose-pre-bg:var(--tw-prose-invert-pre-bg);--tw-prose-th-borders:var(--tw-prose-invert-th-borders);--tw-prose-td-borders:var(--tw-prose-invert-td-borders)}.dark\:prose-invert:is(.dark *) :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:#818cf8}.dark\:prose-invert:is(.dark *) :where(a):not(:where([class~=not-prose],[class~=not-prose] *)):hover{color:#6366f1}.hover\:bg-black\/10:hover{background-color:rgba(0,0,0,.1)}.hover\:bg-black\/5:hover{background-color:rgba(0,0,0,.05)}.hover\:text-gray-700:hover{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.hover\:text-gray-900:hover{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.focus\:not-sr-only:focus{clip:auto;height:auto;margin:0;overflow:visible;padding:0;position:static;white-space:normal;width:auto}.focus\:absolute:focus{position:absolute}.focus\:mx-auto:focus{margin-left:auto;margin-right:auto}.focus\:mt-2:focus{margin-top:.5rem}.focus\:w-64:focus{width:16rem}.focus\:p-2:focus{padding:.5rem}.group:hover .group-hover\:opacity-100{opacity:1}.prose-h1\:mb-3 :is(:where(h1):not(:where([class~=not-prose],[class~=not-prose] *))){margin-bottom:.75rem}.prose-p\:my-3 :is(:where(p):not(:where([class~=not-prose],[class~=not-prose] *))){margin-bottom:.75rem;margin-top:.75rem}.prose-img\:inline :is(:where(img):not(:where([class~=not-prose],[class~=not-prose] *))){display:inline}.dark\:block:is(.dark *){display:block}.dark\:hidden:is(.dark *){display:none}.dark\:border-\[\#1b2533\]:is(.dark *){--tw-border-opacity:1;border-color:rgb(27 37 51/var(--tw-border-opacity,1))}.dark\:border-gray-700:is(.dark *){--tw-border-opacity:1;border-color:rgb(55 65 81/var(--tw-border-opacity,1))}.dark\:bg-black\/10:is(.dark *){background-color:rgba(0,0,0,.1)}.dark\:bg-gray-700:is(.dark *){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity,1))}.dark\:bg-gray-800:is(.dark *){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}.dark\:bg-gray-900:is(.dark *){--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}.dark\:bg-white:is(.dark *){--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.dark\:fill-gray-200:is(.dark *){fill:#e5e7eb}.dark\:fill-white:is(.dark *){fill:#fff}.dark\:font-medium:is(.dark *){font-weight:500}.dark\:text-gray-100:is(.dark *){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity,1))}.dark\:text-gray-200:is(.dark *){--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity,1))}.dark\:text-indigo-400:is(.dark *){--tw-text-opacity:1;color:rgb(129 140 248/var(--tw-text-opacity,1))}.dark\:text-white:is(.dark *){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.dark\:hover\:bg-black\/10:hover:is(.dark *){background-color:rgba(0,0,0,.1)}.dark\:hover\:text-white:hover:is(.dark *){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.group:hover .dark\:group-hover\:text-white:is(.dark *){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}@media (min-width:640px){.sm\:mb-0{margin-bottom:0}.sm\:mt-4{margin-top:1rem}.sm\:flex{display:flex}.sm\:leading-none{line-height:1}.sm\:shadow-xl{--tw-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}}@media (min-width:768px){.md\:visible{visibility:visible}.md\:left-0{left:0}.md\:left-64{left:16rem}.md\:top-0{top:0}.md\:mx-2{margin-left:.5rem;margin-right:.5rem}.md\:my-0{margin-bottom:0;margin-top:0}.md\:my-6{margin-bottom:1.5rem;margin-top:1.5rem}.md\:mb-12{margin-bottom:3rem}.md\:ml-0{margin-left:0}.md\:mt-0{margin-top:0}.md\:mt-8{margin-top:2rem}.md\:block{display:block}.md\:inline-block{display:inline-block}.md\:flex{display:flex}.md\:hidden{display:none}.md\:min-h-screen{min-height:100vh}.md\:w-1\/2{width:50%}.md\:w-\[calc\(100vw_-_16rem\)\]{width:calc(100vw - 16rem)}.md\:w-auto{width:auto}.md\:max-w-2xl{max-width:42rem}.md\:max-w-none{max-width:none}.md\:flex-grow{flex-grow:1}.md\:flex-grow-0{flex-grow:0}.md\:items-center{align-items:center}.md\:border-none{border-style:none}.md\:bg-transparent{background-color:transparent}.md\:bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.md\:bg-left{background-position:0}.md\:px-16{padding-left:4rem;padding-right:4rem}.md\:py-0{padding-bottom:0;padding-top:0}.md\:py-16{padding-bottom:4rem;padding-top:4rem}.md\:pb-0{padding-bottom:0}.md\:pl-0{padding-left:0}.md\:text-center{text-align:center}.md\:text-3xl{font-size:1.875rem;line-height:2.25rem}.md\:text-4xl{font-size:2.25rem;line-height:2.5rem}.md\:text-5xl{font-size:3rem;line-height:1}.md\:text-6xl{font-size:3.75rem;line-height:1}.md\:shadow-none{--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.dark\:md\:bg-transparent:is(.dark *){background-color:transparent}}@media (min-width:1024px){.lg\:mb-12{margin-bottom:3rem}.lg\:ml-8{margin-left:2rem}.lg\:bg-center{background-position:50%}.lg\:text-5xl{font-size:3rem;line-height:1}.lg\:text-7xl{font-size:4.5rem;line-height:1}.lg\:text-lg{font-size:1.125rem;line-height:1.75rem}}@media (min-width:1280px){.xl\:mb-16{margin-bottom:4rem}}@media print{.print\:top-0{top:0}.print\:hidden{display:none}} +pre code.torchlight .line-number,pre code.torchlight .summary-caret{margin-right:1rem}.prose .torchlight-link,.torchlight-link{text-decoration-line:underline}.torchlight.has-focus-lines .line:not(.line-focus){transition:filter .35s,opacity .35s;filter:blur(.095rem);opacity:.65}.torchlight.has-focus-lines:hover .line:not(.line-focus){filter:blur(0px);opacity:1}.torchlight summary:focus{outline:2px solid transparent;outline-offset:2px}.torchlight details>summary::marker,.torchlight details>summary::-webkit-details-marker{display:none}.torchlight details .summary-caret:after{pointer-events:none}.torchlight .summary-caret-empty:after,.torchlight details .summary-caret-middle:after,.torchlight details .summary-caret-end:after{content:" "}.torchlight details[open] .summary-caret-start:after{content:"-"}.torchlight details:not([open]) .summary-caret-start:after{content:"+"}.torchlight details[open] .summary-hide-when-open{display:none}.torchlight details:not([open]) .summary-hide-when-open{display:block}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.prose{color:var(--tw-prose-body);max-width:96ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:#5956eb;text-decoration:none;font-weight:500}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)):hover{color:#4f46e5}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{font-weight:400;color:var(--tw-prose-counters)}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-style:unset;color:unset;border-inline-start-width:.25rem;border-inline-start-color:var(--tw-prose-quote-borders);quotes:"“""”""‘""’";margin-top:1em;margin-bottom:1em;padding-inline-start:1em;background-color:#80808020;border-left-color:#d1d5db;line-height:1.25em;padding-left:.75em;padding-top:.25em;padding-bottom:.25em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)) p{padding-right:.25em;margin-top:.25em;margin-bottom:.25em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)) p:before{content:unset}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)) p:after{content:unset}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:900;color:inherit}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:700;font-size:1.5em;margin-top:1.5em;margin-bottom:.75em;line-height:1.3333333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:800;color:inherit}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-top:2em;margin-bottom:2em}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-family:inherit;color:var(--tw-prose-kbd);box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%),0 3px rgb(var(--tw-prose-kbd-shadows) / 10%);font-size:.875em;border-radius:.3125rem;padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;padding-inline-start:.375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-weight:600;font-size:.875em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:unset}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:unset}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:#292d3e;overflow-x:auto;font-weight:400;font-size:.875em;line-height:1.7142857;margin-top:1rem;margin-bottom:1rem;border-radius:.25rem;padding-top:.8571429em;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-inline-start:1.1428571em}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)) code{font-family:"Fira Code Regular",Consolas,Monospace,"Courier New"}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-width:0;border-radius:0;padding:0;font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){width:100%;table-layout:auto;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;vertical-align:bottom;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body: #374151;--tw-prose-headings: #111827;--tw-prose-lead: #4b5563;--tw-prose-links: #111827;--tw-prose-bold: #111827;--tw-prose-counters: #6b7280;--tw-prose-bullets: #d1d5db;--tw-prose-hr: #e5e7eb;--tw-prose-quotes: #111827;--tw-prose-quote-borders: #e5e7eb;--tw-prose-captions: #6b7280;--tw-prose-kbd: #111827;--tw-prose-kbd-shadows: 17 24 39;--tw-prose-code: #111827;--tw-prose-pre-code: #e5e7eb;--tw-prose-pre-bg: #1f2937;--tw-prose-th-borders: #d1d5db;--tw-prose-td-borders: #e5e7eb;--tw-prose-invert-body: #d1d5db;--tw-prose-invert-headings: #fff;--tw-prose-invert-lead: #9ca3af;--tw-prose-invert-links: #fff;--tw-prose-invert-bold: #fff;--tw-prose-invert-counters: #9ca3af;--tw-prose-invert-bullets: #4b5563;--tw-prose-invert-hr: #374151;--tw-prose-invert-quotes: #f3f4f6;--tw-prose-invert-quote-borders: #374151;--tw-prose-invert-captions: #9ca3af;--tw-prose-invert-kbd: #fff;--tw-prose-invert-kbd-shadows: 255 255 255;--tw-prose-invert-code: #fff;--tw-prose-invert-pre-code: #d1d5db;--tw-prose-invert-pre-bg: rgb(0 0 0 / 50%);--tw-prose-invert-th-borders: #4b5563;--tw-prose-invert-td-borders: #374151;font-size:1rem;line-height:1.5em}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.5714286em;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose :where(code:not(pre code)):not(:where([class~=not-prose],[class~=not-prose] *)){font:unset;background-color:#80808033;padding-left:4px;padding-right:4px;margin-left:-2px;margin-right:1px;border-radius:4px;max-width:80vw;overflow-x:auto;vertical-align:top;word-break:break-all}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.visible{visibility:visible}.invisible{visibility:hidden}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{top:0;right:0;bottom:0;left:0}.-left-64{left:-16rem}.-top-1{top:-.25rem}.bottom-0{bottom:0}.bottom-4{bottom:1rem}.left-0{left:0}.left-80{left:20rem}.right-0{right:0}.right-1{right:.25rem}.right-3{right:.75rem}.right-4{right:1rem}.top-0{top:0}.top-16{top:4rem}.top-2\.5{top:.625rem}.top-4{top:1rem}.top-auto{top:auto}.z-10{z-index:10}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.float-right{float:right}.float-left{float:left}.m-2{margin:.5rem}.m-8{margin:2rem}.-mx-4{margin-left:-1rem;margin-right:-1rem}.mx-0{margin-left:0;margin-right:0}.mx-3{margin-left:.75rem;margin-right:.75rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-8{margin-left:2rem;margin-right:2rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0{margin-top:0;margin-bottom:0}.my-0\.5{margin-top:.125rem;margin-bottom:.125rem}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.my-8{margin-top:2rem;margin-bottom:2rem}.my-auto{margin-top:auto;margin-bottom:auto}.-ml-2{margin-left:-.5rem}.-ml-4{margin-left:-1rem}.-ml-6{margin-left:-1.5rem}.-ml-8{margin-left:-2rem}.-mt-4{margin-top:-1rem}.mb-0{margin-bottom:0}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.mb-8{margin-bottom:2rem}.ml-1{margin-left:.25rem}.ml-4{margin-left:1rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-4{margin-right:1rem}.mr-auto{margin-right:auto}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-8{margin-top:2rem}.mt-auto{margin-top:auto}.\!block{display:block!important}.block{display:block}.inline{display:inline}.flex{display:flex}.contents{display:contents}.hidden{display:none}.h-0\.5{height:.125rem}.h-1{height:.25rem}.h-16{height:4rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-8{height:2rem}.h-auto{height:auto}.h-full{height:100%}.h-screen{height:100vh}.max-h-\[60vh\]{max-height:60vh}.max-h-\[75vh\]{max-height:75vh}.min-h-\[300px\]{min-height:300px}.min-h-\[calc\(100vh_-_4rem\)\]{min-height:calc(100vh - 4rem)}.min-h-screen{min-height:100vh}.w-1{width:.25rem}.w-16{width:4rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-8{width:2rem}.w-\[70ch\]{width:70ch}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-screen{width:100vw}.max-w-3xl{max-width:48rem}.max-w-7xl{max-width:80rem}.max-w-\[1000px\]{max-width:1000px}.max-w-full{max-width:100%}.max-w-lg{max-width:32rem}.max-w-sm{max-width:24rem}.flex-shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.origin-center{transform-origin:center}.-rotate-45{--tw-rotate: -45deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-45{--tw-rotate: 45deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-auto{cursor:auto}.cursor-pointer{cursor:pointer}.scroll-mt-2{scroll-margin-top:.5rem}.list-none{list-style-type:none}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-4{gap:1rem}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-hidden{overflow-y:hidden}.scroll-smooth{scroll-behavior:smooth}.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border-2{border-width:2px}.border-4{border-width:4px}.border-y{border-top-width:1px;border-bottom-width:1px}.border-b{border-bottom-width:1px}.border-l-4{border-left-width:4px}.border-l-\[0\.325rem\]{border-left-width:.325rem}.border-t{border-top-width:1px}.border-amber-500{--tw-border-opacity: 1;border-color:rgb(245 158 11 / var(--tw-border-opacity, 1))}.border-blue-500{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1))}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}.border-gray-500{--tw-border-opacity: 1;border-color:rgb(107 114 128 / var(--tw-border-opacity, 1))}.border-green-500{--tw-border-opacity: 1;border-color:rgb(34 197 94 / var(--tw-border-opacity, 1))}.border-indigo-500{--tw-border-opacity: 1;border-color:rgb(89 86 235 / var(--tw-border-opacity, 1))}.border-red-600{--tw-border-opacity: 1;border-color:rgb(220 38 38 / var(--tw-border-opacity, 1))}.border-transparent{border-color:transparent}.border-yellow-400{--tw-border-opacity: 1;border-color:rgb(250 204 21 / var(--tw-border-opacity, 1))}.border-t-transparent{border-top-color:transparent}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.bg-black\/5{background-color:#0000000d}.bg-black\/50{background-color:#00000080}.bg-current{background-color:currentColor}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.bg-gray-200{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.bg-slate-100{--tw-bg-opacity: 1;background-color:rgb(241 245 249 / var(--tw-bg-opacity, 1))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-yellow-400{--tw-bg-opacity: 1;background-color:rgb(250 204 21 / var(--tw-bg-opacity, 1))}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.bg-cover{background-size:cover}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.bg-no-repeat{background-repeat:no-repeat}.fill-black{fill:#000}.fill-current{fill:currentColor}.p-0{padding:0}.p-12{padding:3rem}.p-2{padding:.5rem}.p-4{padding:1rem}.px-0{padding-left:0;padding-right:0}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0{padding-top:0;padding-bottom:0}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-24{padding-top:6rem;padding-bottom:6rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-32{padding-top:8rem;padding-bottom:8rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-12{padding-bottom:3rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pl-2{padding-left:.5rem}.pl-4{padding-left:1rem}.pl-5{padding-left:1.25rem}.pl-8{padding-left:2rem}.pt-3{padding-top:.75rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.font-sans{font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji"}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-5xl{font-size:3rem;line-height:1}.text-\[75\%\]{font-size:75%}.text-\[90\%\]{font-size:90%}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.font-black{font-weight:900}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-light{font-weight:300}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-10{line-height:2.5rem}.leading-8{line-height:2rem}.leading-normal{line-height:1.5}.leading-relaxed{line-height:1.625}.tracking-normal{letter-spacing:0em}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity, 1))}.text-gray-100{--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}.text-gray-200{--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity, 1))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.text-indigo-500{--tw-text-opacity: 1;color:rgb(89 86 235 / var(--tw-text-opacity, 1))}.text-indigo-600{--tw-text-opacity: 1;color:rgb(79 70 229 / var(--tw-text-opacity, 1))}.text-transparent{color:transparent}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-75{opacity:.75}.opacity-80{opacity:.8}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-none{--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.drop-shadow-2xl{--tw-drop-shadow: drop-shadow(0 25px 25px rgb(0 0 0 / .15));filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-300{transition-duration:.3s}.duration-75{transition-duration:75ms}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-linear{transition-timing-function:linear}.dark\:prose-invert:is(.dark *){--tw-prose-body: var(--tw-prose-invert-body);--tw-prose-headings: var(--tw-prose-invert-headings);--tw-prose-lead: var(--tw-prose-invert-lead);--tw-prose-links: var(--tw-prose-invert-links);--tw-prose-bold: var(--tw-prose-invert-bold);--tw-prose-counters: var(--tw-prose-invert-counters);--tw-prose-bullets: var(--tw-prose-invert-bullets);--tw-prose-hr: var(--tw-prose-invert-hr);--tw-prose-quotes: var(--tw-prose-invert-quotes);--tw-prose-quote-borders: var(--tw-prose-invert-quote-borders);--tw-prose-captions: var(--tw-prose-invert-captions);--tw-prose-kbd: var(--tw-prose-invert-kbd);--tw-prose-kbd-shadows: var(--tw-prose-invert-kbd-shadows);--tw-prose-code: var(--tw-prose-invert-code);--tw-prose-pre-code: var(--tw-prose-invert-pre-code);--tw-prose-pre-bg: var(--tw-prose-invert-pre-bg);--tw-prose-th-borders: var(--tw-prose-invert-th-borders);--tw-prose-td-borders: var(--tw-prose-invert-td-borders)}.dark\:prose-invert:is(.dark *) :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:#818cf8}.dark\:prose-invert:is(.dark *) :where(a):not(:where([class~=not-prose],[class~=not-prose] *)):hover{color:#6366f1}.hover\:bg-black\/10:hover{background-color:#0000001a}.hover\:bg-black\/5:hover{background-color:#0000000d}.hover\:bg-gray-200\/20:hover{background-color:#e5e7eb33}.hover\:text-gray-700:hover{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.hover\:text-gray-900:hover{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.focus\:not-sr-only:focus{position:static;width:auto;height:auto;padding:0;margin:0;overflow:visible;clip:auto;white-space:normal}.focus\:absolute:focus{position:absolute}.focus\:mx-auto:focus{margin-left:auto;margin-right:auto}.focus\:mt-2:focus{margin-top:.5rem}.focus\:w-64:focus{width:16rem}.focus\:p-2:focus{padding:.5rem}.focus\:opacity-100:focus{opacity:1}.focus\:grayscale-0:focus{--tw-grayscale: grayscale(0);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.group:hover .group-hover\:opacity-100{opacity:1}.group:hover .group-hover\:grayscale-0{--tw-grayscale: grayscale(0);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.prose-h1\:mb-3 :is(:where(h1):not(:where([class~=not-prose],[class~=not-prose] *))){margin-bottom:.75rem}.prose-p\:my-3 :is(:where(p):not(:where([class~=not-prose],[class~=not-prose] *))){margin-top:.75rem;margin-bottom:.75rem}.prose-img\:inline :is(:where(img):not(:where([class~=not-prose],[class~=not-prose] *))){display:inline}.dark\:block:is(.dark *){display:block}.dark\:hidden:is(.dark *){display:none}.dark\:border-\[\#1b2533\]:is(.dark *){--tw-border-opacity: 1;border-color:rgb(27 37 51 / var(--tw-border-opacity, 1))}.dark\:border-gray-700:is(.dark *){--tw-border-opacity: 1;border-color:rgb(55 65 81 / var(--tw-border-opacity, 1))}.dark\:bg-black\/10:is(.dark *){background-color:#0000001a}.dark\:bg-gray-700:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity, 1))}.dark\:bg-gray-800:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.dark\:bg-gray-900:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(17 24 39 / var(--tw-bg-opacity, 1))}.dark\:bg-yellow-300:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(253 224 71 / var(--tw-bg-opacity, 1))}.dark\:fill-gray-200:is(.dark *){fill:#e5e7eb}.dark\:fill-white:is(.dark *){fill:#fff}.dark\:font-medium:is(.dark *){font-weight:500}.dark\:text-gray-100:is(.dark *){--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}.dark\:text-gray-200:is(.dark *){--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity, 1))}.dark\:text-gray-300:is(.dark *){--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.dark\:text-gray-400:is(.dark *){--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.dark\:text-indigo-400:is(.dark *){--tw-text-opacity: 1;color:rgb(129 140 248 / var(--tw-text-opacity, 1))}.dark\:text-white:is(.dark *){--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.dark\:hover\:bg-black\/10:hover:is(.dark *){background-color:#0000001a}.dark\:hover\:text-white:hover:is(.dark *){--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.group:hover .dark\:group-hover\:text-white:is(.dark *){--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}@media (min-width: 640px){.sm\:mb-0{margin-bottom:0}.sm\:mt-4{margin-top:1rem}.sm\:block{display:block}.sm\:leading-none{line-height:1}.sm\:shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}}@media (min-width: 768px){.md\:visible{visibility:visible}.md\:left-0{left:0}.md\:left-64{left:16rem}.md\:top-0{top:0}.md\:mx-2{margin-left:.5rem;margin-right:.5rem}.md\:my-0{margin-top:0;margin-bottom:0}.md\:my-6{margin-top:1.5rem;margin-bottom:1.5rem}.md\:mb-12{margin-bottom:3rem}.md\:ml-0{margin-left:0}.md\:mt-0{margin-top:0}.md\:mt-8{margin-top:2rem}.md\:block{display:block}.md\:inline-block{display:inline-block}.md\:flex{display:flex}.md\:hidden{display:none}.md\:min-h-screen{min-height:100vh}.md\:w-1\/2{width:50%}.md\:w-\[calc\(100vw_-_16rem\)\]{width:calc(100vw - 16rem)}.md\:w-auto{width:auto}.md\:max-w-2xl{max-width:42rem}.md\:max-w-none{max-width:none}.md\:flex-grow{flex-grow:1}.md\:flex-grow-0{flex-grow:0}.md\:items-center{align-items:center}.md\:border-none{border-style:none}.md\:bg-transparent{background-color:transparent}.md\:bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.md\:bg-left{background-position:left}.md\:px-16{padding-left:4rem;padding-right:4rem}.md\:py-0{padding-top:0;padding-bottom:0}.md\:py-16{padding-top:4rem;padding-bottom:4rem}.md\:pb-0{padding-bottom:0}.md\:pl-0{padding-left:0}.md\:text-center{text-align:center}.md\:text-3xl{font-size:1.875rem;line-height:2.25rem}.md\:text-4xl{font-size:2.25rem;line-height:2.5rem}.md\:text-5xl{font-size:3rem;line-height:1}.md\:text-6xl{font-size:3.75rem;line-height:1}.md\:shadow-none{--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.dark\:md\:bg-transparent:is(.dark *){background-color:transparent}}@media (min-width: 1024px){.lg\:mb-12{margin-bottom:3rem}.lg\:ml-8{margin-left:2rem}.lg\:bg-center{background-position:center}.lg\:text-5xl{font-size:3rem;line-height:1}.lg\:text-7xl{font-size:4.5rem;line-height:1}.lg\:text-lg{font-size:1.125rem;line-height:1.75rem}}@media (min-width: 1280px){.xl\:mb-16{margin-bottom:4rem}}@media print{.print\:top-0{top:0}.print\:hidden{display:none}} diff --git a/app/config.php b/app/config.php index 79c7e5e871a..26156665112 100644 --- a/app/config.php +++ b/app/config.php @@ -73,6 +73,7 @@ Hyde\Foundation\Providers\ConfigurationServiceProvider::class, Hyde\Framework\HydeServiceProvider::class, Hyde\Foundation\Providers\ViewServiceProvider::class, + Hyde\Foundation\Providers\NavigationServiceProvider::class, Hyde\Console\ConsoleServiceProvider::class, ], @@ -91,18 +92,22 @@ 'Hyde' => Hyde\Hyde::class, 'Site' => \Hyde\Facades\Site::class, 'Meta' => \Hyde\Facades\Meta::class, + 'Vite' => \Hyde\Facades\Vite::class, 'Asset' => \Hyde\Facades\Asset::class, 'Author' => \Hyde\Facades\Author::class, + 'HydeFront' => \Hyde\Facades\HydeFront::class, 'Features' => \Hyde\Facades\Features::class, 'Config' => \Hyde\Facades\Config::class, 'Filesystem' => \Hyde\Facades\Filesystem::class, + 'Navigation' => \Hyde\Facades\Navigation::class, 'Routes' => \Hyde\Foundation\Facades\Routes::class, 'HtmlPage' => \Hyde\Pages\HtmlPage::class, 'BladePage' => \Hyde\Pages\BladePage::class, 'MarkdownPage' => \Hyde\Pages\MarkdownPage::class, 'MarkdownPost' => \Hyde\Pages\MarkdownPost::class, 'DocumentationPage' => \Hyde\Pages\DocumentationPage::class, - 'DataCollections' => \Hyde\Support\DataCollections::class, + 'MediaFile' => \Hyde\Support\Filesystem\MediaFile::class, + 'DataCollection' => \Hyde\Support\DataCollection::class, 'Includes' => \Hyde\Support\Includes::class, 'Feature' => \Hyde\Enums\Feature::class, ], diff --git a/config/docs.php b/config/docs.php index fab400e973d..4ac1dd70706 100644 --- a/config/docs.php +++ b/config/docs.php @@ -30,49 +30,49 @@ // When using a grouped sidebar, should the groups be collapsible? 'collapsible' => true, - // Should the sidebar footer be shown? You can also set this to a string - // of Markdown to show in the footer. Set to `false` to disable. - 'footer' => true, - ], - - /* - |-------------------------------------------------------------------------- - | Sidebar Page Order - |-------------------------------------------------------------------------- - | - | In the generated Documentation pages the navigation links in the sidebar - | default to sort alphabetically. You can reorder the page identifiers - | in the list below, and the links will get sorted in that order. - | - | The items will get a priority of 500 plus the order its found in the list. - | Pages without a priority will fall back to the default priority of 999. - | - | You can also set explicit priorities in front matter or by specifying - | a value to the array key in the list to override the inferred value. - | - */ - - 'sidebar_order' => [ - 'readme', - 'installation', - 'getting-started', - ], - - /* - |-------------------------------------------------------------------------- - | Table of Contents Settings - |-------------------------------------------------------------------------- - | - | The Hyde Documentation Module comes with a fancy Sidebar that, by default, - | has a Table of Contents included. Here, you can configure its behavior, - | content, look and feel. You can also disable the feature completely. - | - */ + // A string of Markdown to show in the footer. Set to `false` to disable. + 'footer' => '[Back to home page](../)', + + /* + |-------------------------------------------------------------------------- + | Sidebar Page Order + |-------------------------------------------------------------------------- + | + | In the generated Documentation pages the navigation links in the sidebar + | default to sort alphabetically. You can reorder the page identifiers + | in the list below, and the links will get sorted in that order. + | + | The items will get a priority of 500 plus the order its found in the list. + | Pages without a priority will fall back to the default priority of 999. + | + | You can also set explicit priorities in front matter or by specifying + | a value to the array key in the list to override the inferred value. + | + */ + + 'order' => [ + 'readme', + 'installation', + 'getting-started', + ], + + /* + |-------------------------------------------------------------------------- + | Table of Contents Settings + |-------------------------------------------------------------------------- + | + | The Hyde Documentation Module comes with a fancy Sidebar that, by default, + | has a Table of Contents included. Here, you can configure its behavior, + | content, look and feel. You can also disable the feature completely. + | + */ + + 'table_of_contents' => [ + 'enabled' => true, + 'min_heading_level' => 2, + 'max_heading_level' => 4, + ], - 'table_of_contents' => [ - 'enabled' => true, - 'min_heading_level' => 2, - 'max_heading_level' => 4, ], /* diff --git a/config/hyde.php b/config/hyde.php index 3d41f7da554..3a4bdf7b9b8 100644 --- a/config/hyde.php +++ b/config/hyde.php @@ -23,8 +23,9 @@ */ use Hyde\Facades\Author; -use Hyde\Enums\Feature; use Hyde\Facades\Meta; +use Hyde\Enums\Feature; +use Hyde\Facades\Navigation; return [ @@ -248,7 +249,6 @@ | | Some of Hyde's features are optional. Feel free to disable the features | you don't need by removing or commenting them out from this array. - | This config concept is directly inspired by Laravel Jetstream. | */ @@ -278,17 +278,26 @@ | However, it's tedious to have to add those to each and every | post you make, and keeping them updated is even harder. | - | Here you can add predefined authors. When writing posts, - | just specify the username in the front matter, and the - | rest of the data will be pulled from a matching entry. + | To solve this problem, you can add predefined authors with this setting. + | When writing posts just specify the author's username (the array key). + | Hyde will pull the matching data from here and fill in the blanks. | */ 'authors' => [ - Author::create( - 'mr_hyde', // Required username - 'Mr. Hyde', // Optional display name - 'https://hydephp.com' // Optional website URL + 'mr_hyde' => Author::create( + // The following settings are used in the default blog post template. + name: 'Mr. Hyde', // Optional display name + website: 'https://hydephp.com', // Optional website URL + + // The following settings are not used in the bundled templates, + // but you can use them in your own custom views, for example. + // bio: 'The mysterious author of HydePHP', + // avatar: 'avatar.png', + // socials: [ + // 'twitter' => 'HydeFramework', + // 'github' => 'hydephp', + // ], ), ], @@ -323,58 +332,39 @@ | */ - 'navigation' => [ - // This configuration sets the priorities used to determine the order of the menu. - // The default values have been added below for reference and easy editing. - // The array key is the page's route key, the value is the priority. - // Lower values show up first in the menu. The default is 999. - 'order' => [ + 'navigation' => Navigation::configure() + ->setPagePriorities([ 'index' => 0, 'posts' => 10, 'docs/index' => 100, - ], - - // In case you want to customize the labels for the menu items, you can do so here. - // Simply add the route key as the array key, and the label as the value. - 'labels' => [ + ]) + ->setPageLabels([ 'index' => 'Home', 'docs/index' => 'Docs', - ], - - // These are the route keys of pages that should not show up in the navigation menu. - 'exclude' => [ + ]) + ->excludePages([ '404', - ], - - // Any extra links you want to add to the navigation menu can be added here. - // To get started quickly, you can uncomment the defaults here. - // See the documentation link above for more information. - 'custom' => [ - // NavItem::forLink('https://github.com/hydephp/hyde', 'GitHub', 200), - ], - - // How should pages in subdirectories be displayed in the menu? - // You can choose between 'dropdown', 'flat', and 'hidden'. - 'subdirectories' => 'hidden', - ], + ]) + ->addNavigationItems([ + // Navigation::item('https://github.com/hydephp/hyde', 'GitHub', 200), + ]) + ->setSubdirectoryDisplayMode('hidden'), /* |-------------------------------------------------------------------------- | Cache Busting |-------------------------------------------------------------------------- | - | Any assets loaded using the Asset::mediaLink() helper will automatically - | have a cache busting query string appended to the URL. This is useful + | Any assets loaded using the Hyde Asset helpers will automatically have + | a "cache busting" query string appended to the URL. This is useful | when you want to force browsers to load a new version of an asset. + | All included Blade templates use this feature to load assets. | - | The mediaLink helper is used in the built-in views to load the - | default stylesheets and scripts, and thus use this feature. - | - | To disable cache busting, set this setting to false. + | To disable the cache busting, set this setting to false. | */ - 'enable_cache_busting' => true, + 'cache_busting' => true, /* |-------------------------------------------------------------------------- @@ -433,7 +423,7 @@ 'host' => env('SERVER_HOST', 'localhost'), // Should preview pages be saved to the output directory? - 'save_preview' => true, + 'save_preview' => env('SERVER_SAVE_PREVIEW', false), // Should the live edit feature be enabled? 'live_edit' => env('SERVER_LIVE_EDIT', true), @@ -477,11 +467,6 @@ // Where should the build manifest be saved? (Relative to project root, for example _site/build-manifest.json) 'build_manifest_path' => 'app/storage/framework/cache/build-manifest.json', - // Here you can specify HydeFront version and URL for when loading app.css from the CDN. - // Only change these if you know what you're doing as some versions may be incompatible with your Hyde version. - 'hydefront_version' => \Hyde\Framework\Services\AssetService::HYDEFRONT_VERSION, - 'hydefront_cdn_url' => \Hyde\Framework\Services\AssetService::HYDEFRONT_CDN_URL, - // Should the theme toggle buttons be displayed in the layouts? 'theme_toggle_buttons' => true, diff --git a/config/markdown.php b/config/markdown.php index 0ec940714ab..cd9afdea0e5 100644 --- a/config/markdown.php +++ b/config/markdown.php @@ -95,4 +95,22 @@ */ 'prose_classes' => 'prose dark:prose-invert', + + /* + |-------------------------------------------------------------------------- + | Heading Permalinks Configuration + |-------------------------------------------------------------------------- + | + | Here you can specify which page classes should have heading permalinks. + | By default, only documentation pages have permalinks enabled, but you + | are free to enable it for any kind of page by adding the page class. + | + */ + + 'permalinks' => [ + 'pages' => [ + \Hyde\Pages\DocumentationPage::class, + ], + ], + ]; diff --git a/docs/_data/partials/hyde-pages-api/documentation-page-methods.md b/docs/_data/partials/hyde-pages-api/documentation-page-methods.md index a22aa0bc815..31b50835012 100644 --- a/docs/_data/partials/hyde-pages-api/documentation-page-methods.md +++ b/docs/_data/partials/hyde-pages-api/documentation-page-methods.md @@ -19,14 +19,6 @@ No description provided. DocumentationPage::homeRouteName(): string ``` -#### `hasTableOfContents()` - -No description provided. - -```php -DocumentationPage::hasTableOfContents(): bool -``` - #### `getOnlineSourcePath()` No description provided. @@ -35,14 +27,6 @@ No description provided. $page->getOnlineSourcePath(): string|false ``` -#### `getTableOfContents()` - -Generate Table of Contents as HTML from a Markdown document body. - -```php -$page->getTableOfContents(): string -``` - #### `getRouteKey()` Get the route key for the page. diff --git a/docs/_data/partials/hyde-pages-api/hyde-kernel-base-methods.md b/docs/_data/partials/hyde-pages-api/hyde-kernel-base-methods.md index 290eea031f7..e8fbb41573b 100644 --- a/docs/_data/partials/hyde-pages-api/hyde-kernel-base-methods.md +++ b/docs/_data/partials/hyde-pages-api/hyde-kernel-base-methods.md @@ -1,7 +1,7 @@
- + #### `version()` @@ -32,7 +32,7 @@ Hyde::features(): Hyde\Facades\Features No description provided. ```php -Hyde::hasFeature(Hyde\Enums\Feature|string $feature): bool +Hyde::hasFeature(Hyde\Enums\Feature $feature): bool ``` #### `toArray()` diff --git a/docs/_data/partials/hyde-pages-api/hyde-kernel-filesystem-methods.md b/docs/_data/partials/hyde-pages-api/hyde-kernel-filesystem-methods.md index bdbe12dd34d..fa76f9881e7 100644 --- a/docs/_data/partials/hyde-pages-api/hyde-kernel-filesystem-methods.md +++ b/docs/_data/partials/hyde-pages-api/hyde-kernel-filesystem-methods.md @@ -1,7 +1,7 @@
- + #### `filesystem()` @@ -27,14 +27,6 @@ No description provided. Hyde::vendorPath(string $path, string $package): string ``` -#### `mediaPath()` - -No description provided. - -```php -Hyde::mediaPath(string $path): string -``` - #### `sitePath()` No description provided. @@ -43,28 +35,28 @@ No description provided. Hyde::sitePath(string $path): string ``` -#### `siteMediaPath()` +#### `pathToAbsolute()` No description provided. ```php -Hyde::siteMediaPath(string $path): string +Hyde::pathToAbsolute(array|string $path): array|string ``` -#### `pathToAbsolute()` +#### `pathToRelative()` No description provided. ```php -Hyde::pathToAbsolute(array|string $path): array|string +Hyde::pathToRelative(string $path): string ``` -#### `pathToRelative()` +#### `assets()` No description provided. ```php -Hyde::pathToRelative(string $path): string +Hyde::assets(): \Illuminate\Support\Collection ``` diff --git a/docs/_data/partials/hyde-pages-api/hyde-kernel-hyperlink-methods.md b/docs/_data/partials/hyde-pages-api/hyde-kernel-hyperlink-methods.md index 1dceb9c542d..d3d7e31ab61 100644 --- a/docs/_data/partials/hyde-pages-api/hyde-kernel-hyperlink-methods.md +++ b/docs/_data/partials/hyde-pages-api/hyde-kernel-hyperlink-methods.md @@ -1,7 +1,7 @@